payload 3.89.0 → 3.90.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 (459) hide show
  1. package/dist/admin/forms/Field.d.ts +2 -0
  2. package/dist/admin/forms/Field.d.ts.map +1 -1
  3. package/dist/admin/forms/Field.js.map +1 -1
  4. package/dist/admin/forms/Form.d.ts +2 -0
  5. package/dist/admin/forms/Form.d.ts.map +1 -1
  6. package/dist/admin/forms/Form.js.map +1 -1
  7. package/dist/admin/functions/index.d.ts +3 -1
  8. package/dist/admin/functions/index.d.ts.map +1 -1
  9. package/dist/admin/functions/index.js.map +1 -1
  10. package/dist/admin/views/dashboard.d.ts +1 -1
  11. package/dist/admin/views/dashboard.d.ts.map +1 -1
  12. package/dist/admin/views/dashboard.js.map +1 -1
  13. package/dist/auth/applyUserReadAccess.d.ts +15 -0
  14. package/dist/auth/applyUserReadAccess.d.ts.map +1 -0
  15. package/dist/auth/applyUserReadAccess.js +41 -0
  16. package/dist/auth/applyUserReadAccess.js.map +1 -0
  17. package/dist/auth/baseFields/apiKey/canCreateOrUpdateAPIKey.d.ts +4 -0
  18. package/dist/auth/baseFields/apiKey/canCreateOrUpdateAPIKey.d.ts.map +1 -0
  19. package/dist/auth/baseFields/apiKey/canCreateOrUpdateAPIKey.js +20 -0
  20. package/dist/auth/baseFields/apiKey/canCreateOrUpdateAPIKey.js.map +1 -0
  21. package/dist/auth/baseFields/apiKey/encryptAPIKey.d.ts +4 -0
  22. package/dist/auth/baseFields/apiKey/encryptAPIKey.d.ts.map +1 -0
  23. package/dist/auth/baseFields/apiKey/encryptAPIKey.js +16 -0
  24. package/dist/auth/baseFields/apiKey/encryptAPIKey.js.map +1 -0
  25. package/dist/auth/baseFields/apiKey/index.d.ts +6 -0
  26. package/dist/auth/baseFields/apiKey/index.d.ts.map +1 -0
  27. package/dist/auth/baseFields/apiKey/index.js +112 -0
  28. package/dist/auth/baseFields/apiKey/index.js.map +1 -0
  29. package/dist/auth/baseFields/apiKey/omitAPIKey.d.ts +4 -0
  30. package/dist/auth/baseFields/apiKey/omitAPIKey.d.ts.map +1 -0
  31. package/dist/auth/baseFields/apiKey/omitAPIKey.js +8 -0
  32. package/dist/auth/baseFields/apiKey/omitAPIKey.js.map +1 -0
  33. package/dist/auth/baseFields/apiKey/omitAPIKeyIndex.d.ts +4 -0
  34. package/dist/auth/baseFields/apiKey/omitAPIKeyIndex.d.ts.map +1 -0
  35. package/dist/auth/baseFields/apiKey/omitAPIKeyIndex.js +5 -0
  36. package/dist/auth/baseFields/apiKey/omitAPIKeyIndex.js.map +1 -0
  37. package/dist/auth/baseFields/apiKey/omitEncryptedAPIKey.d.ts +4 -0
  38. package/dist/auth/baseFields/apiKey/omitEncryptedAPIKey.d.ts.map +1 -0
  39. package/dist/auth/baseFields/apiKey/omitEncryptedAPIKey.js +5 -0
  40. package/dist/auth/baseFields/apiKey/omitEncryptedAPIKey.js.map +1 -0
  41. package/dist/auth/baseFields/apiKey/setAPIKeyIndex.d.ts +4 -0
  42. package/dist/auth/baseFields/apiKey/setAPIKeyIndex.d.ts.map +1 -0
  43. package/dist/auth/baseFields/apiKey/setAPIKeyIndex.js +17 -0
  44. package/dist/auth/baseFields/apiKey/setAPIKeyIndex.js.map +1 -0
  45. package/dist/auth/baseFields/auth.d.ts +1 -0
  46. package/dist/auth/baseFields/auth.d.ts.map +1 -1
  47. package/dist/auth/baseFields/auth.js +9 -0
  48. package/dist/auth/baseFields/auth.js.map +1 -1
  49. package/dist/auth/defaultUnlockAccess.d.ts +3 -0
  50. package/dist/auth/defaultUnlockAccess.d.ts.map +1 -0
  51. package/dist/auth/defaultUnlockAccess.js +8 -0
  52. package/dist/auth/defaultUnlockAccess.js.map +1 -0
  53. package/dist/auth/endpoints/index.d.ts +1 -0
  54. package/dist/auth/endpoints/index.d.ts.map +1 -1
  55. package/dist/auth/endpoints/index.js +8 -0
  56. package/dist/auth/endpoints/index.js.map +1 -1
  57. package/dist/auth/endpoints/revealAPIKey.d.ts +7 -0
  58. package/dist/auth/endpoints/revealAPIKey.d.ts.map +1 -0
  59. package/dist/auth/endpoints/revealAPIKey.js +120 -0
  60. package/dist/auth/endpoints/revealAPIKey.js.map +1 -0
  61. package/dist/auth/executeAccess.d.ts +3 -1
  62. package/dist/auth/executeAccess.d.ts.map +1 -1
  63. package/dist/auth/executeAccess.js +2 -1
  64. package/dist/auth/executeAccess.js.map +1 -1
  65. package/dist/auth/getAuthFields.d.ts +1 -1
  66. package/dist/auth/getAuthFields.d.ts.map +1 -1
  67. package/dist/auth/getAuthFields.js +7 -4
  68. package/dist/auth/getAuthFields.js.map +1 -1
  69. package/dist/auth/getFieldsToSign.d.ts.map +1 -1
  70. package/dist/auth/getFieldsToSign.js +17 -10
  71. package/dist/auth/getFieldsToSign.js.map +1 -1
  72. package/dist/auth/getFieldsToSign.spec.js +114 -0
  73. package/dist/auth/getFieldsToSign.spec.js.map +1 -0
  74. package/dist/auth/jwt.d.ts.map +1 -1
  75. package/dist/auth/jwt.js +2 -0
  76. package/dist/auth/jwt.js.map +1 -1
  77. package/dist/auth/jwt.spec.js +24 -0
  78. package/dist/auth/jwt.spec.js.map +1 -0
  79. package/dist/auth/jwtAuth.d.ts +9 -0
  80. package/dist/auth/jwtAuth.d.ts.map +1 -0
  81. package/dist/auth/jwtAuth.js +8 -0
  82. package/dist/auth/jwtAuth.js.map +1 -0
  83. package/dist/auth/operations/auth.d.ts.map +1 -1
  84. package/dist/auth/operations/auth.js +2 -1
  85. package/dist/auth/operations/auth.js.map +1 -1
  86. package/dist/auth/operations/forgotPassword.d.ts.map +1 -1
  87. package/dist/auth/operations/forgotPassword.js +95 -7
  88. package/dist/auth/operations/forgotPassword.js.map +1 -1
  89. package/dist/auth/operations/local/auth.js +3 -1
  90. package/dist/auth/operations/local/auth.js.map +1 -1
  91. package/dist/auth/operations/login.d.ts.map +1 -1
  92. package/dist/auth/operations/login.js +48 -26
  93. package/dist/auth/operations/login.js.map +1 -1
  94. package/dist/auth/operations/refresh.d.ts.map +1 -1
  95. package/dist/auth/operations/refresh.js +32 -9
  96. package/dist/auth/operations/refresh.js.map +1 -1
  97. package/dist/auth/operations/registerFirstUser.d.ts.map +1 -1
  98. package/dist/auth/operations/registerFirstUser.js +3 -4
  99. package/dist/auth/operations/registerFirstUser.js.map +1 -1
  100. package/dist/auth/operations/resetPassword.d.ts.map +1 -1
  101. package/dist/auth/operations/resetPassword.js +31 -22
  102. package/dist/auth/operations/resetPassword.js.map +1 -1
  103. package/dist/auth/operations/unlock.d.ts.map +1 -1
  104. package/dist/auth/operations/unlock.js +1 -0
  105. package/dist/auth/operations/unlock.js.map +1 -1
  106. package/dist/auth/strategies/apiKey.d.ts.map +1 -1
  107. package/dist/auth/strategies/apiKey.js +15 -1
  108. package/dist/auth/strategies/apiKey.js.map +1 -1
  109. package/dist/auth/strategies/jwt.d.ts.map +1 -1
  110. package/dist/auth/strategies/jwt.js +61 -10
  111. package/dist/auth/strategies/jwt.js.map +1 -1
  112. package/dist/auth/strategies/jwt.spec.js +281 -0
  113. package/dist/auth/strategies/jwt.spec.js.map +1 -0
  114. package/dist/auth/strategies/local/authenticate.d.ts +5 -1
  115. package/dist/auth/strategies/local/authenticate.d.ts.map +1 -1
  116. package/dist/auth/strategies/local/authenticate.js +8 -3
  117. package/dist/auth/strategies/local/authenticate.js.map +1 -1
  118. package/dist/auth/strategies/local/authenticate.spec.js +37 -10
  119. package/dist/auth/strategies/local/authenticate.spec.js.map +1 -1
  120. package/dist/auth/strategies/local/generatePasswordSaltHash.d.ts +9 -1
  121. package/dist/auth/strategies/local/generatePasswordSaltHash.d.ts.map +1 -1
  122. package/dist/auth/strategies/local/generatePasswordSaltHash.js +61 -34
  123. package/dist/auth/strategies/local/generatePasswordSaltHash.js.map +1 -1
  124. package/dist/auth/types.d.ts +16 -1
  125. package/dist/auth/types.d.ts.map +1 -1
  126. package/dist/auth/types.js.map +1 -1
  127. package/dist/collections/config/client.d.ts +1 -0
  128. package/dist/collections/config/client.d.ts.map +1 -1
  129. package/dist/collections/config/client.js +3 -0
  130. package/dist/collections/config/client.js.map +1 -1
  131. package/dist/collections/config/defaults.d.ts.map +1 -1
  132. package/dist/collections/config/defaults.js +4 -2
  133. package/dist/collections/config/defaults.js.map +1 -1
  134. package/dist/collections/config/sanitize.d.ts.map +1 -1
  135. package/dist/collections/config/sanitize.js +17 -6
  136. package/dist/collections/config/sanitize.js.map +1 -1
  137. package/dist/collections/endpoints/index.d.ts +1 -0
  138. package/dist/collections/endpoints/index.d.ts.map +1 -1
  139. package/dist/collections/endpoints/index.js +6 -5
  140. package/dist/collections/endpoints/index.js.map +1 -1
  141. package/dist/collections/operations/create.d.ts.map +1 -1
  142. package/dist/collections/operations/create.js +105 -8
  143. package/dist/collections/operations/create.js.map +1 -1
  144. package/dist/collections/operations/deleteByID.js +13 -13
  145. package/dist/collections/operations/deleteByID.js.map +1 -1
  146. package/dist/collections/operations/findDistinct.d.ts.map +1 -1
  147. package/dist/collections/operations/findDistinct.js +96 -18
  148. package/dist/collections/operations/findDistinct.js.map +1 -1
  149. package/dist/collections/operations/restoreVersion.d.ts.map +1 -1
  150. package/dist/collections/operations/restoreVersion.js +47 -13
  151. package/dist/collections/operations/restoreVersion.js.map +1 -1
  152. package/dist/collections/operations/update.d.ts.map +1 -1
  153. package/dist/collections/operations/update.js +118 -18
  154. package/dist/collections/operations/update.js.map +1 -1
  155. package/dist/collections/operations/updateByID.d.ts.map +1 -1
  156. package/dist/collections/operations/updateByID.js +62 -2
  157. package/dist/collections/operations/updateByID.js.map +1 -1
  158. package/dist/collections/operations/utilities/update.d.ts.map +1 -1
  159. package/dist/collections/operations/utilities/update.js +71 -15
  160. package/dist/collections/operations/utilities/update.js.map +1 -1
  161. package/dist/config/orderable/index.d.ts.map +1 -1
  162. package/dist/config/orderable/index.js +67 -14
  163. package/dist/config/orderable/index.js.map +1 -1
  164. package/dist/config/sanitize.d.ts.map +1 -1
  165. package/dist/config/sanitize.js +1 -1
  166. package/dist/config/sanitize.js.map +1 -1
  167. package/dist/config/types.d.ts +13 -1
  168. package/dist/config/types.d.ts.map +1 -1
  169. package/dist/config/types.js.map +1 -1
  170. package/dist/database/getLocalizedPaths.d.ts +2 -1
  171. package/dist/database/getLocalizedPaths.d.ts.map +1 -1
  172. package/dist/database/getLocalizedPaths.js +12 -3
  173. package/dist/database/getLocalizedPaths.js.map +1 -1
  174. package/dist/database/isNestedRelationshipQuery.d.ts +9 -0
  175. package/dist/database/isNestedRelationshipQuery.d.ts.map +1 -0
  176. package/dist/database/isNestedRelationshipQuery.js +14 -0
  177. package/dist/database/isNestedRelationshipQuery.js.map +1 -0
  178. package/dist/database/prefixWherePaths.d.ts +6 -0
  179. package/dist/database/prefixWherePaths.d.ts.map +1 -0
  180. package/dist/database/prefixWherePaths.js +19 -0
  181. package/dist/database/prefixWherePaths.js.map +1 -0
  182. package/dist/database/prefixWherePaths.spec.js +46 -0
  183. package/dist/database/prefixWherePaths.spec.js.map +1 -0
  184. package/dist/database/queryValidation/validateQueryPaths.d.ts +2 -1
  185. package/dist/database/queryValidation/validateQueryPaths.d.ts.map +1 -1
  186. package/dist/database/queryValidation/validateQueryPaths.js +4 -1
  187. package/dist/database/queryValidation/validateQueryPaths.js.map +1 -1
  188. package/dist/database/queryValidation/validateSearchParams.d.ts +2 -1
  189. package/dist/database/queryValidation/validateSearchParams.d.ts.map +1 -1
  190. package/dist/database/queryValidation/validateSearchParams.js +87 -4
  191. package/dist/database/queryValidation/validateSearchParams.js.map +1 -1
  192. package/dist/database/types.d.ts +5 -0
  193. package/dist/database/types.d.ts.map +1 -1
  194. package/dist/database/types.js.map +1 -1
  195. package/dist/email/normalizeSendEmailOptions.js.map +1 -1
  196. package/dist/email/types.d.ts +4 -1
  197. package/dist/email/types.d.ts.map +1 -1
  198. package/dist/email/types.js.map +1 -1
  199. package/dist/exports/internal.d.ts +7 -0
  200. package/dist/exports/internal.d.ts.map +1 -1
  201. package/dist/exports/internal.js +7 -1
  202. package/dist/exports/internal.js.map +1 -1
  203. package/dist/exports/shared.d.ts +3 -0
  204. package/dist/exports/shared.d.ts.map +1 -1
  205. package/dist/exports/shared.js +3 -0
  206. package/dist/exports/shared.js.map +1 -1
  207. package/dist/fields/config/types.d.ts +7 -5
  208. package/dist/fields/config/types.d.ts.map +1 -1
  209. package/dist/fields/config/types.js.map +1 -1
  210. package/dist/fields/hooks/beforeChange/index.d.ts +7 -1
  211. package/dist/fields/hooks/beforeChange/index.d.ts.map +1 -1
  212. package/dist/fields/hooks/beforeChange/index.js +4 -2
  213. package/dist/fields/hooks/beforeChange/index.js.map +1 -1
  214. package/dist/fields/hooks/beforeChange/index.spec.js +206 -0
  215. package/dist/fields/hooks/beforeChange/index.spec.js.map +1 -0
  216. package/dist/fields/hooks/beforeChange/promise.d.ts +2 -1
  217. package/dist/fields/hooks/beforeChange/promise.d.ts.map +1 -1
  218. package/dist/fields/hooks/beforeChange/promise.js +51 -9
  219. package/dist/fields/hooks/beforeChange/promise.js.map +1 -1
  220. package/dist/fields/hooks/beforeChange/traverseFields.d.ts +2 -1
  221. package/dist/fields/hooks/beforeChange/traverseFields.d.ts.map +1 -1
  222. package/dist/fields/hooks/beforeChange/traverseFields.js +3 -2
  223. package/dist/fields/hooks/beforeChange/traverseFields.js.map +1 -1
  224. package/dist/fields/hooks/beforeDuplicate/promise.d.ts.map +1 -1
  225. package/dist/fields/hooks/beforeDuplicate/promise.js +4 -0
  226. package/dist/fields/hooks/beforeDuplicate/promise.js.map +1 -1
  227. package/dist/fields/hooks/beforeValidate/getFallbackValue.d.ts +2 -1
  228. package/dist/fields/hooks/beforeValidate/getFallbackValue.d.ts.map +1 -1
  229. package/dist/fields/hooks/beforeValidate/getFallbackValue.js +2 -2
  230. package/dist/fields/hooks/beforeValidate/getFallbackValue.js.map +1 -1
  231. package/dist/fields/hooks/beforeValidate/index.d.ts +6 -1
  232. package/dist/fields/hooks/beforeValidate/index.d.ts.map +1 -1
  233. package/dist/fields/hooks/beforeValidate/index.js +3 -1
  234. package/dist/fields/hooks/beforeValidate/index.js.map +1 -1
  235. package/dist/fields/hooks/beforeValidate/index.spec.js +90 -0
  236. package/dist/fields/hooks/beforeValidate/index.spec.js.map +1 -0
  237. package/dist/fields/hooks/beforeValidate/promise.d.ts +6 -1
  238. package/dist/fields/hooks/beforeValidate/promise.d.ts.map +1 -1
  239. package/dist/fields/hooks/beforeValidate/promise.js +23 -8
  240. package/dist/fields/hooks/beforeValidate/promise.js.map +1 -1
  241. package/dist/fields/hooks/beforeValidate/traverseFields.d.ts +6 -1
  242. package/dist/fields/hooks/beforeValidate/traverseFields.d.ts.map +1 -1
  243. package/dist/fields/hooks/beforeValidate/traverseFields.js +3 -1
  244. package/dist/fields/hooks/beforeValidate/traverseFields.js.map +1 -1
  245. package/dist/fields/validations.d.ts.map +1 -1
  246. package/dist/fields/validations.js +3 -1
  247. package/dist/fields/validations.js.map +1 -1
  248. package/dist/globals/operations/restoreVersion.d.ts.map +1 -1
  249. package/dist/globals/operations/restoreVersion.js +45 -11
  250. package/dist/globals/operations/restoreVersion.js.map +1 -1
  251. package/dist/globals/operations/update.d.ts.map +1 -1
  252. package/dist/globals/operations/update.js +95 -16
  253. package/dist/globals/operations/update.js.map +1 -1
  254. package/dist/index.bundled.d.ts +102 -24
  255. package/dist/index.d.ts +3 -1
  256. package/dist/index.d.ts.map +1 -1
  257. package/dist/index.js +2 -2
  258. package/dist/index.js.map +1 -1
  259. package/dist/preferences/config.d.ts.map +1 -1
  260. package/dist/preferences/config.js +2 -1
  261. package/dist/preferences/config.js.map +1 -1
  262. package/dist/query-presets/access.d.ts.map +1 -1
  263. package/dist/query-presets/access.js +2 -1
  264. package/dist/query-presets/access.js.map +1 -1
  265. package/dist/queues/config/types/index.d.ts +2 -1
  266. package/dist/queues/config/types/index.d.ts.map +1 -1
  267. package/dist/queues/config/types/index.js.map +1 -1
  268. package/dist/uploads/assertClientUploadAccess.d.ts +7 -0
  269. package/dist/uploads/assertClientUploadAccess.d.ts.map +1 -0
  270. package/dist/uploads/assertClientUploadAccess.js +27 -0
  271. package/dist/uploads/assertClientUploadAccess.js.map +1 -0
  272. package/dist/uploads/assertClientUploadAllowed.d.ts +11 -0
  273. package/dist/uploads/assertClientUploadAllowed.d.ts.map +1 -0
  274. package/dist/uploads/assertClientUploadAllowed.js +46 -0
  275. package/dist/uploads/assertClientUploadAllowed.js.map +1 -0
  276. package/dist/uploads/assertClientUploadAllowed.spec.js +91 -0
  277. package/dist/uploads/assertClientUploadAllowed.spec.js.map +1 -0
  278. package/dist/uploads/checkFileRestrictions.d.ts +4 -1
  279. package/dist/uploads/checkFileRestrictions.d.ts.map +1 -1
  280. package/dist/uploads/checkFileRestrictions.js +66 -26
  281. package/dist/uploads/checkFileRestrictions.js.map +1 -1
  282. package/dist/uploads/clientUploadReceipt.d.ts +23 -0
  283. package/dist/uploads/clientUploadReceipt.d.ts.map +1 -0
  284. package/dist/uploads/clientUploadReceipt.js +55 -0
  285. package/dist/uploads/clientUploadReceipt.js.map +1 -0
  286. package/dist/uploads/deleteAssociatedFiles.d.ts.map +1 -1
  287. package/dist/uploads/deleteAssociatedFiles.js +33 -8
  288. package/dist/uploads/deleteAssociatedFiles.js.map +1 -1
  289. package/dist/uploads/deleteAssociatedFiles.spec.js +124 -0
  290. package/dist/uploads/deleteAssociatedFiles.spec.js.map +1 -0
  291. package/dist/uploads/detectSvgFromXml.d.ts +1 -3
  292. package/dist/uploads/detectSvgFromXml.d.ts.map +1 -1
  293. package/dist/uploads/detectSvgFromXml.js +3 -40
  294. package/dist/uploads/detectSvgFromXml.js.map +1 -1
  295. package/dist/uploads/endpoints/getFile.d.ts.map +1 -1
  296. package/dist/uploads/endpoints/getFile.js +5 -3
  297. package/dist/uploads/endpoints/getFile.js.map +1 -1
  298. package/dist/uploads/fetchAPI-multipart/handlers.d.ts +2 -2
  299. package/dist/uploads/fetchAPI-multipart/handlers.d.ts.map +1 -1
  300. package/dist/uploads/fetchAPI-multipart/handlers.js +18 -5
  301. package/dist/uploads/fetchAPI-multipart/handlers.js.map +1 -1
  302. package/dist/uploads/fetchAPI-multipart/index.d.ts.map +1 -1
  303. package/dist/uploads/fetchAPI-multipart/index.js +24 -2
  304. package/dist/uploads/fetchAPI-multipart/index.js.map +1 -1
  305. package/dist/uploads/fetchAPI-multipart/processMultipart.d.ts +0 -6
  306. package/dist/uploads/fetchAPI-multipart/processMultipart.d.ts.map +1 -1
  307. package/dist/uploads/fetchAPI-multipart/processMultipart.js +146 -126
  308. package/dist/uploads/fetchAPI-multipart/processMultipart.js.map +1 -1
  309. package/dist/uploads/fetchAPI-multipart/processMultipart.spec.js +663 -0
  310. package/dist/uploads/fetchAPI-multipart/processMultipart.spec.js.map +1 -0
  311. package/dist/uploads/generateFileData.d.ts +3 -1
  312. package/dist/uploads/generateFileData.d.ts.map +1 -1
  313. package/dist/uploads/generateFileData.js +29 -16
  314. package/dist/uploads/generateFileData.js.map +1 -1
  315. package/dist/uploads/getBaseFields.d.ts.map +1 -1
  316. package/dist/uploads/getBaseFields.js +3 -1
  317. package/dist/uploads/getBaseFields.js.map +1 -1
  318. package/dist/uploads/getExternalFile.d.ts +1 -1
  319. package/dist/uploads/getExternalFile.d.ts.map +1 -1
  320. package/dist/uploads/getExternalFile.js +60 -15
  321. package/dist/uploads/getExternalFile.js.map +1 -1
  322. package/dist/uploads/getFileTypeFallback.d.ts.map +1 -1
  323. package/dist/uploads/getFileTypeFallback.js +3 -1
  324. package/dist/uploads/getFileTypeFallback.js.map +1 -1
  325. package/dist/uploads/getFileTypeIdentity.d.ts +19 -0
  326. package/dist/uploads/getFileTypeIdentity.d.ts.map +1 -0
  327. package/dist/uploads/getFileTypeIdentity.js +34 -0
  328. package/dist/uploads/getFileTypeIdentity.js.map +1 -0
  329. package/dist/uploads/getFileTypeIdentity.spec.js +43 -0
  330. package/dist/uploads/getFileTypeIdentity.spec.js.map +1 -0
  331. package/dist/uploads/isProcessableImage.d.ts +2 -0
  332. package/dist/uploads/isProcessableImage.d.ts.map +1 -0
  333. package/dist/uploads/isProcessableImage.js +7 -0
  334. package/dist/uploads/isProcessableImage.js.map +1 -0
  335. package/dist/uploads/safeFetch.d.ts.map +1 -1
  336. package/dist/uploads/safeFetch.js +3 -2
  337. package/dist/uploads/safeFetch.js.map +1 -1
  338. package/dist/uploads/sanitizeUploadData.d.ts +26 -0
  339. package/dist/uploads/sanitizeUploadData.d.ts.map +1 -0
  340. package/dist/uploads/sanitizeUploadData.js +159 -0
  341. package/dist/uploads/sanitizeUploadData.js.map +1 -0
  342. package/dist/uploads/sanitizeUploadData.spec.js +255 -0
  343. package/dist/uploads/sanitizeUploadData.spec.js.map +1 -0
  344. package/dist/uploads/types.d.ts +11 -3
  345. package/dist/uploads/types.d.ts.map +1 -1
  346. package/dist/uploads/types.js.map +1 -1
  347. package/dist/uploads/uploadContentSecurityPolicy.d.ts +2 -0
  348. package/dist/uploads/uploadContentSecurityPolicy.d.ts.map +1 -0
  349. package/dist/uploads/uploadContentSecurityPolicy.js +3 -0
  350. package/dist/uploads/uploadContentSecurityPolicy.js.map +1 -0
  351. package/dist/uploads/validateISOBaseMediaFile.d.ts +4 -0
  352. package/dist/uploads/validateISOBaseMediaFile.d.ts.map +1 -0
  353. package/dist/uploads/validateISOBaseMediaFile.js +91 -0
  354. package/dist/uploads/validateISOBaseMediaFile.js.map +1 -0
  355. package/dist/uploads/validateISOBaseMediaFile.spec.js +130 -0
  356. package/dist/uploads/validateISOBaseMediaFile.spec.js.map +1 -0
  357. package/dist/uploads/validateSvg.d.ts +10 -4
  358. package/dist/uploads/validateSvg.d.ts.map +1 -1
  359. package/dist/uploads/validateSvg.js +280 -40
  360. package/dist/uploads/validateSvg.js.map +1 -1
  361. package/dist/uploads/validateSvg.spec.js +123 -0
  362. package/dist/uploads/validateSvg.spec.js.map +1 -0
  363. package/dist/uploads/validateUploadFilename.d.ts +3 -0
  364. package/dist/uploads/validateUploadFilename.d.ts.map +1 -0
  365. package/dist/uploads/validateUploadFilename.js +13 -0
  366. package/dist/uploads/validateUploadFilename.js.map +1 -0
  367. package/dist/uploads/validateUploadFilename.spec.js +24 -0
  368. package/dist/uploads/validateUploadFilename.spec.js.map +1 -0
  369. package/dist/utilities/addDataAndFileToRequest.d.ts.map +1 -1
  370. package/dist/utilities/addDataAndFileToRequest.js +28 -1
  371. package/dist/utilities/addDataAndFileToRequest.js.map +1 -1
  372. package/dist/utilities/addDataAndFileToRequest.spec.js +158 -0
  373. package/dist/utilities/addDataAndFileToRequest.spec.js.map +1 -1
  374. package/dist/utilities/createPayloadRequest.d.ts.map +1 -1
  375. package/dist/utilities/createPayloadRequest.js +2 -1
  376. package/dist/utilities/createPayloadRequest.js.map +1 -1
  377. package/dist/utilities/deepCopyObject.d.ts.map +1 -1
  378. package/dist/utilities/deepCopyObject.js +110 -19
  379. package/dist/utilities/deepCopyObject.js.map +1 -1
  380. package/dist/utilities/deepCopyObject.spec.js +216 -0
  381. package/dist/utilities/deepCopyObject.spec.js.map +1 -0
  382. package/dist/utilities/fieldPath.d.ts +13 -0
  383. package/dist/utilities/fieldPath.d.ts.map +1 -0
  384. package/dist/utilities/fieldPath.js +51 -0
  385. package/dist/utilities/fieldPath.js.map +1 -0
  386. package/dist/utilities/fieldPath.spec.js +155 -0
  387. package/dist/utilities/fieldPath.spec.js.map +1 -0
  388. package/dist/utilities/getEntityPermissions/getEntityPermissions.d.ts.map +1 -1
  389. package/dist/utilities/getEntityPermissions/getEntityPermissions.js +2 -0
  390. package/dist/utilities/getEntityPermissions/getEntityPermissions.js.map +1 -1
  391. package/dist/utilities/getObjectDotNotation.d.ts.map +1 -1
  392. package/dist/utilities/getObjectDotNotation.js +7 -1
  393. package/dist/utilities/getObjectDotNotation.js.map +1 -1
  394. package/dist/utilities/getObjectDotNotation.spec.js +33 -0
  395. package/dist/utilities/getObjectDotNotation.spec.js.map +1 -0
  396. package/dist/utilities/getSafeRedirect.spec.js +14 -0
  397. package/dist/utilities/getSafeRedirect.spec.js.map +1 -1
  398. package/dist/utilities/getTopLevelFieldNames.d.ts +2 -0
  399. package/dist/utilities/getTopLevelFieldNames.d.ts.map +1 -0
  400. package/dist/utilities/getTopLevelFieldNames.js +3 -0
  401. package/dist/utilities/getTopLevelFieldNames.js.map +1 -0
  402. package/dist/utilities/getTopLevelFieldNames.spec.js +18 -0
  403. package/dist/utilities/getTopLevelFieldNames.spec.js.map +1 -0
  404. package/dist/utilities/handleEndpoints.js +1 -1
  405. package/dist/utilities/handleEndpoints.js.map +1 -1
  406. package/dist/utilities/parseParams/index.d.ts.map +1 -1
  407. package/dist/utilities/parseParams/index.js +3 -1
  408. package/dist/utilities/parseParams/index.js.map +1 -1
  409. package/dist/utilities/parseParams/index.spec.js +8 -0
  410. package/dist/utilities/parseParams/index.spec.js.map +1 -1
  411. package/dist/utilities/telemetry/featureInfo/getFeatureInfo.d.ts +4 -0
  412. package/dist/utilities/telemetry/featureInfo/getFeatureInfo.d.ts.map +1 -0
  413. package/dist/utilities/telemetry/featureInfo/getFeatureInfo.js +248 -0
  414. package/dist/utilities/telemetry/featureInfo/getFeatureInfo.js.map +1 -0
  415. package/dist/utilities/telemetry/featureInfo/types.d.ts +62 -0
  416. package/dist/utilities/telemetry/featureInfo/types.d.ts.map +1 -0
  417. package/dist/utilities/telemetry/featureInfo/types.js +3 -0
  418. package/dist/utilities/telemetry/featureInfo/types.js.map +1 -0
  419. package/dist/utilities/telemetry/getProjectContext.d.ts +14 -0
  420. package/dist/utilities/telemetry/getProjectContext.d.ts.map +1 -0
  421. package/dist/utilities/telemetry/getProjectContext.js +36 -0
  422. package/dist/utilities/telemetry/getProjectContext.js.map +1 -0
  423. package/dist/utilities/telemetry/index.d.ts +7 -1
  424. package/dist/utilities/telemetry/index.d.ts.map +1 -1
  425. package/dist/utilities/telemetry/index.js +22 -0
  426. package/dist/utilities/telemetry/index.js.map +1 -1
  427. package/dist/utilities/traverseFields.d.ts.map +1 -1
  428. package/dist/utilities/traverseFields.js +5 -14
  429. package/dist/utilities/traverseFields.js.map +1 -1
  430. package/dist/utilities/unflatten.d.ts.map +1 -1
  431. package/dist/utilities/unflatten.js +21 -9
  432. package/dist/utilities/unflatten.js.map +1 -1
  433. package/dist/utilities/unflatten.spec.js +38 -0
  434. package/dist/utilities/unflatten.spec.js.map +1 -0
  435. package/dist/versions/allLocalesPublicationStatus.d.ts +38 -0
  436. package/dist/versions/allLocalesPublicationStatus.d.ts.map +1 -0
  437. package/dist/versions/allLocalesPublicationStatus.js +57 -0
  438. package/dist/versions/allLocalesPublicationStatus.js.map +1 -0
  439. package/dist/versions/getLatestGlobalVersion.d.ts.map +1 -1
  440. package/dist/versions/getLatestGlobalVersion.js +10 -2
  441. package/dist/versions/getLatestGlobalVersion.js.map +1 -1
  442. package/dist/versions/getRestoredStatusesToAuthorize.d.ts +9 -0
  443. package/dist/versions/getRestoredStatusesToAuthorize.d.ts.map +1 -0
  444. package/dist/versions/getRestoredStatusesToAuthorize.js +22 -0
  445. package/dist/versions/getRestoredStatusesToAuthorize.js.map +1 -0
  446. package/dist/versions/getRestoredStatusesToAuthorize.spec.js +50 -0
  447. package/dist/versions/getRestoredStatusesToAuthorize.spec.js.map +1 -0
  448. package/dist/versions/schedule/job.d.ts +2 -2
  449. package/dist/versions/schedule/job.d.ts.map +1 -1
  450. package/dist/versions/schedule/job.js +11 -7
  451. package/dist/versions/schedule/job.js.map +1 -1
  452. package/dist/versions/schedule/types.d.ts +5 -1
  453. package/dist/versions/schedule/types.d.ts.map +1 -1
  454. package/dist/versions/schedule/types.js.map +1 -1
  455. package/package.json +4 -2
  456. package/dist/auth/baseFields/apiKey.d.ts +0 -3
  457. package/dist/auth/baseFields/apiKey.d.ts.map +0 -1
  458. package/dist/auth/baseFields/apiKey.js +0 -59
  459. package/dist/auth/baseFields/apiKey.js.map +0 -1
@@ -0,0 +1,123 @@
1
+ import { randomUUID } from 'crypto';
2
+ import fs from 'fs/promises';
3
+ import os from 'os';
4
+ import path from 'path';
5
+ import { afterEach, describe, expect, it } from 'vitest';
6
+ import { inspectSvg, inspectSvgFile, validateSvg } from './validateSvg.js';
7
+ const tempFiles = [];
8
+ const writeTempFile = async (content)=>{
9
+ const filePath = path.join(os.tmpdir(), `payload-svg-${randomUUID()}`);
10
+ tempFiles.push(filePath);
11
+ await fs.writeFile(filePath, content);
12
+ return filePath;
13
+ };
14
+ afterEach(async ()=>{
15
+ await Promise.all(tempFiles.splice(0).map((filePath)=>fs.unlink(filePath)));
16
+ });
17
+ describe('SVG inspection', ()=>{
18
+ it.each([
19
+ [
20
+ 'script elements',
21
+ '<script>reference()</script>'
22
+ ],
23
+ [
24
+ 'event attributes',
25
+ '<g onload="reference()"/>'
26
+ ],
27
+ [
28
+ 'embedded HTML',
29
+ '<foreignObject/>'
30
+ ],
31
+ [
32
+ 'active links',
33
+ '<a href="javascript:reference()"/>'
34
+ ],
35
+ [
36
+ 'nested SVG data',
37
+ '<image href="data:image/svg+xml,<svg/>"/>'
38
+ ],
39
+ [
40
+ 'active style attributes',
41
+ '<g style="background:url(javascript:reference())"/>'
42
+ ],
43
+ [
44
+ 'active style elements',
45
+ '<style>@import url("reference.css")</style>'
46
+ ],
47
+ [
48
+ 'animated active links',
49
+ '<animate attributeName="href" values="https://example.com; javascript:reference()"/>'
50
+ ],
51
+ [
52
+ 'assigned active links',
53
+ '<set attributeName="href" to="javascript:reference()"/>'
54
+ ]
55
+ ])('should reject %s', (_, content)=>{
56
+ expect(validateSvg(Buffer.from(`<svg xmlns="http://www.w3.org/2000/svg">${content}</svg>`))).toBe(false);
57
+ });
58
+ it('should reject XML-declared SVG event attributes', ()=>{
59
+ expect(validateSvg(Buffer.from('<?xml version="1.0"?><svg xmlns="http://www.w3.org/2000/svg" onload="reference()"/>'))).toBe(false);
60
+ });
61
+ it('should inspect complete style content across text and CDATA', ()=>{
62
+ expect(validateSvg(Buffer.from('<svg xmlns="http://www.w3.org/2000/svg"><style>@im<![CDATA[port]]> url("reference.css")</style></svg>'))).toBe(false);
63
+ });
64
+ it('should inspect UTF-16 XML-declared SVG content', ()=>{
65
+ const content = Buffer.concat([
66
+ Buffer.from([
67
+ 0xff,
68
+ 0xfe
69
+ ]),
70
+ Buffer.from('<?xml version="1.0" encoding="UTF-16"?><svg xmlns="http://www.w3.org/2000/svg" onload="reference()"/>', 'utf16le')
71
+ ]);
72
+ expect(inspectSvg(content)).toMatchObject({
73
+ isSafe: false,
74
+ isSvg: true,
75
+ isValid: true
76
+ });
77
+ });
78
+ it('should accept ordinary SVG content and external resources', ()=>{
79
+ expect(validateSvg(Buffer.from('<svg xmlns="http://www.w3.org/2000/svg"><text>javascript: reference</text><g aria-label="url(javascript: reference)"/><image href="https://example.com/reference.png"/><animate attributeName="fill" values="red;blue"/></svg>'))).toBe(true);
80
+ });
81
+ it('should accept large ordinary style content', ()=>{
82
+ expect(validateSvg(Buffer.from(`<svg xmlns="http://www.w3.org/2000/svg"><style>${'.reference { fill: blue; }'.repeat(50_000)}</style></svg>`))).toBe(true);
83
+ });
84
+ it('should stop buffer inspection after a valid non-SVG root is identified', ()=>{
85
+ expect(inspectSvg(Buffer.from('<feed xmlns="urn:example"><entry>'))).toMatchObject({
86
+ isSafe: false,
87
+ isSvg: false,
88
+ isValid: true
89
+ });
90
+ });
91
+ it('should stop streaming after a valid non-SVG root is identified', async ()=>{
92
+ const filePath = await writeTempFile('<feed xmlns="urn:example"><entry>');
93
+ await expect(inspectSvgFile(filePath, {
94
+ highWaterMark: 64
95
+ })).resolves.toMatchObject({
96
+ isSafe: false,
97
+ isSvg: false,
98
+ isValid: true
99
+ });
100
+ });
101
+ it('should inspect style content across temp-file chunks', async ()=>{
102
+ const filePath = await writeTempFile('<svg xmlns="http://www.w3.org/2000/svg"><style>@import url("reference.css")</style></svg>');
103
+ await expect(inspectSvgFile(filePath, {
104
+ highWaterMark: 3
105
+ })).resolves.toMatchObject({
106
+ isSafe: false,
107
+ isSvg: true,
108
+ isValid: true
109
+ });
110
+ });
111
+ it('should handle deeply nested namespace declarations', ()=>{
112
+ const depth = 10_000;
113
+ const elements = Array.from({
114
+ length: depth
115
+ }, (_, index)=>`<g xmlns:reference${index}="urn:reference:${index}">`).join('');
116
+ const source = Buffer.from(`<svg xmlns="http://www.w3.org/2000/svg">${elements}${'</g>'.repeat(depth)}</svg>`);
117
+ const startedAt = performance.now();
118
+ expect(validateSvg(source)).toBe(true);
119
+ expect(performance.now() - startedAt).toBeLessThan(5_000);
120
+ });
121
+ });
122
+
123
+ //# sourceMappingURL=validateSvg.spec.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/uploads/validateSvg.spec.ts"],"sourcesContent":["import { randomUUID } from 'crypto'\nimport fs from 'fs/promises'\nimport os from 'os'\nimport path from 'path'\nimport { afterEach, describe, expect, it } from 'vitest'\n\nimport { inspectSvg, inspectSvgFile, validateSvg } from './validateSvg.js'\n\nconst tempFiles: string[] = []\n\nconst writeTempFile = async (content: Buffer | string): Promise<string> => {\n const filePath = path.join(os.tmpdir(), `payload-svg-${randomUUID()}`)\n tempFiles.push(filePath)\n await fs.writeFile(filePath, content)\n return filePath\n}\n\nafterEach(async () => {\n await Promise.all(tempFiles.splice(0).map((filePath) => fs.unlink(filePath)))\n})\n\ndescribe('SVG inspection', () => {\n it.each([\n ['script elements', '<script>reference()</script>'],\n ['event attributes', '<g onload=\"reference()\"/>'],\n ['embedded HTML', '<foreignObject/>'],\n ['active links', '<a href=\"javascript:reference()\"/>'],\n ['nested SVG data', '<image href=\"data:image/svg+xml,<svg/>\"/>'],\n ['active style attributes', '<g style=\"background:url(javascript:reference())\"/>'],\n ['active style elements', '<style>@import url(\"reference.css\")</style>'],\n [\n 'animated active links',\n '<animate attributeName=\"href\" values=\"https://example.com; javascript:reference()\"/>',\n ],\n ['assigned active links', '<set attributeName=\"href\" to=\"javascript:reference()\"/>'],\n ])('should reject %s', (_, content) => {\n expect(\n validateSvg(Buffer.from(`<svg xmlns=\"http://www.w3.org/2000/svg\">${content}</svg>`)),\n ).toBe(false)\n })\n\n it('should reject XML-declared SVG event attributes', () => {\n expect(\n validateSvg(\n Buffer.from(\n '<?xml version=\"1.0\"?><svg xmlns=\"http://www.w3.org/2000/svg\" onload=\"reference()\"/>',\n ),\n ),\n ).toBe(false)\n })\n\n it('should inspect complete style content across text and CDATA', () => {\n expect(\n validateSvg(\n Buffer.from(\n '<svg xmlns=\"http://www.w3.org/2000/svg\"><style>@im<![CDATA[port]]> url(\"reference.css\")</style></svg>',\n ),\n ),\n ).toBe(false)\n })\n\n it('should inspect UTF-16 XML-declared SVG content', () => {\n const content = Buffer.concat([\n Buffer.from([0xff, 0xfe]),\n Buffer.from(\n '<?xml version=\"1.0\" encoding=\"UTF-16\"?><svg xmlns=\"http://www.w3.org/2000/svg\" onload=\"reference()\"/>',\n 'utf16le',\n ),\n ])\n\n expect(inspectSvg(content)).toMatchObject({ isSafe: false, isSvg: true, isValid: true })\n })\n\n it('should accept ordinary SVG content and external resources', () => {\n expect(\n validateSvg(\n Buffer.from(\n '<svg xmlns=\"http://www.w3.org/2000/svg\"><text>javascript: reference</text><g aria-label=\"url(javascript: reference)\"/><image href=\"https://example.com/reference.png\"/><animate attributeName=\"fill\" values=\"red;blue\"/></svg>',\n ),\n ),\n ).toBe(true)\n })\n\n it('should accept large ordinary style content', () => {\n expect(\n validateSvg(\n Buffer.from(\n `<svg xmlns=\"http://www.w3.org/2000/svg\"><style>${'.reference { fill: blue; }'.repeat(50_000)}</style></svg>`,\n ),\n ),\n ).toBe(true)\n })\n\n it('should stop buffer inspection after a valid non-SVG root is identified', () => {\n expect(inspectSvg(Buffer.from('<feed xmlns=\"urn:example\"><entry>'))).toMatchObject({\n isSafe: false,\n isSvg: false,\n isValid: true,\n })\n })\n\n it('should stop streaming after a valid non-SVG root is identified', async () => {\n const filePath = await writeTempFile('<feed xmlns=\"urn:example\"><entry>')\n\n await expect(inspectSvgFile(filePath, { highWaterMark: 64 })).resolves.toMatchObject({\n isSafe: false,\n isSvg: false,\n isValid: true,\n })\n })\n\n it('should inspect style content across temp-file chunks', async () => {\n const filePath = await writeTempFile(\n '<svg xmlns=\"http://www.w3.org/2000/svg\"><style>@import url(\"reference.css\")</style></svg>',\n )\n\n await expect(inspectSvgFile(filePath, { highWaterMark: 3 })).resolves.toMatchObject({\n isSafe: false,\n isSvg: true,\n isValid: true,\n })\n })\n\n it('should handle deeply nested namespace declarations', () => {\n const depth = 10_000\n const elements = Array.from(\n { length: depth },\n (_, index) => `<g xmlns:reference${index}=\"urn:reference:${index}\">`,\n ).join('')\n const source = Buffer.from(\n `<svg xmlns=\"http://www.w3.org/2000/svg\">${elements}${'</g>'.repeat(depth)}</svg>`,\n )\n const startedAt = performance.now()\n\n expect(validateSvg(source)).toBe(true)\n expect(performance.now() - startedAt).toBeLessThan(5_000)\n })\n})\n"],"names":["randomUUID","fs","os","path","afterEach","describe","expect","it","inspectSvg","inspectSvgFile","validateSvg","tempFiles","writeTempFile","content","filePath","join","tmpdir","push","writeFile","Promise","all","splice","map","unlink","each","_","Buffer","from","toBe","concat","toMatchObject","isSafe","isSvg","isValid","repeat","highWaterMark","resolves","depth","elements","Array","length","index","source","startedAt","performance","now","toBeLessThan"],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import type { Validate } from '../fields/config/types.js';
2
+ export declare const validateUploadFilename: Validate;
3
+ //# sourceMappingURL=validateUploadFilename.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validateUploadFilename.d.ts","sourceRoot":"","sources":["../../src/uploads/validateUploadFilename.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,2BAA2B,CAAA;AAEzD,eAAO,MAAM,sBAAsB,EAAE,QAgBpC,CAAA"}
@@ -0,0 +1,13 @@
1
+ import path from 'path';
2
+ export const validateUploadFilename = (value)=>{
3
+ if (!value) {
4
+ return true;
5
+ }
6
+ const normalizedFilename = value.replaceAll('\\', '/');
7
+ if (path.posix.isAbsolute(normalizedFilename) || path.win32.isAbsolute(value) || normalizedFilename.split('/').includes('..')) {
8
+ return 'Invalid filename';
9
+ }
10
+ return true;
11
+ };
12
+
13
+ //# sourceMappingURL=validateUploadFilename.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/uploads/validateUploadFilename.ts"],"sourcesContent":["import path from 'path'\n\nimport type { Validate } from '../fields/config/types.js'\n\nexport const validateUploadFilename: Validate = (value: null | string | undefined) => {\n if (!value) {\n return true\n }\n\n const normalizedFilename = value.replaceAll('\\\\', '/')\n\n if (\n path.posix.isAbsolute(normalizedFilename) ||\n path.win32.isAbsolute(value) ||\n normalizedFilename.split('/').includes('..')\n ) {\n return 'Invalid filename'\n }\n\n return true\n}\n"],"names":["path","validateUploadFilename","value","normalizedFilename","replaceAll","posix","isAbsolute","win32","split","includes"],"mappings":"AAAA,OAAOA,UAAU,OAAM;AAIvB,OAAO,MAAMC,yBAAmC,CAACC;IAC/C,IAAI,CAACA,OAAO;QACV,OAAO;IACT;IAEA,MAAMC,qBAAqBD,MAAME,UAAU,CAAC,MAAM;IAElD,IACEJ,KAAKK,KAAK,CAACC,UAAU,CAACH,uBACtBH,KAAKO,KAAK,CAACD,UAAU,CAACJ,UACtBC,mBAAmBK,KAAK,CAAC,KAAKC,QAAQ,CAAC,OACvC;QACA,OAAO;IACT;IAEA,OAAO;AACT,EAAC"}
@@ -0,0 +1,24 @@
1
+ import { describe, expect, it } from 'vitest';
2
+ import { validateUploadFilename } from './validateUploadFilename.js';
3
+ describe('validateUploadFilename', ()=>{
4
+ it.each([
5
+ '../document.pdf',
6
+ 'archive/../document.pdf',
7
+ '..\\document.pdf',
8
+ 'archive\\..\\document.pdf',
9
+ '/archive/document.pdf',
10
+ 'C:\\archive\\document.pdf'
11
+ ])('rejects non-contained filename %s', (filename)=>{
12
+ expect(validateUploadFilename(filename, {})).toBe('Invalid filename');
13
+ });
14
+ it.each([
15
+ 'document.pdf',
16
+ 'tenant/document.pdf',
17
+ 'tenant\\document.pdf',
18
+ 'summary..pdf'
19
+ ])('accepts contained filename %s', (filename)=>{
20
+ expect(validateUploadFilename(filename, {})).toBe(true);
21
+ });
22
+ });
23
+
24
+ //# sourceMappingURL=validateUploadFilename.spec.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/uploads/validateUploadFilename.spec.ts"],"sourcesContent":["import { describe, expect, it } from 'vitest'\n\nimport { validateUploadFilename } from './validateUploadFilename.js'\n\ndescribe('validateUploadFilename', () => {\n it.each([\n '../document.pdf',\n 'archive/../document.pdf',\n '..\\\\document.pdf',\n 'archive\\\\..\\\\document.pdf',\n '/archive/document.pdf',\n 'C:\\\\archive\\\\document.pdf',\n ])('rejects non-contained filename %s', (filename) => {\n expect(validateUploadFilename(filename, {} as never)).toBe('Invalid filename')\n })\n\n it.each(['document.pdf', 'tenant/document.pdf', 'tenant\\\\document.pdf', 'summary..pdf'])(\n 'accepts contained filename %s',\n (filename) => {\n expect(validateUploadFilename(filename, {} as never)).toBe(true)\n },\n )\n})\n"],"names":["describe","expect","it","validateUploadFilename","each","filename","toBe"],"mappings":"AAAA,SAASA,QAAQ,EAAEC,MAAM,EAAEC,EAAE,QAAQ,SAAQ;AAE7C,SAASC,sBAAsB,QAAQ,8BAA6B;AAEpEH,SAAS,0BAA0B;IACjCE,GAAGE,IAAI,CAAC;QACN;QACA;QACA;QACA;QACA;QACA;KACD,EAAE,qCAAqC,CAACC;QACvCJ,OAAOE,uBAAuBE,UAAU,CAAC,IAAaC,IAAI,CAAC;IAC7D;IAEAJ,GAAGE,IAAI,CAAC;QAAC;QAAgB;QAAuB;QAAwB;KAAe,EACrF,iCACA,CAACC;QACCJ,OAAOE,uBAAuBE,UAAU,CAAC,IAAaC,IAAI,CAAC;IAC7D;AAEJ"}
@@ -1 +1 @@
1
- {"version":3,"file":"addDataAndFileToRequest.d.ts","sourceRoot":"","sources":["../../src/utilities/addDataAndFileToRequest.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAA;AAOvD,KAAK,uBAAuB,GAAG,CAAC,GAAG,EAAE,cAAc,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;AAErE;;GAEG;AACH,eAAO,MAAM,uBAAuB,EAAE,uBAiErC,CAAA"}
1
+ {"version":3,"file":"addDataAndFileToRequest.d.ts","sourceRoot":"","sources":["../../src/utilities/addDataAndFileToRequest.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAA;AAQvD,KAAK,uBAAuB,GAAG,CAAC,GAAG,EAAE,cAAc,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;AAErE;;GAEG;AACH,eAAO,MAAM,uBAAuB,EAAE,uBAsGrC,CAAA"}
@@ -1,4 +1,5 @@
1
1
  import { APIError } from '../errors/APIError.js';
2
+ import { verifyClientUploadReceipt } from '../uploads/clientUploadReceipt.js';
2
3
  import { processMultipartFormdata } from '../uploads/fetchAPI-multipart/index.js';
3
4
  import { getFileFromClientUpload } from '../uploads/getFileFromClientUpload.js';
4
5
  /**
@@ -57,8 +58,34 @@ import { getFileFromClientUpload } from '../uploads/getFileFromClientUpload.js';
57
58
  } catch {
58
59
  throw new APIError('A file name is required.', 400);
59
60
  }
61
+ // The collection must come from the route, never from the request body: the body
62
+ // is client-controlled and would select another collection's upload handlers.
63
+ const collectionSlug = typeof req.routeParams?.collection === 'string' ? req.routeParams.collection : undefined;
64
+ const uploadConfig = collectionSlug ? req.payload.collections[collectionSlug]?.config.upload : undefined;
65
+ if (!collectionSlug || !uploadConfig) {
66
+ throw new APIError('Invalid upload collection.', 400);
67
+ }
68
+ if (uploadConfig.requiresClientUploadReceipt) {
69
+ const clientUploadContext = clientUploadFile.clientUploadContext;
70
+ if (!clientUploadContext || typeof clientUploadContext !== 'object' || typeof clientUploadContext.signedReceipt !== 'string') {
71
+ throw new APIError('A verified client upload reference is required.', 400);
72
+ }
73
+ const receipt = verifyClientUploadReceipt({
74
+ collectionSlug,
75
+ req,
76
+ signedReceipt: clientUploadContext.signedReceipt
77
+ });
78
+ if (receipt.filename !== clientUploadFile.filename) {
79
+ throw new APIError('Client upload reference does not match this request.', 400);
80
+ }
81
+ clientUploadFile.clientUploadContext = receipt.context;
82
+ }
83
+ // Pass the route-derived collection to the upload helper, never the body value.
60
84
  req.file = await getFileFromClientUpload({
61
- file: clientUploadFile,
85
+ file: {
86
+ ...clientUploadFile,
87
+ collectionSlug
88
+ },
62
89
  req
63
90
  });
64
91
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/utilities/addDataAndFileToRequest.ts"],"sourcesContent":["import type { PayloadRequest } from '../types/index.js'\nimport type { ClientUploadData } from '../uploads/getFileFromClientUpload.js'\n\nimport { APIError } from '../errors/APIError.js'\nimport { processMultipartFormdata } from '../uploads/fetchAPI-multipart/index.js'\nimport { getFileFromClientUpload } from '../uploads/getFileFromClientUpload.js'\n\ntype AddDataAndFileToRequest = (req: PayloadRequest) => Promise<void>\n\n/**\n * Mutates the Request, appending 'data' and 'file' if found\n */\nexport const addDataAndFileToRequest: AddDataAndFileToRequest = async (req) => {\n const { body, headers, method, payload } = req\n\n if (method && ['PATCH', 'POST', 'PUT'].includes(method.toUpperCase()) && body) {\n const [contentType] = (headers.get('Content-Type') || '').split(';', 1)\n const bodyByteSize = parseInt(req.headers.get('Content-Length') || '0', 10)\n const hasBodyStream = req.body !== null\n\n if (contentType === 'application/json') {\n try {\n const text = await req.text?.()\n const data = text ? JSON.parse(text) : {}\n req.data = data\n // @ts-expect-error attach json method to request\n req.json = () => Promise.resolve(data)\n } catch (error) {\n if (error instanceof SyntaxError) {\n throw new APIError('Invalid JSON', 400)\n }\n req.payload.logger.error(error)\n throw error\n }\n } else if ((bodyByteSize || hasBodyStream) && contentType?.includes('multipart/')) {\n const { error, fields, files } = await processMultipartFormdata({\n options: {\n ...(payload.config.bodyParser || {}),\n ...(payload.config.upload || {}),\n },\n request: req as Request,\n })\n\n if (error) {\n throw new APIError(error.message)\n }\n\n // Set all files on req.files for access by hooks\n if (files) {\n req.files = files\n // Backwards compatibility: set req.file for standard upload collections\n // Guard: if multiple files share the field name \"file\", files.file is an array — skip\n if (files.file && !Array.isArray(files.file)) {\n req.file = files.file\n }\n }\n\n if (fields?._payload && typeof fields._payload === 'string') {\n req.data = JSON.parse(fields._payload)\n }\n\n if (!req.file && fields?.file && typeof fields?.file === 'string') {\n let clientUploadFile: ClientUploadData\n\n try {\n clientUploadFile = JSON.parse(fields.file) as ClientUploadData\n } catch {\n throw new APIError('A file name is required.', 400)\n }\n\n req.file = await getFileFromClientUpload({\n file: clientUploadFile,\n req,\n })\n }\n }\n }\n}\n"],"names":["APIError","processMultipartFormdata","getFileFromClientUpload","addDataAndFileToRequest","req","body","headers","method","payload","includes","toUpperCase","contentType","get","split","bodyByteSize","parseInt","hasBodyStream","text","data","JSON","parse","json","Promise","resolve","error","SyntaxError","logger","fields","files","options","config","bodyParser","upload","request","message","file","Array","isArray","_payload","clientUploadFile"],"mappings":"AAGA,SAASA,QAAQ,QAAQ,wBAAuB;AAChD,SAASC,wBAAwB,QAAQ,yCAAwC;AACjF,SAASC,uBAAuB,QAAQ,wCAAuC;AAI/E;;CAEC,GACD,OAAO,MAAMC,0BAAmD,OAAOC;IACrE,MAAM,EAAEC,IAAI,EAAEC,OAAO,EAAEC,MAAM,EAAEC,OAAO,EAAE,GAAGJ;IAE3C,IAAIG,UAAU;QAAC;QAAS;QAAQ;KAAM,CAACE,QAAQ,CAACF,OAAOG,WAAW,OAAOL,MAAM;QAC7E,MAAM,CAACM,YAAY,GAAG,AAACL,CAAAA,QAAQM,GAAG,CAAC,mBAAmB,EAAC,EAAGC,KAAK,CAAC,KAAK;QACrE,MAAMC,eAAeC,SAASX,IAAIE,OAAO,CAACM,GAAG,CAAC,qBAAqB,KAAK;QACxE,MAAMI,gBAAgBZ,IAAIC,IAAI,KAAK;QAEnC,IAAIM,gBAAgB,oBAAoB;YACtC,IAAI;gBACF,MAAMM,OAAO,MAAMb,IAAIa,IAAI;gBAC3B,MAAMC,OAAOD,OAAOE,KAAKC,KAAK,CAACH,QAAQ,CAAC;gBACxCb,IAAIc,IAAI,GAAGA;gBACX,iDAAiD;gBACjDd,IAAIiB,IAAI,GAAG,IAAMC,QAAQC,OAAO,CAACL;YACnC,EAAE,OAAOM,OAAO;gBACd,IAAIA,iBAAiBC,aAAa;oBAChC,MAAM,IAAIzB,SAAS,gBAAgB;gBACrC;gBACAI,IAAII,OAAO,CAACkB,MAAM,CAACF,KAAK,CAACA;gBACzB,MAAMA;YACR;QACF,OAAO,IAAI,AAACV,CAAAA,gBAAgBE,aAAY,KAAML,aAAaF,SAAS,eAAe;YACjF,MAAM,EAAEe,KAAK,EAAEG,MAAM,EAAEC,KAAK,EAAE,GAAG,MAAM3B,yBAAyB;gBAC9D4B,SAAS;oBACP,GAAIrB,QAAQsB,MAAM,CAACC,UAAU,IAAI,CAAC,CAAC;oBACnC,GAAIvB,QAAQsB,MAAM,CAACE,MAAM,IAAI,CAAC,CAAC;gBACjC;gBACAC,SAAS7B;YACX;YAEA,IAAIoB,OAAO;gBACT,MAAM,IAAIxB,SAASwB,MAAMU,OAAO;YAClC;YAEA,iDAAiD;YACjD,IAAIN,OAAO;gBACTxB,IAAIwB,KAAK,GAAGA;gBACZ,wEAAwE;gBACxE,sFAAsF;gBACtF,IAAIA,MAAMO,IAAI,IAAI,CAACC,MAAMC,OAAO,CAACT,MAAMO,IAAI,GAAG;oBAC5C/B,IAAI+B,IAAI,GAAGP,MAAMO,IAAI;gBACvB;YACF;YAEA,IAAIR,QAAQW,YAAY,OAAOX,OAAOW,QAAQ,KAAK,UAAU;gBAC3DlC,IAAIc,IAAI,GAAGC,KAAKC,KAAK,CAACO,OAAOW,QAAQ;YACvC;YAEA,IAAI,CAAClC,IAAI+B,IAAI,IAAIR,QAAQQ,QAAQ,OAAOR,QAAQQ,SAAS,UAAU;gBACjE,IAAII;gBAEJ,IAAI;oBACFA,mBAAmBpB,KAAKC,KAAK,CAACO,OAAOQ,IAAI;gBAC3C,EAAE,OAAM;oBACN,MAAM,IAAInC,SAAS,4BAA4B;gBACjD;gBAEAI,IAAI+B,IAAI,GAAG,MAAMjC,wBAAwB;oBACvCiC,MAAMI;oBACNnC;gBACF;YACF;QACF;IACF;AACF,EAAC"}
1
+ {"version":3,"sources":["../../src/utilities/addDataAndFileToRequest.ts"],"sourcesContent":["import type { PayloadRequest } from '../types/index.js'\nimport type { ClientUploadData } from '../uploads/getFileFromClientUpload.js'\n\nimport { APIError } from '../errors/APIError.js'\nimport { verifyClientUploadReceipt } from '../uploads/clientUploadReceipt.js'\nimport { processMultipartFormdata } from '../uploads/fetchAPI-multipart/index.js'\nimport { getFileFromClientUpload } from '../uploads/getFileFromClientUpload.js'\n\ntype AddDataAndFileToRequest = (req: PayloadRequest) => Promise<void>\n\n/**\n * Mutates the Request, appending 'data' and 'file' if found\n */\nexport const addDataAndFileToRequest: AddDataAndFileToRequest = async (req) => {\n const { body, headers, method, payload } = req\n\n if (method && ['PATCH', 'POST', 'PUT'].includes(method.toUpperCase()) && body) {\n const [contentType] = (headers.get('Content-Type') || '').split(';', 1)\n const bodyByteSize = parseInt(req.headers.get('Content-Length') || '0', 10)\n const hasBodyStream = req.body !== null\n\n if (contentType === 'application/json') {\n try {\n const text = await req.text?.()\n const data = text ? JSON.parse(text) : {}\n req.data = data\n // @ts-expect-error attach json method to request\n req.json = () => Promise.resolve(data)\n } catch (error) {\n if (error instanceof SyntaxError) {\n throw new APIError('Invalid JSON', 400)\n }\n req.payload.logger.error(error)\n throw error\n }\n } else if ((bodyByteSize || hasBodyStream) && contentType?.includes('multipart/')) {\n const { error, fields, files } = await processMultipartFormdata({\n options: {\n ...(payload.config.bodyParser || {}),\n ...(payload.config.upload || {}),\n },\n request: req as Request,\n })\n\n if (error) {\n throw new APIError(error.message)\n }\n\n // Set all files on req.files for access by hooks\n if (files) {\n req.files = files\n // Backwards compatibility: set req.file for standard upload collections\n // Guard: if multiple files share the field name \"file\", files.file is an array — skip\n if (files.file && !Array.isArray(files.file)) {\n req.file = files.file\n }\n }\n\n if (fields?._payload && typeof fields._payload === 'string') {\n req.data = JSON.parse(fields._payload)\n }\n\n if (!req.file && fields?.file && typeof fields?.file === 'string') {\n let clientUploadFile: ClientUploadData\n\n try {\n clientUploadFile = JSON.parse(fields.file) as ClientUploadData\n } catch {\n throw new APIError('A file name is required.', 400)\n }\n\n // The collection must come from the route, never from the request body: the body\n // is client-controlled and would select another collection's upload handlers.\n const collectionSlug =\n typeof req.routeParams?.collection === 'string' ? req.routeParams.collection : undefined\n const uploadConfig = collectionSlug\n ? req.payload.collections[collectionSlug]?.config.upload\n : undefined\n\n if (!collectionSlug || !uploadConfig) {\n throw new APIError('Invalid upload collection.', 400)\n }\n\n if (uploadConfig.requiresClientUploadReceipt) {\n const clientUploadContext = clientUploadFile.clientUploadContext\n\n if (\n !clientUploadContext ||\n typeof clientUploadContext !== 'object' ||\n typeof (clientUploadContext as { signedReceipt?: unknown }).signedReceipt !== 'string'\n ) {\n throw new APIError('A verified client upload reference is required.', 400)\n }\n\n const receipt = verifyClientUploadReceipt({\n collectionSlug,\n req,\n signedReceipt: (clientUploadContext as { signedReceipt: string }).signedReceipt,\n })\n\n if (receipt.filename !== clientUploadFile.filename) {\n throw new APIError('Client upload reference does not match this request.', 400)\n }\n\n clientUploadFile.clientUploadContext = receipt.context\n }\n\n // Pass the route-derived collection to the upload helper, never the body value.\n req.file = await getFileFromClientUpload({\n file: { ...clientUploadFile, collectionSlug },\n req,\n })\n }\n }\n }\n}\n"],"names":["APIError","verifyClientUploadReceipt","processMultipartFormdata","getFileFromClientUpload","addDataAndFileToRequest","req","body","headers","method","payload","includes","toUpperCase","contentType","get","split","bodyByteSize","parseInt","hasBodyStream","text","data","JSON","parse","json","Promise","resolve","error","SyntaxError","logger","fields","files","options","config","bodyParser","upload","request","message","file","Array","isArray","_payload","clientUploadFile","collectionSlug","routeParams","collection","undefined","uploadConfig","collections","requiresClientUploadReceipt","clientUploadContext","signedReceipt","receipt","filename","context"],"mappings":"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"}
@@ -60,6 +60,9 @@ const createClientUploadReq = ({ file, handler, upload })=>{
60
60
  logger: {
61
61
  error: ()=>{}
62
62
  }
63
+ },
64
+ routeParams: {
65
+ collection: 'media'
63
66
  }
64
67
  };
65
68
  };
@@ -72,6 +75,161 @@ describe('addDataAndFileToRequest', ()=>{
72
75
  expect(req.file?.name).toBe('hello.txt');
73
76
  expect(req.file?.mimetype).toBe('text/plain');
74
77
  });
78
+ it('should reject unsigned upload instructions before the route handler', async ()=>{
79
+ const formData = new FormData();
80
+ formData.append('file', JSON.stringify({
81
+ collectionSlug: 'private-media',
82
+ clientUploadContext: {
83
+ prefix: 'private'
84
+ },
85
+ filename: 'example.txt',
86
+ mimeType: 'text/plain',
87
+ size: 11
88
+ }));
89
+ const request = new Request('http://localhost/api/public-media', {
90
+ body: formData,
91
+ method: 'POST'
92
+ });
93
+ const privateHandler = vi.fn();
94
+ const publicHandler = vi.fn((_req, args)=>{
95
+ return new Response('hello world', {
96
+ headers: {
97
+ 'content-type': 'text/plain',
98
+ 'x-collection': args.params.collection
99
+ }
100
+ });
101
+ });
102
+ const req = {
103
+ body: request.body,
104
+ headers: request.headers,
105
+ method: request.method,
106
+ payload: {
107
+ collections: {
108
+ 'private-media': {
109
+ config: {
110
+ upload: {
111
+ handlers: [
112
+ privateHandler
113
+ ]
114
+ }
115
+ }
116
+ },
117
+ 'public-media': {
118
+ config: {
119
+ upload: {
120
+ handlers: [
121
+ publicHandler
122
+ ],
123
+ requiresClientUploadReceipt: true
124
+ }
125
+ }
126
+ }
127
+ },
128
+ config: {
129
+ bodyParser: {},
130
+ upload: {}
131
+ },
132
+ logger: {
133
+ error: ()=>{}
134
+ }
135
+ },
136
+ routeParams: {
137
+ collection: 'public-media'
138
+ }
139
+ };
140
+ await expect(addDataAndFileToRequest(req)).rejects.toThrow('A verified client upload reference is required.');
141
+ expect(privateHandler).not.toHaveBeenCalled();
142
+ expect(publicHandler).not.toHaveBeenCalled();
143
+ expect(req.file).toBeUndefined();
144
+ });
145
+ it('should require a route collection for upload instructions', async ()=>{
146
+ const formData = new FormData();
147
+ formData.append('file', JSON.stringify({
148
+ collectionSlug: 'media',
149
+ filename: 'example.txt',
150
+ mimeType: 'text/plain',
151
+ size: 11
152
+ }));
153
+ const request = new Request('http://localhost/api/graphql', {
154
+ body: formData,
155
+ method: 'POST'
156
+ });
157
+ const handler = vi.fn(()=>new Response('hello world'));
158
+ const req = {
159
+ body: request.body,
160
+ headers: request.headers,
161
+ method: request.method,
162
+ payload: {
163
+ collections: {
164
+ media: {
165
+ config: {
166
+ upload: {
167
+ handlers: [
168
+ handler
169
+ ]
170
+ }
171
+ }
172
+ }
173
+ },
174
+ config: {
175
+ bodyParser: {},
176
+ upload: {}
177
+ },
178
+ logger: {
179
+ error: ()=>{}
180
+ }
181
+ }
182
+ };
183
+ await expect(addDataAndFileToRequest(req)).rejects.toThrow('Invalid upload collection.');
184
+ expect(handler).not.toHaveBeenCalled();
185
+ });
186
+ it('should require the route collection to support uploads', async ()=>{
187
+ const formData = new FormData();
188
+ formData.append('file', JSON.stringify({
189
+ collectionSlug: 'media',
190
+ filename: 'example.txt',
191
+ mimeType: 'text/plain',
192
+ size: 11
193
+ }));
194
+ const request = new Request('http://localhost/api/posts', {
195
+ body: formData,
196
+ method: 'POST'
197
+ });
198
+ const handler = vi.fn(()=>new Response('hello world'));
199
+ const req = {
200
+ body: request.body,
201
+ headers: request.headers,
202
+ method: request.method,
203
+ payload: {
204
+ collections: {
205
+ media: {
206
+ config: {
207
+ upload: {
208
+ handlers: [
209
+ handler
210
+ ]
211
+ }
212
+ }
213
+ },
214
+ posts: {
215
+ config: {}
216
+ }
217
+ },
218
+ config: {
219
+ bodyParser: {},
220
+ upload: {}
221
+ },
222
+ logger: {
223
+ error: ()=>{}
224
+ }
225
+ },
226
+ routeParams: {
227
+ collection: 'posts'
228
+ }
229
+ };
230
+ await expect(addDataAndFileToRequest(req)).rejects.toThrow('Invalid upload collection.');
231
+ expect(handler).not.toHaveBeenCalled();
232
+ });
75
233
  describe('client uploads', ()=>{
76
234
  const tempFilesToRemove = [];
77
235
  afterEach(async ()=>{
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/utilities/addDataAndFileToRequest.spec.ts"],"sourcesContent":["import type { PayloadRequest } from '../types/index.js'\nimport type { ClientUploadData } from '../uploads/getFileFromClientUpload.js'\nimport type { SanitizedUploadConfig } from '../uploads/types.js'\n\nimport fs from 'fs/promises'\nimport { afterEach, describe, expect, it, vi } from 'vitest'\n\nimport { addDataAndFileToRequest } from './addDataAndFileToRequest.js'\n\ntype MinimalReq = Pick<PayloadRequest, 'body' | 'headers' | 'method' | 'payload'> & {\n file?: PayloadRequest['file']\n}\n\nconst createReqWithMultipartBody = (): MinimalReq => {\n const formData = new FormData()\n formData.append('file', new Blob(['hello world'], { type: 'text/plain' }), 'hello.txt')\n\n const request = new Request('http://localhost/api/upload', {\n body: formData,\n method: 'POST',\n })\n\n return {\n body: request.body,\n headers: request.headers,\n method: request.method,\n payload: {\n collections: {},\n config: {\n bodyParser: {},\n upload: {},\n },\n logger: {\n error: () => {},\n },\n } as unknown as PayloadRequest['payload'],\n }\n}\n\nconst createClientUploadReq = ({\n file,\n handler,\n upload,\n}: {\n file: ClientUploadData\n handler: NonNullable<SanitizedUploadConfig['handlers']>[number]\n upload?: Partial<SanitizedUploadConfig>\n}): MinimalReq => {\n const formData = new FormData()\n formData.append('file', JSON.stringify(file))\n\n const request = new Request('http://localhost/api/media', {\n body: formData,\n method: 'POST',\n })\n\n return {\n body: request.body,\n headers: request.headers,\n method: request.method,\n payload: {\n collections: {\n media: {\n config: {\n upload: {\n disableLocalStorage: true,\n handlers: [handler],\n ...upload,\n },\n },\n },\n },\n config: {\n bodyParser: {},\n upload: {},\n },\n logger: {\n error: () => {},\n },\n } as unknown as PayloadRequest['payload'],\n }\n}\n\ndescribe('addDataAndFileToRequest', () => {\n it('should parse multipart form-data even when content-length is absent', async () => {\n const req = createReqWithMultipartBody()\n\n expect(req.headers.get('content-length')).toBeNull()\n\n await addDataAndFileToRequest(req as PayloadRequest)\n\n expect(req.file).toBeDefined()\n expect(req.file?.name).toBe('hello.txt')\n expect(req.file?.mimetype).toBe('text/plain')\n })\n\n describe('client uploads', () => {\n const tempFilesToRemove: string[] = []\n\n afterEach(async () => {\n for (const tempFilePath of tempFilesToRemove) {\n await fs.rm(tempFilePath, { force: true })\n }\n tempFilesToRemove.length = 0\n })\n\n it('materializes client-upload metadata without buffering an unused cloud file', async () => {\n const handler = vi.fn(() => {\n throw new Error('No-content handler was invoked')\n })\n const req = createClientUploadReq({\n file: {\n clientUploadContext: { prefix: '' },\n collectionSlug: 'media',\n filename: 'large.mp4',\n mimeType: 'video/mp4',\n size: 5_000_000_000,\n },\n handler,\n upload: { disableLocalStorage: true },\n })\n\n await addDataAndFileToRequest(req as PayloadRequest)\n\n expect(handler).not.toHaveBeenCalled()\n expect(req.file).toMatchObject({\n clientUploadContext: { prefix: '' },\n mimetype: 'video/mp4',\n name: 'large.mp4',\n size: 5_000_000_000,\n })\n expect(req.file?.data.length).toBe(0)\n })\n\n it('streams a full-content client upload to a temp file without buffering the whole body', async () => {\n const chunks = [Buffer.from('chunk-one-'), Buffer.from('chunk-two')]\n const stream = new ReadableStream({\n start(controller) {\n for (const chunk of chunks) {\n controller.enqueue(chunk)\n }\n controller.close()\n },\n })\n const response = new Response(stream, {\n headers: { 'Content-Type': 'video/mp4' },\n status: 200,\n })\n const arrayBufferTripwire = vi.fn(async () => {\n throw new Error('Unexpected whole-body buffering')\n })\n Object.defineProperty(response, 'arrayBuffer', { value: arrayBufferTripwire })\n\n const handler = vi.fn(async () => response)\n const req = createClientUploadReq({\n file: {\n clientUploadContext: { prefix: '' },\n collectionSlug: 'media',\n filename: 'clip.mp4',\n mimeType: 'video/mp4',\n size: 20,\n },\n handler,\n upload: { disableLocalStorage: true, mimeTypes: ['video/*'] },\n })\n\n await addDataAndFileToRequest(req as PayloadRequest)\n tempFilesToRemove.push(req.file!.tempFilePath!)\n\n expect(arrayBufferTripwire).not.toHaveBeenCalled()\n expect(req.file?.data.length).toBe(0)\n expect(req.file?.tempFilePath).toBeDefined()\n const written = await fs.readFile(req.file!.tempFilePath!)\n expect(written.toString()).toBe(chunks.map((chunk) => chunk.toString()).join(''))\n })\n })\n})\n"],"names":["fs","afterEach","describe","expect","it","vi","addDataAndFileToRequest","createReqWithMultipartBody","formData","FormData","append","Blob","type","request","Request","body","method","headers","payload","collections","config","bodyParser","upload","logger","error","createClientUploadReq","file","handler","JSON","stringify","media","disableLocalStorage","handlers","req","get","toBeNull","toBeDefined","name","toBe","mimetype","tempFilesToRemove","tempFilePath","rm","force","length","fn","Error","clientUploadContext","prefix","collectionSlug","filename","mimeType","size","not","toHaveBeenCalled","toMatchObject","data","chunks","Buffer","from","stream","ReadableStream","start","controller","chunk","enqueue","close","response","Response","status","arrayBufferTripwire","Object","defineProperty","value","mimeTypes","push","written","readFile","toString","map","join"],"mappings":"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"}
1
+ {"version":3,"sources":["../../src/utilities/addDataAndFileToRequest.spec.ts"],"sourcesContent":["import type { PayloadRequest } from '../types/index.js'\nimport type { ClientUploadData } from '../uploads/getFileFromClientUpload.js'\nimport type { SanitizedUploadConfig } from '../uploads/types.js'\n\nimport fs from 'fs/promises'\nimport { afterEach, describe, expect, it, vi } from 'vitest'\n\nimport { addDataAndFileToRequest } from './addDataAndFileToRequest.js'\n\ntype MinimalReq = Pick<PayloadRequest, 'body' | 'headers' | 'method' | 'payload'> & {\n file?: PayloadRequest['file']\n routeParams?: PayloadRequest['routeParams']\n}\n\nconst createReqWithMultipartBody = (): MinimalReq => {\n const formData = new FormData()\n formData.append('file', new Blob(['hello world'], { type: 'text/plain' }), 'hello.txt')\n\n const request = new Request('http://localhost/api/upload', {\n body: formData,\n method: 'POST',\n })\n\n return {\n body: request.body,\n headers: request.headers,\n method: request.method,\n payload: {\n collections: {},\n config: {\n bodyParser: {},\n upload: {},\n },\n logger: {\n error: () => {},\n },\n } as unknown as PayloadRequest['payload'],\n }\n}\n\nconst createClientUploadReq = ({\n file,\n handler,\n upload,\n}: {\n file: ClientUploadData\n handler: NonNullable<SanitizedUploadConfig['handlers']>[number]\n upload?: Partial<SanitizedUploadConfig>\n}): MinimalReq => {\n const formData = new FormData()\n formData.append('file', JSON.stringify(file))\n\n const request = new Request('http://localhost/api/media', {\n body: formData,\n method: 'POST',\n })\n\n return {\n body: request.body,\n headers: request.headers,\n method: request.method,\n payload: {\n collections: {\n media: {\n config: {\n upload: {\n disableLocalStorage: true,\n handlers: [handler],\n ...upload,\n },\n },\n },\n },\n config: {\n bodyParser: {},\n upload: {},\n },\n logger: {\n error: () => {},\n },\n } as unknown as PayloadRequest['payload'],\n routeParams: {\n collection: 'media',\n },\n }\n}\n\ndescribe('addDataAndFileToRequest', () => {\n it('should parse multipart form-data even when content-length is absent', async () => {\n const req = createReqWithMultipartBody()\n\n expect(req.headers.get('content-length')).toBeNull()\n\n await addDataAndFileToRequest(req as PayloadRequest)\n\n expect(req.file).toBeDefined()\n expect(req.file?.name).toBe('hello.txt')\n expect(req.file?.mimetype).toBe('text/plain')\n })\n\n it('should reject unsigned upload instructions before the route handler', async () => {\n const formData = new FormData()\n formData.append(\n 'file',\n JSON.stringify({\n collectionSlug: 'private-media',\n clientUploadContext: { prefix: 'private' },\n filename: 'example.txt',\n mimeType: 'text/plain',\n size: 11,\n }),\n )\n\n const request = new Request('http://localhost/api/public-media', {\n body: formData,\n method: 'POST',\n })\n\n const privateHandler = vi.fn()\n const publicHandler = vi.fn((_req, args) => {\n return new Response('hello world', {\n headers: {\n 'content-type': 'text/plain',\n 'x-collection': args.params.collection,\n },\n })\n })\n\n const req: MinimalReq = {\n body: request.body,\n headers: request.headers,\n method: request.method,\n payload: {\n collections: {\n 'private-media': {\n config: {\n upload: {\n handlers: [privateHandler],\n },\n },\n },\n 'public-media': {\n config: {\n upload: {\n handlers: [publicHandler],\n requiresClientUploadReceipt: true,\n },\n },\n },\n },\n config: {\n bodyParser: {},\n upload: {},\n },\n logger: {\n error: () => {},\n },\n } as unknown as PayloadRequest['payload'],\n routeParams: {\n collection: 'public-media',\n },\n }\n\n await expect(addDataAndFileToRequest(req as PayloadRequest)).rejects.toThrow(\n 'A verified client upload reference is required.',\n )\n\n expect(privateHandler).not.toHaveBeenCalled()\n expect(publicHandler).not.toHaveBeenCalled()\n expect(req.file).toBeUndefined()\n })\n\n it('should require a route collection for upload instructions', async () => {\n const formData = new FormData()\n formData.append(\n 'file',\n JSON.stringify({\n collectionSlug: 'media',\n filename: 'example.txt',\n mimeType: 'text/plain',\n size: 11,\n }),\n )\n\n const request = new Request('http://localhost/api/graphql', {\n body: formData,\n method: 'POST',\n })\n const handler = vi.fn(() => new Response('hello world'))\n\n const req: MinimalReq = {\n body: request.body,\n headers: request.headers,\n method: request.method,\n payload: {\n collections: {\n media: {\n config: {\n upload: {\n handlers: [handler],\n },\n },\n },\n },\n config: {\n bodyParser: {},\n upload: {},\n },\n logger: {\n error: () => {},\n },\n } as unknown as PayloadRequest['payload'],\n }\n\n await expect(addDataAndFileToRequest(req as PayloadRequest)).rejects.toThrow(\n 'Invalid upload collection.',\n )\n\n expect(handler).not.toHaveBeenCalled()\n })\n\n it('should require the route collection to support uploads', async () => {\n const formData = new FormData()\n formData.append(\n 'file',\n JSON.stringify({\n collectionSlug: 'media',\n filename: 'example.txt',\n mimeType: 'text/plain',\n size: 11,\n }),\n )\n\n const request = new Request('http://localhost/api/posts', {\n body: formData,\n method: 'POST',\n })\n const handler = vi.fn(() => new Response('hello world'))\n\n const req: MinimalReq = {\n body: request.body,\n headers: request.headers,\n method: request.method,\n payload: {\n collections: {\n media: {\n config: {\n upload: {\n handlers: [handler],\n },\n },\n },\n posts: {\n config: {},\n },\n },\n config: {\n bodyParser: {},\n upload: {},\n },\n logger: {\n error: () => {},\n },\n } as unknown as PayloadRequest['payload'],\n routeParams: {\n collection: 'posts',\n },\n }\n\n await expect(addDataAndFileToRequest(req as PayloadRequest)).rejects.toThrow(\n 'Invalid upload collection.',\n )\n\n expect(handler).not.toHaveBeenCalled()\n })\n\n describe('client uploads', () => {\n const tempFilesToRemove: string[] = []\n\n afterEach(async () => {\n for (const tempFilePath of tempFilesToRemove) {\n await fs.rm(tempFilePath, { force: true })\n }\n tempFilesToRemove.length = 0\n })\n\n it('materializes client-upload metadata without buffering an unused cloud file', async () => {\n const handler = vi.fn(() => {\n throw new Error('No-content handler was invoked')\n })\n const req = createClientUploadReq({\n file: {\n clientUploadContext: { prefix: '' },\n collectionSlug: 'media',\n filename: 'large.mp4',\n mimeType: 'video/mp4',\n size: 5_000_000_000,\n },\n handler,\n upload: { disableLocalStorage: true },\n })\n\n await addDataAndFileToRequest(req as PayloadRequest)\n\n expect(handler).not.toHaveBeenCalled()\n expect(req.file).toMatchObject({\n clientUploadContext: { prefix: '' },\n mimetype: 'video/mp4',\n name: 'large.mp4',\n size: 5_000_000_000,\n })\n expect(req.file?.data.length).toBe(0)\n })\n\n it('streams a full-content client upload to a temp file without buffering the whole body', async () => {\n const chunks = [Buffer.from('chunk-one-'), Buffer.from('chunk-two')]\n const stream = new ReadableStream({\n start(controller) {\n for (const chunk of chunks) {\n controller.enqueue(chunk)\n }\n controller.close()\n },\n })\n const response = new Response(stream, {\n headers: { 'Content-Type': 'video/mp4' },\n status: 200,\n })\n const arrayBufferTripwire = vi.fn(async () => {\n throw new Error('Unexpected whole-body buffering')\n })\n Object.defineProperty(response, 'arrayBuffer', { value: arrayBufferTripwire })\n\n const handler = vi.fn(async () => response)\n const req = createClientUploadReq({\n file: {\n clientUploadContext: { prefix: '' },\n collectionSlug: 'media',\n filename: 'clip.mp4',\n mimeType: 'video/mp4',\n size: 20,\n },\n handler,\n upload: { disableLocalStorage: true, mimeTypes: ['video/*'] },\n })\n\n await addDataAndFileToRequest(req as PayloadRequest)\n tempFilesToRemove.push(req.file!.tempFilePath!)\n\n expect(arrayBufferTripwire).not.toHaveBeenCalled()\n expect(req.file?.data.length).toBe(0)\n expect(req.file?.tempFilePath).toBeDefined()\n const written = await fs.readFile(req.file!.tempFilePath!)\n expect(written.toString()).toBe(chunks.map((chunk) => chunk.toString()).join(''))\n })\n })\n})\n"],"names":["fs","afterEach","describe","expect","it","vi","addDataAndFileToRequest","createReqWithMultipartBody","formData","FormData","append","Blob","type","request","Request","body","method","headers","payload","collections","config","bodyParser","upload","logger","error","createClientUploadReq","file","handler","JSON","stringify","media","disableLocalStorage","handlers","routeParams","collection","req","get","toBeNull","toBeDefined","name","toBe","mimetype","collectionSlug","clientUploadContext","prefix","filename","mimeType","size","privateHandler","fn","publicHandler","_req","args","Response","params","requiresClientUploadReceipt","rejects","toThrow","not","toHaveBeenCalled","toBeUndefined","posts","tempFilesToRemove","tempFilePath","rm","force","length","Error","toMatchObject","data","chunks","Buffer","from","stream","ReadableStream","start","controller","chunk","enqueue","close","response","status","arrayBufferTripwire","Object","defineProperty","value","mimeTypes","push","written","readFile","toString","map","join"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"createPayloadRequest.d.ts","sourceRoot":"","sources":["../../src/utilities/createPayloadRequest.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAA;AAEzD,OAAO,KAAK,EAAkC,cAAc,EAAE,MAAM,mBAAmB,CAAA;AAUvF,KAAK,IAAI,GAAG;IACV,aAAa,CAAC,EAAE,OAAO,CAAA;IACvB,MAAM,EAAE,OAAO,CAAC,eAAe,CAAC,GAAG,eAAe,CAAA;IAClD,MAAM,CAAC,EAAE;QACP,UAAU,EAAE,MAAM,CAAA;KACnB,CAAA;IACD,uBAAuB,CAAC,EAAE,MAAM,CAAA;IAChC,OAAO,EAAE,OAAO,CAAA;CACjB,CAAA;AAED,eAAO,MAAM,oBAAoB,wFAM9B,IAAI,KAAG,OAAO,CAAC,cAAc,CA2G/B,CAAA"}
1
+ {"version":3,"file":"createPayloadRequest.d.ts","sourceRoot":"","sources":["../../src/utilities/createPayloadRequest.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAA;AAEzD,OAAO,KAAK,EAAkC,cAAc,EAAE,MAAM,mBAAmB,CAAA;AAUvF,KAAK,IAAI,GAAG;IACV,aAAa,CAAC,EAAE,OAAO,CAAA;IACvB,MAAM,EAAE,OAAO,CAAC,eAAe,CAAC,GAAG,eAAe,CAAA;IAClD,MAAM,CAAC,EAAE;QACP,UAAU,EAAE,MAAM,CAAA;KACnB,CAAA;IACD,uBAAuB,CAAC,EAAE,MAAM,CAAA;IAChC,OAAO,EAAE,OAAO,CAAA;CACjB,CAAA;AAED,eAAO,MAAM,oBAAoB,wFAM9B,IAAI,KAAG,OAAO,CAAC,cAAc,CA4G/B,CAAA"}
@@ -81,7 +81,8 @@ export const createPayloadRequest = async ({ canSetHeaders, config: configPromis
81
81
  canSetHeaders,
82
82
  headers: req.headers,
83
83
  isGraphQL,
84
- payload
84
+ payload,
85
+ req
85
86
  });
86
87
  req.user = user;
87
88
  if (responseHeaders) {
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/utilities/createPayloadRequest.ts"],"sourcesContent":["import { initI18n } from '@payloadcms/translations'\nimport * as qs from 'qs-esm'\n\nimport type { SanitizedConfig } from '../config/types.js'\nimport type { TypedFallbackLocale } from '../index.js'\nimport type { CustomPayloadRequestProperties, PayloadRequest } from '../types/index.js'\n\nimport { executeAuthStrategies } from '../auth/executeAuthStrategies.js'\nimport { getDataLoader } from '../collections/dataloader.js'\nimport { getPayload } from '../index.js'\nimport { sanitizeLocales } from './addLocalesToRequest.js'\nimport { formatAdminURL } from './formatAdminURL.js'\nimport { getRequestLanguage } from './getRequestLanguage.js'\nimport { parseCookies } from './parseCookies.js'\n\ntype Args = {\n canSetHeaders?: boolean\n config: Promise<SanitizedConfig> | SanitizedConfig\n params?: {\n collection: string\n }\n payloadInstanceCacheKey?: string\n request: Request\n}\n\nexport const createPayloadRequest = async ({\n canSetHeaders,\n config: configPromise,\n params,\n payloadInstanceCacheKey,\n request,\n}: Args): Promise<PayloadRequest> => {\n const cookies = parseCookies(request.headers)\n const payload = await getPayload({\n config: configPromise,\n cron: true,\n key: payloadInstanceCacheKey,\n })\n\n const { config } = payload\n const localization = config.localization\n\n const urlProperties = new URL(request.url)\n const { pathname, searchParams } = urlProperties\n\n const isGraphQL =\n !config.graphQL.disable &&\n pathname ===\n formatAdminURL({\n apiRoute: config.routes.api,\n path: config.routes.graphQL as `/${string}`,\n })\n\n const language = getRequestLanguage({\n config,\n cookies,\n headers: request.headers,\n })\n\n const i18n = await initI18n({\n config: config.i18n,\n context: 'api',\n language,\n })\n\n let locale = searchParams.get('locale')\n\n const { search: queryToParse } = urlProperties\n\n const query = queryToParse\n ? qs.parse(queryToParse, {\n allowEmptyArrays: true,\n arrayLimit: 1000,\n depth: 10,\n ignoreQueryPrefix: true,\n })\n : {}\n\n const fallbackFromRequest = (query.fallbackLocale ||\n searchParams.get('fallback-locale') ||\n searchParams.get('fallbackLocale')) as TypedFallbackLocale\n\n let fallbackLocale = fallbackFromRequest\n\n if (localization) {\n const locales = sanitizeLocales({\n fallbackLocale: fallbackLocale!,\n locale: locale!,\n localization,\n })\n\n fallbackLocale = locales.fallbackLocale!\n locale = locales.locale!\n }\n\n const customRequest: CustomPayloadRequestProperties = {\n context: {},\n fallbackLocale: fallbackLocale!,\n hash: urlProperties.hash,\n host: urlProperties.host,\n href: urlProperties.href,\n i18n,\n locale,\n origin: urlProperties.origin,\n pathname: urlProperties.pathname,\n payload,\n payloadAPI: isGraphQL ? 'GraphQL' : 'REST',\n payloadDataLoader: undefined!,\n payloadUploadSizes: {},\n port: urlProperties.port,\n protocol: urlProperties.protocol,\n query,\n routeParams: params || {},\n search: urlProperties.search,\n searchParams: urlProperties.searchParams,\n t: i18n.t,\n transactionID: undefined,\n user: null,\n }\n\n const req: PayloadRequest = Object.assign(request, customRequest)\n\n req.payloadDataLoader = getDataLoader(req)\n\n const { responseHeaders, user } = await executeAuthStrategies({\n canSetHeaders,\n headers: req.headers,\n isGraphQL,\n payload,\n })\n\n req.user = user\n\n if (responseHeaders) {\n req.responseHeaders = responseHeaders\n }\n\n return req\n}\n"],"names":["initI18n","qs","executeAuthStrategies","getDataLoader","getPayload","sanitizeLocales","formatAdminURL","getRequestLanguage","parseCookies","createPayloadRequest","canSetHeaders","config","configPromise","params","payloadInstanceCacheKey","request","cookies","headers","payload","cron","key","localization","urlProperties","URL","url","pathname","searchParams","isGraphQL","graphQL","disable","apiRoute","routes","api","path","language","i18n","context","locale","get","search","queryToParse","query","parse","allowEmptyArrays","arrayLimit","depth","ignoreQueryPrefix","fallbackFromRequest","fallbackLocale","locales","customRequest","hash","host","href","origin","payloadAPI","payloadDataLoader","undefined","payloadUploadSizes","port","protocol","routeParams","t","transactionID","user","req","Object","assign","responseHeaders"],"mappings":"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"}
1
+ {"version":3,"sources":["../../src/utilities/createPayloadRequest.ts"],"sourcesContent":["import { initI18n } from '@payloadcms/translations'\nimport * as qs from 'qs-esm'\n\nimport type { SanitizedConfig } from '../config/types.js'\nimport type { TypedFallbackLocale } from '../index.js'\nimport type { CustomPayloadRequestProperties, PayloadRequest } from '../types/index.js'\n\nimport { executeAuthStrategies } from '../auth/executeAuthStrategies.js'\nimport { getDataLoader } from '../collections/dataloader.js'\nimport { getPayload } from '../index.js'\nimport { sanitizeLocales } from './addLocalesToRequest.js'\nimport { formatAdminURL } from './formatAdminURL.js'\nimport { getRequestLanguage } from './getRequestLanguage.js'\nimport { parseCookies } from './parseCookies.js'\n\ntype Args = {\n canSetHeaders?: boolean\n config: Promise<SanitizedConfig> | SanitizedConfig\n params?: {\n collection: string\n }\n payloadInstanceCacheKey?: string\n request: Request\n}\n\nexport const createPayloadRequest = async ({\n canSetHeaders,\n config: configPromise,\n params,\n payloadInstanceCacheKey,\n request,\n}: Args): Promise<PayloadRequest> => {\n const cookies = parseCookies(request.headers)\n const payload = await getPayload({\n config: configPromise,\n cron: true,\n key: payloadInstanceCacheKey,\n })\n\n const { config } = payload\n const localization = config.localization\n\n const urlProperties = new URL(request.url)\n const { pathname, searchParams } = urlProperties\n\n const isGraphQL =\n !config.graphQL.disable &&\n pathname ===\n formatAdminURL({\n apiRoute: config.routes.api,\n path: config.routes.graphQL as `/${string}`,\n })\n\n const language = getRequestLanguage({\n config,\n cookies,\n headers: request.headers,\n })\n\n const i18n = await initI18n({\n config: config.i18n,\n context: 'api',\n language,\n })\n\n let locale = searchParams.get('locale')\n\n const { search: queryToParse } = urlProperties\n\n const query = queryToParse\n ? qs.parse(queryToParse, {\n allowEmptyArrays: true,\n arrayLimit: 1000,\n depth: 10,\n ignoreQueryPrefix: true,\n })\n : {}\n\n const fallbackFromRequest = (query.fallbackLocale ||\n searchParams.get('fallback-locale') ||\n searchParams.get('fallbackLocale')) as TypedFallbackLocale\n\n let fallbackLocale = fallbackFromRequest\n\n if (localization) {\n const locales = sanitizeLocales({\n fallbackLocale: fallbackLocale!,\n locale: locale!,\n localization,\n })\n\n fallbackLocale = locales.fallbackLocale!\n locale = locales.locale!\n }\n\n const customRequest: CustomPayloadRequestProperties = {\n context: {},\n fallbackLocale: fallbackLocale!,\n hash: urlProperties.hash,\n host: urlProperties.host,\n href: urlProperties.href,\n i18n,\n locale,\n origin: urlProperties.origin,\n pathname: urlProperties.pathname,\n payload,\n payloadAPI: isGraphQL ? 'GraphQL' : 'REST',\n payloadDataLoader: undefined!,\n payloadUploadSizes: {},\n port: urlProperties.port,\n protocol: urlProperties.protocol,\n query,\n routeParams: params || {},\n search: urlProperties.search,\n searchParams: urlProperties.searchParams,\n t: i18n.t,\n transactionID: undefined,\n user: null,\n }\n\n const req: PayloadRequest = Object.assign(request, customRequest)\n\n req.payloadDataLoader = getDataLoader(req)\n\n const { responseHeaders, user } = await executeAuthStrategies({\n canSetHeaders,\n headers: req.headers,\n isGraphQL,\n payload,\n req,\n })\n\n req.user = user\n\n if (responseHeaders) {\n req.responseHeaders = responseHeaders\n }\n\n return req\n}\n"],"names":["initI18n","qs","executeAuthStrategies","getDataLoader","getPayload","sanitizeLocales","formatAdminURL","getRequestLanguage","parseCookies","createPayloadRequest","canSetHeaders","config","configPromise","params","payloadInstanceCacheKey","request","cookies","headers","payload","cron","key","localization","urlProperties","URL","url","pathname","searchParams","isGraphQL","graphQL","disable","apiRoute","routes","api","path","language","i18n","context","locale","get","search","queryToParse","query","parse","allowEmptyArrays","arrayLimit","depth","ignoreQueryPrefix","fallbackFromRequest","fallbackLocale","locales","customRequest","hash","host","href","origin","payloadAPI","payloadDataLoader","undefined","payloadUploadSizes","port","protocol","routeParams","t","transactionID","user","req","Object","assign","responseHeaders"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"deepCopyObject.d.ts","sourceRoot":"","sources":["../../src/utilities/deepCopyObject.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAA;AA2DlD,eAAO,MAAM,cAAc,GAAI,CAAC,KAAK,CAAC,KAAG,CAiCxC,CAAA;AAQD;;;;;;;;;GASG;AACH,wBAAgB,oBAAoB,CAAC,CAAC,SAAS,SAAS,EAAE,KAAK,EAAE,CAAC,EAAE,eAAe,UAAQ,GAAG,CAAC,CAwB9F;AAED,wBAAgB,0CAA0C,CAAC,CAAC,SAAS,SAAS,EAC5E,KAAK,EAAE,CAAC,EACR,IAAI,GAAE;IACJ,YAAY,CAAC,EAAE,OAAO,CAAA;CAClB,GACL,CAAC,CAoCH;AAED;;;GAGG;AACH,wBAAgB,qBAAqB,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,KAAK,GAAE,OAAO,CAAC,GAAG,EAAE,GAAG,CAAiB,GAAG,CAAC,CAqE/F"}
1
+ {"version":3,"file":"deepCopyObject.d.ts","sourceRoot":"","sources":["../../src/utilities/deepCopyObject.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAA;AA2DlD,eAAO,MAAM,cAAc,GAAI,CAAC,KAAK,CAAC,KAAG,CAiDxC,CAAA;AAQD;;;;;;;;;GASG;AACH,wBAAgB,oBAAoB,CAAC,CAAC,SAAS,SAAS,EAAE,KAAK,EAAE,CAAC,EAAE,eAAe,UAAQ,GAAG,CAAC,CA6C9F;AAED,wBAAgB,0CAA0C,CAAC,CAAC,SAAS,SAAS,EAC5E,KAAK,EAAE,CAAC,EACR,IAAI,GAAE;IACJ,YAAY,CAAC,EAAE,OAAO,CAAA;CAClB,GACL,CAAC,CAyDH;AAED;;;GAGG;AACH,wBAAgB,qBAAqB,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,KAAK,GAAE,OAAO,CAAC,GAAG,EAAE,GAAG,CAAiB,GAAG,CAAC,CAyE/F"}