payload 3.89.0-internal.95c9cba → 3.90.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (468) 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 +123 -23
  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 +82 -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 +146 -48
  255. package/dist/index.d.ts +4 -1
  256. package/dist/index.d.ts.map +1 -1
  257. package/dist/index.js +3 -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/collection.d.ts.map +1 -1
  266. package/dist/queues/config/collection.js +6 -0
  267. package/dist/queues/config/collection.js.map +1 -1
  268. package/dist/queues/config/types/index.d.ts +4 -1
  269. package/dist/queues/config/types/index.d.ts.map +1 -1
  270. package/dist/queues/config/types/index.js.map +1 -1
  271. package/dist/queues/endpoints/handleSchedules.d.ts.map +1 -1
  272. package/dist/queues/endpoints/handleSchedules.js +2 -1
  273. package/dist/queues/endpoints/handleSchedules.js.map +1 -1
  274. package/dist/queues/endpoints/run.d.ts.map +1 -1
  275. package/dist/queues/endpoints/run.js +2 -1
  276. package/dist/queues/endpoints/run.js.map +1 -1
  277. package/dist/uploads/assertClientUploadAccess.d.ts +7 -0
  278. package/dist/uploads/assertClientUploadAccess.d.ts.map +1 -0
  279. package/dist/uploads/assertClientUploadAccess.js +27 -0
  280. package/dist/uploads/assertClientUploadAccess.js.map +1 -0
  281. package/dist/uploads/assertClientUploadAllowed.d.ts +11 -0
  282. package/dist/uploads/assertClientUploadAllowed.d.ts.map +1 -0
  283. package/dist/uploads/assertClientUploadAllowed.js +46 -0
  284. package/dist/uploads/assertClientUploadAllowed.js.map +1 -0
  285. package/dist/uploads/assertClientUploadAllowed.spec.js +91 -0
  286. package/dist/uploads/assertClientUploadAllowed.spec.js.map +1 -0
  287. package/dist/uploads/checkFileRestrictions.d.ts +4 -1
  288. package/dist/uploads/checkFileRestrictions.d.ts.map +1 -1
  289. package/dist/uploads/checkFileRestrictions.js +66 -26
  290. package/dist/uploads/checkFileRestrictions.js.map +1 -1
  291. package/dist/uploads/clientUploadReceipt.d.ts +23 -0
  292. package/dist/uploads/clientUploadReceipt.d.ts.map +1 -0
  293. package/dist/uploads/clientUploadReceipt.js +55 -0
  294. package/dist/uploads/clientUploadReceipt.js.map +1 -0
  295. package/dist/uploads/deleteAssociatedFiles.d.ts.map +1 -1
  296. package/dist/uploads/deleteAssociatedFiles.js +33 -8
  297. package/dist/uploads/deleteAssociatedFiles.js.map +1 -1
  298. package/dist/uploads/deleteAssociatedFiles.spec.js +124 -0
  299. package/dist/uploads/deleteAssociatedFiles.spec.js.map +1 -0
  300. package/dist/uploads/detectSvgFromXml.d.ts +1 -3
  301. package/dist/uploads/detectSvgFromXml.d.ts.map +1 -1
  302. package/dist/uploads/detectSvgFromXml.js +3 -40
  303. package/dist/uploads/detectSvgFromXml.js.map +1 -1
  304. package/dist/uploads/endpoints/getFile.d.ts.map +1 -1
  305. package/dist/uploads/endpoints/getFile.js +5 -3
  306. package/dist/uploads/endpoints/getFile.js.map +1 -1
  307. package/dist/uploads/fetchAPI-multipart/handlers.d.ts +2 -2
  308. package/dist/uploads/fetchAPI-multipart/handlers.d.ts.map +1 -1
  309. package/dist/uploads/fetchAPI-multipart/handlers.js +18 -5
  310. package/dist/uploads/fetchAPI-multipart/handlers.js.map +1 -1
  311. package/dist/uploads/fetchAPI-multipart/index.d.ts.map +1 -1
  312. package/dist/uploads/fetchAPI-multipart/index.js +24 -2
  313. package/dist/uploads/fetchAPI-multipart/index.js.map +1 -1
  314. package/dist/uploads/fetchAPI-multipart/processMultipart.d.ts +0 -6
  315. package/dist/uploads/fetchAPI-multipart/processMultipart.d.ts.map +1 -1
  316. package/dist/uploads/fetchAPI-multipart/processMultipart.js +146 -126
  317. package/dist/uploads/fetchAPI-multipart/processMultipart.js.map +1 -1
  318. package/dist/uploads/fetchAPI-multipart/processMultipart.spec.js +663 -0
  319. package/dist/uploads/fetchAPI-multipart/processMultipart.spec.js.map +1 -0
  320. package/dist/uploads/generateFileData.d.ts +3 -1
  321. package/dist/uploads/generateFileData.d.ts.map +1 -1
  322. package/dist/uploads/generateFileData.js +29 -16
  323. package/dist/uploads/generateFileData.js.map +1 -1
  324. package/dist/uploads/getBaseFields.d.ts.map +1 -1
  325. package/dist/uploads/getBaseFields.js +3 -1
  326. package/dist/uploads/getBaseFields.js.map +1 -1
  327. package/dist/uploads/getExternalFile.d.ts +1 -1
  328. package/dist/uploads/getExternalFile.d.ts.map +1 -1
  329. package/dist/uploads/getExternalFile.js +60 -15
  330. package/dist/uploads/getExternalFile.js.map +1 -1
  331. package/dist/uploads/getFileFromClientUpload.d.ts +2 -2
  332. package/dist/uploads/getFileFromClientUpload.d.ts.map +1 -1
  333. package/dist/uploads/getFileFromClientUpload.js +4 -4
  334. package/dist/uploads/getFileFromClientUpload.js.map +1 -1
  335. package/dist/uploads/getFileFromClientUpload.spec.js +62 -0
  336. package/dist/uploads/getFileFromClientUpload.spec.js.map +1 -1
  337. package/dist/uploads/getFileTypeFallback.d.ts.map +1 -1
  338. package/dist/uploads/getFileTypeFallback.js +3 -1
  339. package/dist/uploads/getFileTypeFallback.js.map +1 -1
  340. package/dist/uploads/getFileTypeIdentity.d.ts +19 -0
  341. package/dist/uploads/getFileTypeIdentity.d.ts.map +1 -0
  342. package/dist/uploads/getFileTypeIdentity.js +34 -0
  343. package/dist/uploads/getFileTypeIdentity.js.map +1 -0
  344. package/dist/uploads/getFileTypeIdentity.spec.js +43 -0
  345. package/dist/uploads/getFileTypeIdentity.spec.js.map +1 -0
  346. package/dist/uploads/isProcessableImage.d.ts +2 -0
  347. package/dist/uploads/isProcessableImage.d.ts.map +1 -0
  348. package/dist/uploads/isProcessableImage.js +7 -0
  349. package/dist/uploads/isProcessableImage.js.map +1 -0
  350. package/dist/uploads/safeFetch.d.ts.map +1 -1
  351. package/dist/uploads/safeFetch.js +3 -2
  352. package/dist/uploads/safeFetch.js.map +1 -1
  353. package/dist/uploads/sanitizeUploadData.d.ts +26 -0
  354. package/dist/uploads/sanitizeUploadData.d.ts.map +1 -0
  355. package/dist/uploads/sanitizeUploadData.js +159 -0
  356. package/dist/uploads/sanitizeUploadData.js.map +1 -0
  357. package/dist/uploads/sanitizeUploadData.spec.js +255 -0
  358. package/dist/uploads/sanitizeUploadData.spec.js.map +1 -0
  359. package/dist/uploads/types.d.ts +11 -3
  360. package/dist/uploads/types.d.ts.map +1 -1
  361. package/dist/uploads/types.js.map +1 -1
  362. package/dist/uploads/unlinkClientUploadTempFile.d.ts +20 -0
  363. package/dist/uploads/unlinkClientUploadTempFile.d.ts.map +1 -0
  364. package/dist/uploads/unlinkClientUploadTempFile.js +30 -0
  365. package/dist/uploads/unlinkClientUploadTempFile.js.map +1 -0
  366. package/dist/uploads/unlinkTempFiles.d.ts.map +1 -1
  367. package/dist/uploads/unlinkTempFiles.js +7 -9
  368. package/dist/uploads/unlinkTempFiles.js.map +1 -1
  369. package/dist/uploads/unlinkTempFiles.spec.js +61 -1
  370. package/dist/uploads/unlinkTempFiles.spec.js.map +1 -1
  371. package/dist/uploads/uploadContentSecurityPolicy.d.ts +2 -0
  372. package/dist/uploads/uploadContentSecurityPolicy.d.ts.map +1 -0
  373. package/dist/uploads/uploadContentSecurityPolicy.js +3 -0
  374. package/dist/uploads/uploadContentSecurityPolicy.js.map +1 -0
  375. package/dist/uploads/validateISOBaseMediaFile.d.ts +4 -0
  376. package/dist/uploads/validateISOBaseMediaFile.d.ts.map +1 -0
  377. package/dist/uploads/validateISOBaseMediaFile.js +91 -0
  378. package/dist/uploads/validateISOBaseMediaFile.js.map +1 -0
  379. package/dist/uploads/validateISOBaseMediaFile.spec.js +130 -0
  380. package/dist/uploads/validateISOBaseMediaFile.spec.js.map +1 -0
  381. package/dist/uploads/validateSvg.d.ts +10 -4
  382. package/dist/uploads/validateSvg.d.ts.map +1 -1
  383. package/dist/uploads/validateSvg.js +280 -40
  384. package/dist/uploads/validateSvg.js.map +1 -1
  385. package/dist/uploads/validateSvg.spec.js +123 -0
  386. package/dist/uploads/validateSvg.spec.js.map +1 -0
  387. package/dist/uploads/validateUploadFilename.d.ts +3 -0
  388. package/dist/uploads/validateUploadFilename.d.ts.map +1 -0
  389. package/dist/uploads/validateUploadFilename.js +13 -0
  390. package/dist/uploads/validateUploadFilename.js.map +1 -0
  391. package/dist/uploads/validateUploadFilename.spec.js +24 -0
  392. package/dist/uploads/validateUploadFilename.spec.js.map +1 -0
  393. package/dist/utilities/addDataAndFileToRequest.d.ts.map +1 -1
  394. package/dist/utilities/addDataAndFileToRequest.js +28 -1
  395. package/dist/utilities/addDataAndFileToRequest.js.map +1 -1
  396. package/dist/utilities/addDataAndFileToRequest.spec.js +158 -0
  397. package/dist/utilities/addDataAndFileToRequest.spec.js.map +1 -1
  398. package/dist/utilities/createPayloadRequest.d.ts.map +1 -1
  399. package/dist/utilities/createPayloadRequest.js +2 -1
  400. package/dist/utilities/createPayloadRequest.js.map +1 -1
  401. package/dist/utilities/deepCopyObject.d.ts.map +1 -1
  402. package/dist/utilities/deepCopyObject.js +110 -19
  403. package/dist/utilities/deepCopyObject.js.map +1 -1
  404. package/dist/utilities/deepCopyObject.spec.js +216 -0
  405. package/dist/utilities/deepCopyObject.spec.js.map +1 -0
  406. package/dist/utilities/fieldPath.d.ts +13 -0
  407. package/dist/utilities/fieldPath.d.ts.map +1 -0
  408. package/dist/utilities/fieldPath.js +51 -0
  409. package/dist/utilities/fieldPath.js.map +1 -0
  410. package/dist/utilities/fieldPath.spec.js +155 -0
  411. package/dist/utilities/fieldPath.spec.js.map +1 -0
  412. package/dist/utilities/getEntityPermissions/getEntityPermissions.d.ts.map +1 -1
  413. package/dist/utilities/getEntityPermissions/getEntityPermissions.js +2 -0
  414. package/dist/utilities/getEntityPermissions/getEntityPermissions.js.map +1 -1
  415. package/dist/utilities/getObjectDotNotation.d.ts.map +1 -1
  416. package/dist/utilities/getObjectDotNotation.js +7 -1
  417. package/dist/utilities/getObjectDotNotation.js.map +1 -1
  418. package/dist/utilities/getObjectDotNotation.spec.js +33 -0
  419. package/dist/utilities/getObjectDotNotation.spec.js.map +1 -0
  420. package/dist/utilities/getSafeRedirect.spec.js +14 -0
  421. package/dist/utilities/getSafeRedirect.spec.js.map +1 -1
  422. package/dist/utilities/getTopLevelFieldNames.d.ts +2 -0
  423. package/dist/utilities/getTopLevelFieldNames.d.ts.map +1 -0
  424. package/dist/utilities/getTopLevelFieldNames.js +3 -0
  425. package/dist/utilities/getTopLevelFieldNames.js.map +1 -0
  426. package/dist/utilities/getTopLevelFieldNames.spec.js +18 -0
  427. package/dist/utilities/getTopLevelFieldNames.spec.js.map +1 -0
  428. package/dist/utilities/handleEndpoints.js +1 -1
  429. package/dist/utilities/handleEndpoints.js.map +1 -1
  430. package/dist/utilities/parseParams/index.d.ts.map +1 -1
  431. package/dist/utilities/parseParams/index.js +3 -1
  432. package/dist/utilities/parseParams/index.js.map +1 -1
  433. package/dist/utilities/parseParams/index.spec.js +8 -0
  434. package/dist/utilities/parseParams/index.spec.js.map +1 -1
  435. package/dist/utilities/traverseFields.d.ts.map +1 -1
  436. package/dist/utilities/traverseFields.js +5 -14
  437. package/dist/utilities/traverseFields.js.map +1 -1
  438. package/dist/utilities/unflatten.d.ts.map +1 -1
  439. package/dist/utilities/unflatten.js +21 -9
  440. package/dist/utilities/unflatten.js.map +1 -1
  441. package/dist/utilities/unflatten.spec.js +38 -0
  442. package/dist/utilities/unflatten.spec.js.map +1 -0
  443. package/dist/utilities/wrapInternalEndpoints.d.ts.map +1 -1
  444. package/dist/utilities/wrapInternalEndpoints.js +10 -3
  445. package/dist/utilities/wrapInternalEndpoints.js.map +1 -1
  446. package/dist/utilities/wrapInternalEndpoints.spec.js +124 -0
  447. package/dist/utilities/wrapInternalEndpoints.spec.js.map +1 -0
  448. package/dist/versions/allLocalesPublicationStatus.d.ts +38 -0
  449. package/dist/versions/allLocalesPublicationStatus.d.ts.map +1 -0
  450. package/dist/versions/allLocalesPublicationStatus.js +57 -0
  451. package/dist/versions/allLocalesPublicationStatus.js.map +1 -0
  452. package/dist/versions/getLatestGlobalVersion.d.ts.map +1 -1
  453. package/dist/versions/getLatestGlobalVersion.js +10 -2
  454. package/dist/versions/getLatestGlobalVersion.js.map +1 -1
  455. package/dist/versions/getRestoredStatusesToAuthorize.d.ts +9 -0
  456. package/dist/versions/getRestoredStatusesToAuthorize.d.ts.map +1 -0
  457. package/dist/versions/getRestoredStatusesToAuthorize.js +22 -0
  458. package/dist/versions/getRestoredStatusesToAuthorize.js.map +1 -0
  459. package/dist/versions/getRestoredStatusesToAuthorize.spec.js +50 -0
  460. package/dist/versions/getRestoredStatusesToAuthorize.spec.js.map +1 -0
  461. package/dist/versions/schedule/job.d.ts +2 -2
  462. package/dist/versions/schedule/job.d.ts.map +1 -1
  463. package/dist/versions/schedule/job.js +11 -7
  464. package/dist/versions/schedule/job.js.map +1 -1
  465. package/dist/versions/schedule/types.d.ts +5 -1
  466. package/dist/versions/schedule/types.d.ts.map +1 -1
  467. package/dist/versions/schedule/types.js.map +1 -1
  468. package/package.json +4 -2
@@ -130,6 +130,10 @@ type Admin = {
130
130
  controls?: PayloadComponent[];
131
131
  };
132
132
  };
133
+ export type ExternalFileHeaderFilterContext = {
134
+ isSameOrigin: boolean;
135
+ url: string;
136
+ };
133
137
  export type UploadConfig = {
134
138
  /**
135
139
  * The adapter name to use for uploads. Used for storage adapter telemetry.
@@ -187,8 +191,10 @@ export type UploadConfig = {
187
191
  */
188
192
  displayPreview?: boolean;
189
193
  /**
190
- *
191
- * Accepts existing headers and returns the headers after filtering or modifying.
194
+ * Accepts existing headers and returns the headers after filtering or modifying. The optional
195
+ * context identifies the destination for the current request, including each redirect hop.
196
+ * `isSameOrigin` is true only when that destination matches a trusted origin established for a
197
+ * relative file URL.
192
198
  * If using this option, you should handle the removal of any sensitive cookies
193
199
  * (like payload-prefixed cookies) to prevent leaking session information to external
194
200
  * services. By default, Payload automatically filters out payload-prefixed cookies
@@ -197,7 +203,7 @@ export type UploadConfig = {
197
203
  * Useful for adding custom headers to fetch from external providers.
198
204
  * @default undefined
199
205
  */
200
- externalFileHeaderFilter?: (headers: Record<string, string>) => Record<string, string>;
206
+ externalFileHeaderFilter?: (headers: Record<string, string>, context?: ExternalFileHeaderFilterContext) => Record<string, string>;
201
207
  /**
202
208
  * Field slugs to use for a compound index instead of the default filename index.
203
209
  */
@@ -268,6 +274,8 @@ export type UploadConfig = {
268
274
  pasteURL?: {
269
275
  allowList: AllowList;
270
276
  } | false;
277
+ /** @internal Require a server-issued receipt before invoking client-upload handlers. */
278
+ requiresClientUploadReceipt?: boolean;
271
279
  /**
272
280
  * Sharp resize options for the original image.
273
281
  * @link https://sharp.pixelplumbing.com/api-resize#resize
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/uploads/types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/uploads/types.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/uploads/types.ts"],"sourcesContent":["import type { ResizeOptions, Sharp, SharpOptions } from 'sharp'\n\nimport type { CollectionConfig, TypeWithID } from '../collections/config/types.js'\nimport type { PayloadComponent } from '../config/types.js'\nimport type { PayloadRequest } from '../types/index.js'\nimport type { WithMetadata } from './optionallyAppendMetadata.js'\n\nexport type FileSize = {\n filename: null | string\n filesize: null | number\n height: null | number\n mimeType: null | string\n url?: null | string // TODO V4: make non-optional\n width: null | number\n}\n\n// TODO: deprecate in Payload v4.\n/**\n * FileSizeImproved is a more precise type, and will replace FileSize in Payload v4.\n * This type is for internal use only as it will be deprecated in the future.\n * @internal\n */\nexport type FileSizeImproved = {\n url: null | string\n} & FileSize\n\nexport type FileSizes = {\n [size: string]: FileSize\n}\n\nexport type FileData = {\n filename: string\n filesize: number\n focalX?: number\n focalY?: number\n height: number\n mimeType: string\n sizes: FileSizes\n tempFilePath?: string\n url?: string\n width: number\n}\n\nexport type ProbedImageSize = {\n height: number\n width: number\n}\n\n/**\n * Params sent to the sharp `toFormat()` function\n * @link https://sharp.pixelplumbing.com/api-output#toformat\n */\nexport type ImageUploadFormatOptions = {\n format: Parameters<Sharp['toFormat']>[0]\n options?: Parameters<Sharp['toFormat']>[1]\n}\n\n/**\n * Params sent to the sharp trim() function\n * @link https://sharp.pixelplumbing.com/api-resize#trim\n */\nexport type ImageUploadTrimOptions = Parameters<Sharp['trim']>[0]\n\nexport type GenerateImageName = (args: {\n extension: string\n height: number\n originalName: string\n sizeName: string\n width: number\n}) => string\n\nexport type ImageSize = {\n /**\n * Admin UI options that control how this image size appears in list views.\n *\n * NOTE: In Payload v4, these options (`disableGroupBy`, `disableListColumn` and `disableListFilter`)\n * should default to `true` so image size subfields are hidden from list columns\n * and filters by default, reducing noise in the admin UI.\n */\n admin?: {\n /**\n * If set to true, this image size will not be available\n * as a selectable groupBy option in the collection list view.\n * @default false\n */\n disableGroupBy?: boolean\n /**\n * If set to true, this image size will not be available\n * as a selectable column in the collection list view.\n * @default false\n */\n disableListColumn?: boolean\n /**\n * If set to true, this image size will not be available\n * as a filter option in the collection list view.\n * @default false\n */\n disableListFilter?: boolean\n }\n /**\n * @deprecated prefer position\n */\n crop?: string // comes from sharp package\n formatOptions?: ImageUploadFormatOptions\n /**\n * Generate a custom name for the file of this image size.\n */\n generateImageName?: GenerateImageName\n name: string\n trimOptions?: ImageUploadTrimOptions\n /**\n * When an uploaded image is smaller than the defined image size, we have 3 options:\n *\n * `undefined | false | true`\n *\n * 1. `undefined` [default]: uploading images with smaller width AND height than the image size will return null\n * 2. `false`: always enlarge images to the image size\n * 3. `true`: if the image is smaller than the image size, return the original image\n */\n withoutEnlargement?: ResizeOptions['withoutEnlargement']\n} & Omit<ResizeOptions, 'withoutEnlargement'>\n\nexport type GetAdminThumbnail = (args: { doc: Record<string, unknown> }) => false | null | string\n\nexport type AllowList = Array<{\n hostname: string\n pathname?: string\n port?: string\n protocol?: 'http' | 'https'\n search?: string\n}>\n\nexport type FileAllowList = Array<{\n extensions: string[]\n mimeType: string\n}>\n\ntype Admin = {\n components?: {\n /**\n * The Controls component to extend the upload controls in the admin panel.\n */\n controls?: PayloadComponent[]\n }\n}\n\nexport type UploadConfig = {\n /**\n * The adapter name to use for uploads. Used for storage adapter telemetry.\n * @default undefined\n */\n adapter?: string\n /**\n * The admin configuration for the upload field.\n */\n admin?: Admin\n /**\n * Represents an admin thumbnail, which can be either a React component or a string.\n * - If a string, it should be one of the image size names.\n * - A function that generates a fully qualified URL for the thumbnail, receives the doc as the only argument.\n **/\n adminThumbnail?: GetAdminThumbnail | string\n /**\n * Allow restricted file types known to be problematic.\n * - If set to `true`, it will allow all file types.\n * - If set to `false`, it will not allow file types and extensions known to be problematic.\n * - This setting is overriden by the `mimeTypes` option.\n * @default false\n */\n allowRestrictedFileTypes?: boolean\n /**\n * Enables bulk upload of files from the list view.\n * @default true\n */\n bulkUpload?: boolean\n /**\n * Appends a cache tag to the image URL when fetching the thumbnail in the admin panel. It may be desirable to disable this when hosting via CDNs with strict parameters.\n *\n * @default true\n */\n cacheTags?: boolean\n /**\n * Sharp constructor options to be passed to the uploaded file.\n * @link https://sharp.pixelplumbing.com/api-constructor/#sharp\n */\n constructorOptions?: SharpOptions\n /**\n * Enables cropping of images.\n * @default true\n */\n crop?: boolean\n /**\n * Disable the ability to save files to disk.\n * @default false\n */\n disableLocalStorage?: boolean\n /**\n * Enable displaying preview of the uploaded file in Upload fields related to this Collection.\n * Can be locally overridden by `displayPreview` option in Upload field.\n * @default false\n */\n displayPreview?: boolean\n /**\n *\n * Accepts existing headers and returns the headers after filtering or modifying.\n * If using this option, you should handle the removal of any sensitive cookies\n * (like payload-prefixed cookies) to prevent leaking session information to external\n * services. By default, Payload automatically filters out payload-prefixed cookies\n * when this option is NOT defined.\n *\n * Useful for adding custom headers to fetch from external providers.\n * @default undefined\n */\n externalFileHeaderFilter?: (headers: Record<string, string>) => Record<string, string>\n /**\n * Field slugs to use for a compound index instead of the default filename index.\n */\n filenameCompoundIndex?: string[]\n /**\n * Require files to be uploaded when creating a document.\n * @default true\n */\n filesRequiredOnCreate?: boolean\n /**\n * Enables focal point positioning for image manipulation.\n * @default true\n */\n focalPoint?: boolean\n /**\n * Format options for the uploaded file. Formatting image sizes needs to be done within each formatOptions individually.\n */\n formatOptions?: ImageUploadFormatOptions\n /**\n * Custom handlers to run when a file is fetched.\n *\n * - If a handler returns a Response, the response will be sent to the client and no further handlers will be run.\n * - If a handler returns null, the next handler will be run.\n * - If no handlers return a response the file will be returned by default.\n *\n * @link https://sharp.pixelplumbing.com/api-output/#toformat\n * @default undefined\n */\n handlers?: ((\n req: PayloadRequest,\n args: {\n doc: TypeWithID\n headers?: Headers\n params: {\n clientUploadContext?: unknown\n collection: string\n filename: string\n prefix?: string\n }\n },\n ) => Promise<Response> | Promise<void> | Response | void)[]\n /**\n * Set to `true` to prevent the admin UI from showing file inputs during document creation, useful for programmatic file generation.\n */\n hideFileInputOnCreate?: boolean\n /**\n * Set to `true` to prevent the admin UI having a way to remove an existing file while editing.\n */\n hideRemoveFile?: boolean\n imageSizes?: ImageSize[]\n /**\n * Restrict mimeTypes in the file picker. Array of valid mime types or mimetype wildcards\n * @example ['image/*', 'application/pdf']\n * @default undefined\n */\n mimeTypes?: string[]\n /**\n * Ability to modify the response headers fetching a file.\n * @default undefined\n */\n modifyResponseHeaders?: ({ headers }: { headers: Headers }) => Headers | void\n /**\n * Controls the behavior of pasting/uploading files from URLs.\n * If set to `false`, fetching from remote URLs is disabled.\n * If an `allowList` is provided, server-side fetching will be enabled for specified URLs.\n *\n * @default true (client-side fetching enabled)\n */\n pasteURL?:\n | {\n allowList: AllowList\n }\n | false\n /**\n * Sharp resize options for the original image.\n * @link https://sharp.pixelplumbing.com/api-resize#resize\n * @default undefined\n */\n resizeOptions?: ResizeOptions\n /**\n * Skip safe fetch when using server-side fetching for external files from these URLs.\n * @default false\n */\n skipSafeFetch?: AllowList | boolean\n /**\n * The directory to serve static files from. Defaults to collection slug.\n * @default undefined\n */\n staticDir?: string\n trimOptions?: ImageUploadTrimOptions\n /**\n * Optionally append metadata to the image during processing.\n *\n * Can be a boolean or a function.\n *\n * If true, metadata will be appended to the image.\n * If false, no metadata will be appended.\n * If a function, it will receive an object containing the metadata and should return a boolean indicating whether to append the metadata.\n * @default false\n */\n withMetadata?: WithMetadata\n}\nexport type checkFileRestrictionsParams = {\n collection: CollectionConfig\n file: File\n req: PayloadRequest\n}\n\nexport type SanitizedUploadConfig = {\n staticDir: UploadConfig['staticDir']\n} & UploadConfig\n\nexport type File = {\n /**\n * The buffer of the file.\n */\n data: Buffer\n /**\n * The mimetype of the file.\n */\n mimetype: string\n /**\n * The name of the file.\n */\n name: string\n /**\n * The size of the file in bytes.\n */\n size: number\n /**\n * Path to the temp file on disk when useTempFiles is enabled. In this case file.data will be an empty buffer.\n */\n tempFilePath?: string\n}\n\nexport type FileToSave =\n | {\n /**\n * The buffer of the file.\n */\n buffer: Buffer\n /**\n * The path to save the file.\n */\n path: string\n }\n | {\n /**\n * The path to save the file.\n */\n path: string\n /**\n * An existing file on disk to copy to `path`, instead of `buffer` - avoids loading a file\n * that's already on disk (e.g. a temp file) fully into memory just to write it back out.\n */\n sourcePath: string\n }\n\ntype Crop = {\n height: number\n unit: '%' | 'px'\n width: number\n x: number\n y: number\n}\n\nexport type FocalPoint = {\n x: number\n y: number\n}\n\nexport type UploadEdits = {\n crop?: Crop\n focalPoint?: FocalPoint\n heightInPixels?: number\n widthInPixels?: number\n}\n"],"names":[],"mappings":"AAiYA,WAKC"}
1
+ {"version":3,"sources":["../../src/uploads/types.ts"],"sourcesContent":["import type { ResizeOptions, Sharp, SharpOptions } from 'sharp'\n\nimport type { CollectionConfig, TypeWithID } from '../collections/config/types.js'\nimport type { PayloadComponent } from '../config/types.js'\nimport type { PayloadRequest } from '../types/index.js'\nimport type { WithMetadata } from './optionallyAppendMetadata.js'\n\nexport type FileSize = {\n filename: null | string\n filesize: null | number\n height: null | number\n mimeType: null | string\n url?: null | string // TODO V4: make non-optional\n width: null | number\n}\n\n// TODO: deprecate in Payload v4.\n/**\n * FileSizeImproved is a more precise type, and will replace FileSize in Payload v4.\n * This type is for internal use only as it will be deprecated in the future.\n * @internal\n */\nexport type FileSizeImproved = {\n url: null | string\n} & FileSize\n\nexport type FileSizes = {\n [size: string]: FileSize\n}\n\nexport type FileData = {\n filename: string\n filesize: number\n focalX?: number\n focalY?: number\n height: number\n mimeType: string\n sizes: FileSizes\n tempFilePath?: string\n url?: string\n width: number\n}\n\nexport type ProbedImageSize = {\n height: number\n width: number\n}\n\n/**\n * Params sent to the sharp `toFormat()` function\n * @link https://sharp.pixelplumbing.com/api-output#toformat\n */\nexport type ImageUploadFormatOptions = {\n format: Parameters<Sharp['toFormat']>[0]\n options?: Parameters<Sharp['toFormat']>[1]\n}\n\n/**\n * Params sent to the sharp trim() function\n * @link https://sharp.pixelplumbing.com/api-resize#trim\n */\nexport type ImageUploadTrimOptions = Parameters<Sharp['trim']>[0]\n\nexport type GenerateImageName = (args: {\n extension: string\n height: number\n originalName: string\n sizeName: string\n width: number\n}) => string\n\nexport type ImageSize = {\n /**\n * Admin UI options that control how this image size appears in list views.\n *\n * NOTE: In Payload v4, these options (`disableGroupBy`, `disableListColumn` and `disableListFilter`)\n * should default to `true` so image size subfields are hidden from list columns\n * and filters by default, reducing noise in the admin UI.\n */\n admin?: {\n /**\n * If set to true, this image size will not be available\n * as a selectable groupBy option in the collection list view.\n * @default false\n */\n disableGroupBy?: boolean\n /**\n * If set to true, this image size will not be available\n * as a selectable column in the collection list view.\n * @default false\n */\n disableListColumn?: boolean\n /**\n * If set to true, this image size will not be available\n * as a filter option in the collection list view.\n * @default false\n */\n disableListFilter?: boolean\n }\n /**\n * @deprecated prefer position\n */\n crop?: string // comes from sharp package\n formatOptions?: ImageUploadFormatOptions\n /**\n * Generate a custom name for the file of this image size.\n */\n generateImageName?: GenerateImageName\n name: string\n trimOptions?: ImageUploadTrimOptions\n /**\n * When an uploaded image is smaller than the defined image size, we have 3 options:\n *\n * `undefined | false | true`\n *\n * 1. `undefined` [default]: uploading images with smaller width AND height than the image size will return null\n * 2. `false`: always enlarge images to the image size\n * 3. `true`: if the image is smaller than the image size, return the original image\n */\n withoutEnlargement?: ResizeOptions['withoutEnlargement']\n} & Omit<ResizeOptions, 'withoutEnlargement'>\n\nexport type GetAdminThumbnail = (args: { doc: Record<string, unknown> }) => false | null | string\n\nexport type AllowList = Array<{\n hostname: string\n pathname?: string\n port?: string\n protocol?: 'http' | 'https'\n search?: string\n}>\n\nexport type FileAllowList = Array<{\n extensions: string[]\n mimeType: string\n}>\n\ntype Admin = {\n components?: {\n /**\n * The Controls component to extend the upload controls in the admin panel.\n */\n controls?: PayloadComponent[]\n }\n}\n\nexport type ExternalFileHeaderFilterContext = {\n isSameOrigin: boolean\n url: string\n}\n\nexport type UploadConfig = {\n /**\n * The adapter name to use for uploads. Used for storage adapter telemetry.\n * @default undefined\n */\n adapter?: string\n /**\n * The admin configuration for the upload field.\n */\n admin?: Admin\n /**\n * Represents an admin thumbnail, which can be either a React component or a string.\n * - If a string, it should be one of the image size names.\n * - A function that generates a fully qualified URL for the thumbnail, receives the doc as the only argument.\n **/\n adminThumbnail?: GetAdminThumbnail | string\n /**\n * Allow restricted file types known to be problematic.\n * - If set to `true`, it will allow all file types.\n * - If set to `false`, it will not allow file types and extensions known to be problematic.\n * - This setting is overriden by the `mimeTypes` option.\n * @default false\n */\n allowRestrictedFileTypes?: boolean\n /**\n * Enables bulk upload of files from the list view.\n * @default true\n */\n bulkUpload?: boolean\n /**\n * Appends a cache tag to the image URL when fetching the thumbnail in the admin panel. It may be desirable to disable this when hosting via CDNs with strict parameters.\n *\n * @default true\n */\n cacheTags?: boolean\n /**\n * Sharp constructor options to be passed to the uploaded file.\n * @link https://sharp.pixelplumbing.com/api-constructor/#sharp\n */\n constructorOptions?: SharpOptions\n /**\n * Enables cropping of images.\n * @default true\n */\n crop?: boolean\n /**\n * Disable the ability to save files to disk.\n * @default false\n */\n disableLocalStorage?: boolean\n /**\n * Enable displaying preview of the uploaded file in Upload fields related to this Collection.\n * Can be locally overridden by `displayPreview` option in Upload field.\n * @default false\n */\n displayPreview?: boolean\n /**\n * Accepts existing headers and returns the headers after filtering or modifying. The optional\n * context identifies the destination for the current request, including each redirect hop.\n * `isSameOrigin` is true only when that destination matches a trusted origin established for a\n * relative file URL.\n * If using this option, you should handle the removal of any sensitive cookies\n * (like payload-prefixed cookies) to prevent leaking session information to external\n * services. By default, Payload automatically filters out payload-prefixed cookies\n * when this option is NOT defined.\n *\n * Useful for adding custom headers to fetch from external providers.\n * @default undefined\n */\n externalFileHeaderFilter?: (\n headers: Record<string, string>,\n context?: ExternalFileHeaderFilterContext,\n ) => Record<string, string>\n /**\n * Field slugs to use for a compound index instead of the default filename index.\n */\n filenameCompoundIndex?: string[]\n /**\n * Require files to be uploaded when creating a document.\n * @default true\n */\n filesRequiredOnCreate?: boolean\n /**\n * Enables focal point positioning for image manipulation.\n * @default true\n */\n focalPoint?: boolean\n /**\n * Format options for the uploaded file. Formatting image sizes needs to be done within each formatOptions individually.\n */\n formatOptions?: ImageUploadFormatOptions\n /**\n * Custom handlers to run when a file is fetched.\n *\n * - If a handler returns a Response, the response will be sent to the client and no further handlers will be run.\n * - If a handler returns null, the next handler will be run.\n * - If no handlers return a response the file will be returned by default.\n *\n * @link https://sharp.pixelplumbing.com/api-output/#toformat\n * @default undefined\n */\n handlers?: ((\n req: PayloadRequest,\n args: {\n doc: TypeWithID\n headers?: Headers\n params: {\n clientUploadContext?: unknown\n collection: string\n filename: string\n prefix?: string\n }\n },\n ) => Promise<Response> | Promise<void> | Response | void)[]\n /**\n * Set to `true` to prevent the admin UI from showing file inputs during document creation, useful for programmatic file generation.\n */\n hideFileInputOnCreate?: boolean\n /**\n * Set to `true` to prevent the admin UI having a way to remove an existing file while editing.\n */\n hideRemoveFile?: boolean\n imageSizes?: ImageSize[]\n /**\n * Restrict mimeTypes in the file picker. Array of valid mime types or mimetype wildcards\n * @example ['image/*', 'application/pdf']\n * @default undefined\n */\n mimeTypes?: string[]\n /**\n * Ability to modify the response headers fetching a file.\n * @default undefined\n */\n modifyResponseHeaders?: ({ headers }: { headers: Headers }) => Headers | void\n /**\n * Controls the behavior of pasting/uploading files from URLs.\n * If set to `false`, fetching from remote URLs is disabled.\n * If an `allowList` is provided, server-side fetching will be enabled for specified URLs.\n *\n * @default true (client-side fetching enabled)\n */\n pasteURL?:\n | {\n allowList: AllowList\n }\n | false\n /** @internal Require a server-issued receipt before invoking client-upload handlers. */\n requiresClientUploadReceipt?: boolean\n /**\n * Sharp resize options for the original image.\n * @link https://sharp.pixelplumbing.com/api-resize#resize\n * @default undefined\n */\n resizeOptions?: ResizeOptions\n /**\n * Skip safe fetch when using server-side fetching for external files from these URLs.\n * @default false\n */\n skipSafeFetch?: AllowList | boolean\n /**\n * The directory to serve static files from. Defaults to collection slug.\n * @default undefined\n */\n staticDir?: string\n trimOptions?: ImageUploadTrimOptions\n /**\n * Optionally append metadata to the image during processing.\n *\n * Can be a boolean or a function.\n *\n * If true, metadata will be appended to the image.\n * If false, no metadata will be appended.\n * If a function, it will receive an object containing the metadata and should return a boolean indicating whether to append the metadata.\n * @default false\n */\n withMetadata?: WithMetadata\n}\nexport type checkFileRestrictionsParams = {\n collection: CollectionConfig\n file: File\n req: PayloadRequest\n}\n\nexport type SanitizedUploadConfig = {\n staticDir: UploadConfig['staticDir']\n} & UploadConfig\n\nexport type File = {\n /**\n * The buffer of the file.\n */\n data: Buffer\n /**\n * The mimetype of the file.\n */\n mimetype: string\n /**\n * The name of the file.\n */\n name: string\n /**\n * The size of the file in bytes.\n */\n size: number\n /**\n * Path to the temp file on disk when useTempFiles is enabled. In this case file.data will be an empty buffer.\n */\n tempFilePath?: string\n}\n\nexport type FileToSave =\n | {\n /**\n * The buffer of the file.\n */\n buffer: Buffer\n /**\n * The path to save the file.\n */\n path: string\n }\n | {\n /**\n * The path to save the file.\n */\n path: string\n /**\n * An existing file on disk to copy to `path`, instead of `buffer` - avoids loading a file\n * that's already on disk (e.g. a temp file) fully into memory just to write it back out.\n */\n sourcePath: string\n }\n\ntype Crop = {\n height: number\n unit: '%' | 'px'\n width: number\n x: number\n y: number\n}\n\nexport type FocalPoint = {\n x: number\n y: number\n}\n\nexport type UploadEdits = {\n crop?: Crop\n focalPoint?: FocalPoint\n heightInPixels?: number\n widthInPixels?: number\n}\n"],"names":[],"mappings":"AA6YA,WAKC"}
@@ -0,0 +1,20 @@
1
+ import type { PayloadRequest } from '../types/index.js';
2
+ type Args = {
3
+ /**
4
+ * A path the caller has already removed, so the redundant unlink is skipped.
5
+ */
6
+ alreadyUnlinkedPath?: string;
7
+ req: PayloadRequest;
8
+ };
9
+ /**
10
+ * Removes the temp file a client upload materialized, if it is still on disk. Logs rather than
11
+ * throws, so cleanup can never replace a response or mask the error that a caller is handling.
12
+ *
13
+ * The path is tracked on `req.context` rather than read back off `req.file` because the file
14
+ * can outlive both: plugin-cloud-storage's afterChange hook clears `req.file` before cleanup
15
+ * runs, and the request parser materializes the file for whatever `collectionSlug` the multipart
16
+ * field names, which does not have to be a collection the endpoint writes a document to.
17
+ */
18
+ export declare const unlinkClientUploadTempFile: (args: Args) => Promise<void>;
19
+ export {};
20
+ //# sourceMappingURL=unlinkClientUploadTempFile.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"unlinkClientUploadTempFile.d.ts","sourceRoot":"","sources":["../../src/uploads/unlinkClientUploadTempFile.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAA;AAIvD,KAAK,IAAI,GAAG;IACV;;OAEG;IACH,mBAAmB,CAAC,EAAE,MAAM,CAAA;IAC5B,GAAG,EAAE,cAAc,CAAA;CACpB,CAAA;AAED;;;;;;;;GAQG;AACH,eAAO,MAAM,0BAA0B,EAAE,CAAC,IAAI,EAAE,IAAI,KAAK,OAAO,CAAC,IAAI,CAqBpE,CAAA"}
@@ -0,0 +1,30 @@
1
+ import fs from 'fs/promises';
2
+ import { CLIENT_UPLOAD_TEMP_FILE_PATH_CONTEXT_KEY } from './getFileFromClientUpload.js';
3
+ /**
4
+ * Removes the temp file a client upload materialized, if it is still on disk. Logs rather than
5
+ * throws, so cleanup can never replace a response or mask the error that a caller is handling.
6
+ *
7
+ * The path is tracked on `req.context` rather than read back off `req.file` because the file
8
+ * can outlive both: plugin-cloud-storage's afterChange hook clears `req.file` before cleanup
9
+ * runs, and the request parser materializes the file for whatever `collectionSlug` the multipart
10
+ * field names, which does not have to be a collection the endpoint writes a document to.
11
+ */ export const unlinkClientUploadTempFile = async ({ alreadyUnlinkedPath, req })=>{
12
+ const tempFilePath = req.context?.[CLIENT_UPLOAD_TEMP_FILE_PATH_CONTEXT_KEY];
13
+ if (typeof tempFilePath !== 'string') {
14
+ return;
15
+ }
16
+ delete req.context[CLIENT_UPLOAD_TEMP_FILE_PATH_CONTEXT_KEY];
17
+ if (tempFilePath === alreadyUnlinkedPath) {
18
+ return;
19
+ }
20
+ try {
21
+ await fs.unlink(tempFilePath);
22
+ } catch (error) {
23
+ req.payload.logger.error({
24
+ err: error,
25
+ msg: 'Failed to remove client upload temp file'
26
+ });
27
+ }
28
+ };
29
+
30
+ //# sourceMappingURL=unlinkClientUploadTempFile.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/uploads/unlinkClientUploadTempFile.ts"],"sourcesContent":["import fs from 'fs/promises'\n\nimport type { PayloadRequest } from '../types/index.js'\n\nimport { CLIENT_UPLOAD_TEMP_FILE_PATH_CONTEXT_KEY } from './getFileFromClientUpload.js'\n\ntype Args = {\n /**\n * A path the caller has already removed, so the redundant unlink is skipped.\n */\n alreadyUnlinkedPath?: string\n req: PayloadRequest\n}\n\n/**\n * Removes the temp file a client upload materialized, if it is still on disk. Logs rather than\n * throws, so cleanup can never replace a response or mask the error that a caller is handling.\n *\n * The path is tracked on `req.context` rather than read back off `req.file` because the file\n * can outlive both: plugin-cloud-storage's afterChange hook clears `req.file` before cleanup\n * runs, and the request parser materializes the file for whatever `collectionSlug` the multipart\n * field names, which does not have to be a collection the endpoint writes a document to.\n */\nexport const unlinkClientUploadTempFile: (args: Args) => Promise<void> = async ({\n alreadyUnlinkedPath,\n req,\n}) => {\n const tempFilePath = req.context?.[CLIENT_UPLOAD_TEMP_FILE_PATH_CONTEXT_KEY]\n\n if (typeof tempFilePath !== 'string') {\n return\n }\n\n delete req.context[CLIENT_UPLOAD_TEMP_FILE_PATH_CONTEXT_KEY]\n\n if (tempFilePath === alreadyUnlinkedPath) {\n return\n }\n\n try {\n await fs.unlink(tempFilePath)\n } catch (error) {\n req.payload.logger.error({ err: error, msg: 'Failed to remove client upload temp file' })\n }\n}\n"],"names":["fs","CLIENT_UPLOAD_TEMP_FILE_PATH_CONTEXT_KEY","unlinkClientUploadTempFile","alreadyUnlinkedPath","req","tempFilePath","context","unlink","error","payload","logger","err","msg"],"mappings":"AAAA,OAAOA,QAAQ,cAAa;AAI5B,SAASC,wCAAwC,QAAQ,+BAA8B;AAUvF;;;;;;;;CAQC,GACD,OAAO,MAAMC,6BAA4D,OAAO,EAC9EC,mBAAmB,EACnBC,GAAG,EACJ;IACC,MAAMC,eAAeD,IAAIE,OAAO,EAAE,CAACL,yCAAyC;IAE5E,IAAI,OAAOI,iBAAiB,UAAU;QACpC;IACF;IAEA,OAAOD,IAAIE,OAAO,CAACL,yCAAyC;IAE5D,IAAII,iBAAiBF,qBAAqB;QACxC;IACF;IAEA,IAAI;QACF,MAAMH,GAAGO,MAAM,CAACF;IAClB,EAAE,OAAOG,OAAO;QACdJ,IAAIK,OAAO,CAACC,MAAM,CAACF,KAAK,CAAC;YAAEG,KAAKH;YAAOI,KAAK;QAA2C;IACzF;AACF,EAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"unlinkTempFiles.d.ts","sourceRoot":"","sources":["../../src/uploads/unlinkTempFiles.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,gCAAgC,CAAA;AAC/E,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAA;AACzD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAA;AAKvD,KAAK,IAAI,GAAG;IACV,gBAAgB,EAAE,yBAAyB,CAAA;IAC3C,MAAM,EAAE,eAAe,CAAA;IACvB,GAAG,EAAE,cAAc,CAAA;CACpB,CAAA;AACD;;GAEG;AACH,eAAO,MAAM,eAAe,EAAE,CAAC,IAAI,EAAE,IAAI,KAAK,OAAO,CAAC,IAAI,CAgCzD,CAAA"}
1
+ {"version":3,"file":"unlinkTempFiles.d.ts","sourceRoot":"","sources":["../../src/uploads/unlinkTempFiles.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,gCAAgC,CAAA;AAC/E,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAA;AACzD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAA;AAKvD,KAAK,IAAI,GAAG;IACV,gBAAgB,EAAE,yBAAyB,CAAA;IAC3C,MAAM,EAAE,eAAe,CAAA;IACvB,GAAG,EAAE,cAAc,CAAA;CACpB,CAAA;AACD;;GAEG;AACH,eAAO,MAAM,eAAe,EAAE,CAAC,IAAI,EAAE,IAAI,KAAK,OAAO,CAAC,IAAI,CAuBzD,CAAA"}
@@ -1,11 +1,12 @@
1
1
  import fs from 'fs/promises';
2
2
  import { mapAsync } from '../utilities/mapAsync.js';
3
- import { CLIENT_UPLOAD_TEMP_FILE_PATH_CONTEXT_KEY } from './getFileFromClientUpload.js';
3
+ import { unlinkClientUploadTempFile } from './unlinkClientUploadTempFile.js';
4
4
  /**
5
5
  * Cleanup temp files after operation lifecycle
6
6
  */ export const unlinkTempFiles = async ({ collectionConfig, config, req })=>{
7
7
  const { file } = req;
8
8
  const isClientUploadTempFile = Boolean(file?.tempFilePath && Object.prototype.hasOwnProperty.call(file, 'clientUploadContext'));
9
+ let unlinkedTempFilePath;
9
10
  if (collectionConfig.upload && (config.upload?.useTempFiles || isClientUploadTempFile)) {
10
11
  const fileArray = [
11
12
  {
@@ -16,17 +17,14 @@ import { CLIENT_UPLOAD_TEMP_FILE_PATH_CONTEXT_KEY } from './getFileFromClientUpl
16
17
  // Still need this check because this will not be populated if using local API
17
18
  if (file?.tempFilePath) {
18
19
  await fs.unlink(file.tempFilePath);
20
+ unlinkedTempFilePath = file.tempFilePath;
19
21
  }
20
22
  });
21
23
  }
22
- // plugin-cloud-storage's afterChange hook clears req.file after uploading generated image
23
- // sizes, before this cleanup runs, so the materializer's temp file is tracked separately and
24
- // may still need removing even though req.file no longer references it.
25
- const clientUploadTempFilePath = req.context?.[CLIENT_UPLOAD_TEMP_FILE_PATH_CONTEXT_KEY];
26
- if (typeof clientUploadTempFilePath === 'string' && clientUploadTempFilePath !== file?.tempFilePath) {
27
- delete req.context[CLIENT_UPLOAD_TEMP_FILE_PATH_CONTEXT_KEY];
28
- await fs.unlink(clientUploadTempFilePath);
29
- }
24
+ await unlinkClientUploadTempFile({
25
+ alreadyUnlinkedPath: unlinkedTempFilePath,
26
+ req
27
+ });
30
28
  };
31
29
 
32
30
  //# sourceMappingURL=unlinkTempFiles.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/uploads/unlinkTempFiles.ts"],"sourcesContent":["import fs from 'fs/promises'\n\nimport type { SanitizedCollectionConfig } from '../collections/config/types.js'\nimport type { SanitizedConfig } from '../config/types.js'\nimport type { PayloadRequest } from '../types/index.js'\n\nimport { mapAsync } from '../utilities/mapAsync.js'\nimport { CLIENT_UPLOAD_TEMP_FILE_PATH_CONTEXT_KEY } from './getFileFromClientUpload.js'\n\ntype Args = {\n collectionConfig: SanitizedCollectionConfig\n config: SanitizedConfig\n req: PayloadRequest\n}\n/**\n * Cleanup temp files after operation lifecycle\n */\nexport const unlinkTempFiles: (args: Args) => Promise<void> = async ({\n collectionConfig,\n config,\n req,\n}) => {\n const { file } = req\n const isClientUploadTempFile = Boolean(\n file?.tempFilePath && Object.prototype.hasOwnProperty.call(file, 'clientUploadContext'),\n )\n\n if (collectionConfig.upload && (config.upload?.useTempFiles || isClientUploadTempFile)) {\n const fileArray = [{ file }]\n await mapAsync(fileArray, async ({ file }) => {\n // Still need this check because this will not be populated if using local API\n if (file?.tempFilePath) {\n await fs.unlink(file.tempFilePath)\n }\n })\n }\n\n // plugin-cloud-storage's afterChange hook clears req.file after uploading generated image\n // sizes, before this cleanup runs, so the materializer's temp file is tracked separately and\n // may still need removing even though req.file no longer references it.\n const clientUploadTempFilePath = req.context?.[CLIENT_UPLOAD_TEMP_FILE_PATH_CONTEXT_KEY]\n\n if (\n typeof clientUploadTempFilePath === 'string' &&\n clientUploadTempFilePath !== file?.tempFilePath\n ) {\n delete req.context[CLIENT_UPLOAD_TEMP_FILE_PATH_CONTEXT_KEY]\n await fs.unlink(clientUploadTempFilePath)\n }\n}\n"],"names":["fs","mapAsync","CLIENT_UPLOAD_TEMP_FILE_PATH_CONTEXT_KEY","unlinkTempFiles","collectionConfig","config","req","file","isClientUploadTempFile","Boolean","tempFilePath","Object","prototype","hasOwnProperty","call","upload","useTempFiles","fileArray","unlink","clientUploadTempFilePath","context"],"mappings":"AAAA,OAAOA,QAAQ,cAAa;AAM5B,SAASC,QAAQ,QAAQ,2BAA0B;AACnD,SAASC,wCAAwC,QAAQ,+BAA8B;AAOvF;;CAEC,GACD,OAAO,MAAMC,kBAAiD,OAAO,EACnEC,gBAAgB,EAChBC,MAAM,EACNC,GAAG,EACJ;IACC,MAAM,EAAEC,IAAI,EAAE,GAAGD;IACjB,MAAME,yBAAyBC,QAC7BF,MAAMG,gBAAgBC,OAAOC,SAAS,CAACC,cAAc,CAACC,IAAI,CAACP,MAAM;IAGnE,IAAIH,iBAAiBW,MAAM,IAAKV,CAAAA,OAAOU,MAAM,EAAEC,gBAAgBR,sBAAqB,GAAI;QACtF,MAAMS,YAAY;YAAC;gBAAEV;YAAK;SAAE;QAC5B,MAAMN,SAASgB,WAAW,OAAO,EAAEV,IAAI,EAAE;YACvC,8EAA8E;YAC9E,IAAIA,MAAMG,cAAc;gBACtB,MAAMV,GAAGkB,MAAM,CAACX,KAAKG,YAAY;YACnC;QACF;IACF;IAEA,0FAA0F;IAC1F,6FAA6F;IAC7F,wEAAwE;IACxE,MAAMS,2BAA2Bb,IAAIc,OAAO,EAAE,CAAClB,yCAAyC;IAExF,IACE,OAAOiB,6BAA6B,YACpCA,6BAA6BZ,MAAMG,cACnC;QACA,OAAOJ,IAAIc,OAAO,CAAClB,yCAAyC;QAC5D,MAAMF,GAAGkB,MAAM,CAACC;IAClB;AACF,EAAC"}
1
+ {"version":3,"sources":["../../src/uploads/unlinkTempFiles.ts"],"sourcesContent":["import fs from 'fs/promises'\n\nimport type { SanitizedCollectionConfig } from '../collections/config/types.js'\nimport type { SanitizedConfig } from '../config/types.js'\nimport type { PayloadRequest } from '../types/index.js'\n\nimport { mapAsync } from '../utilities/mapAsync.js'\nimport { unlinkClientUploadTempFile } from './unlinkClientUploadTempFile.js'\n\ntype Args = {\n collectionConfig: SanitizedCollectionConfig\n config: SanitizedConfig\n req: PayloadRequest\n}\n/**\n * Cleanup temp files after operation lifecycle\n */\nexport const unlinkTempFiles: (args: Args) => Promise<void> = async ({\n collectionConfig,\n config,\n req,\n}) => {\n const { file } = req\n const isClientUploadTempFile = Boolean(\n file?.tempFilePath && Object.prototype.hasOwnProperty.call(file, 'clientUploadContext'),\n )\n let unlinkedTempFilePath: string | undefined\n\n if (collectionConfig.upload && (config.upload?.useTempFiles || isClientUploadTempFile)) {\n const fileArray = [{ file }]\n await mapAsync(fileArray, async ({ file }) => {\n // Still need this check because this will not be populated if using local API\n if (file?.tempFilePath) {\n await fs.unlink(file.tempFilePath)\n unlinkedTempFilePath = file.tempFilePath\n }\n })\n }\n\n await unlinkClientUploadTempFile({ alreadyUnlinkedPath: unlinkedTempFilePath, req })\n}\n"],"names":["fs","mapAsync","unlinkClientUploadTempFile","unlinkTempFiles","collectionConfig","config","req","file","isClientUploadTempFile","Boolean","tempFilePath","Object","prototype","hasOwnProperty","call","unlinkedTempFilePath","upload","useTempFiles","fileArray","unlink","alreadyUnlinkedPath"],"mappings":"AAAA,OAAOA,QAAQ,cAAa;AAM5B,SAASC,QAAQ,QAAQ,2BAA0B;AACnD,SAASC,0BAA0B,QAAQ,kCAAiC;AAO5E;;CAEC,GACD,OAAO,MAAMC,kBAAiD,OAAO,EACnEC,gBAAgB,EAChBC,MAAM,EACNC,GAAG,EACJ;IACC,MAAM,EAAEC,IAAI,EAAE,GAAGD;IACjB,MAAME,yBAAyBC,QAC7BF,MAAMG,gBAAgBC,OAAOC,SAAS,CAACC,cAAc,CAACC,IAAI,CAACP,MAAM;IAEnE,IAAIQ;IAEJ,IAAIX,iBAAiBY,MAAM,IAAKX,CAAAA,OAAOW,MAAM,EAAEC,gBAAgBT,sBAAqB,GAAI;QACtF,MAAMU,YAAY;YAAC;gBAAEX;YAAK;SAAE;QAC5B,MAAMN,SAASiB,WAAW,OAAO,EAAEX,IAAI,EAAE;YACvC,8EAA8E;YAC9E,IAAIA,MAAMG,cAAc;gBACtB,MAAMV,GAAGmB,MAAM,CAACZ,KAAKG,YAAY;gBACjCK,uBAAuBR,KAAKG,YAAY;YAC1C;QACF;IACF;IAEA,MAAMR,2BAA2B;QAAEkB,qBAAqBL;QAAsBT;IAAI;AACpF,EAAC"}
@@ -1,7 +1,7 @@
1
1
  import fs from 'fs/promises';
2
2
  import os from 'os';
3
3
  import path from 'path';
4
- import { afterEach, describe, expect, it } from 'vitest';
4
+ import { afterEach, describe, expect, it, vi } from 'vitest';
5
5
  import { CLIENT_UPLOAD_TEMP_FILE_PATH_CONTEXT_KEY } from './getFileFromClientUpload.js';
6
6
  import { unlinkTempFiles } from './unlinkTempFiles.js';
7
7
  const createTempFile = async (contents = 'temp-file-contents')=>{
@@ -22,6 +22,7 @@ const collectionConfig = {
22
22
  disableLocalStorage: true
23
23
  }
24
24
  };
25
+ const nonUploadCollectionConfig = {};
25
26
  describe('unlinkTempFiles', ()=>{
26
27
  const tempFilesToRemove = [];
27
28
  afterEach(async ()=>{
@@ -152,6 +153,65 @@ describe('unlinkTempFiles', ()=>{
152
153
  })).resolves.not.toThrow();
153
154
  expect(await fileExists(tempFilePath)).toBe(false);
154
155
  });
156
+ it('removes a client-upload temp file when the collection is not an upload collection', async ()=>{
157
+ const tempFilePath = await createTempFile();
158
+ tempFilesToRemove.push(tempFilePath);
159
+ // A forged `collectionSlug` in the multipart file field materializes a temp file for a
160
+ // collection that never accepts uploads, so nothing in the upload branch removes it.
161
+ const req = {
162
+ context: {
163
+ [CLIENT_UPLOAD_TEMP_FILE_PATH_CONTEXT_KEY]: tempFilePath
164
+ },
165
+ file: {
166
+ clientUploadContext: {
167
+ prefix: ''
168
+ },
169
+ data: Buffer.alloc(0),
170
+ mimetype: 'video/mp4',
171
+ name: 'clip.mp4',
172
+ size: 10,
173
+ tempFilePath
174
+ }
175
+ };
176
+ await unlinkTempFiles({
177
+ collectionConfig: nonUploadCollectionConfig,
178
+ config: {
179
+ upload: {
180
+ useTempFiles: false
181
+ }
182
+ },
183
+ req
184
+ });
185
+ expect(await fileExists(tempFilePath)).toBe(false);
186
+ expect(req.context[CLIENT_UPLOAD_TEMP_FILE_PATH_CONTEXT_KEY]).toBeUndefined();
187
+ });
188
+ it('logs instead of throwing when a client-upload temp file can no longer be removed', async ()=>{
189
+ const req = {
190
+ context: {
191
+ [CLIENT_UPLOAD_TEMP_FILE_PATH_CONTEXT_KEY]: path.join(os.tmpdir(), 'unlink-temp-files-spec-missing-file')
192
+ },
193
+ payload: {
194
+ logger: {
195
+ error: vi.fn()
196
+ }
197
+ }
198
+ };
199
+ await expect(unlinkTempFiles({
200
+ collectionConfig,
201
+ config: {
202
+ upload: {
203
+ useTempFiles: false
204
+ }
205
+ },
206
+ req
207
+ })).resolves.toBeUndefined();
208
+ expect(req.payload.logger.error).toHaveBeenCalledWith({
209
+ err: expect.objectContaining({
210
+ code: 'ENOENT'
211
+ }),
212
+ msg: 'Failed to remove client upload temp file'
213
+ });
214
+ });
155
215
  });
156
216
 
157
217
  //# sourceMappingURL=unlinkTempFiles.spec.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/uploads/unlinkTempFiles.spec.ts"],"sourcesContent":["import type { SanitizedCollectionConfig } from '../collections/config/types.js'\nimport type { SanitizedConfig } from '../config/types.js'\nimport type { PayloadRequest } from '../types/index.js'\n\nimport fs from 'fs/promises'\nimport os from 'os'\nimport path from 'path'\nimport { afterEach, describe, expect, it } from 'vitest'\n\nimport { CLIENT_UPLOAD_TEMP_FILE_PATH_CONTEXT_KEY } from './getFileFromClientUpload.js'\nimport { unlinkTempFiles } from './unlinkTempFiles.js'\n\nconst createTempFile = async (contents = 'temp-file-contents'): Promise<string> => {\n const tempFilePath = path.join(\n os.tmpdir(),\n `unlink-temp-files-spec-${Date.now()}-${Math.random()}`,\n )\n await fs.writeFile(tempFilePath, contents)\n return tempFilePath\n}\n\nconst fileExists = async (filePath: string): Promise<boolean> => {\n try {\n await fs.access(filePath)\n return true\n } catch {\n return false\n }\n}\n\nconst collectionConfig = {\n upload: { disableLocalStorage: true },\n} as unknown as SanitizedCollectionConfig\n\ndescribe('unlinkTempFiles', () => {\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('removes a client-upload materialized temp file even when useTempFiles is false', async () => {\n const tempFilePath = await createTempFile()\n tempFilesToRemove.push(tempFilePath)\n\n const req = {\n file: {\n clientUploadContext: undefined,\n data: Buffer.alloc(0),\n mimetype: 'video/mp4',\n name: 'clip.mp4',\n size: 10,\n tempFilePath,\n },\n } as unknown as PayloadRequest\n\n await unlinkTempFiles({\n collectionConfig,\n config: { upload: { useTempFiles: false } } as unknown as SanitizedConfig,\n req,\n })\n\n expect(await fileExists(tempFilePath)).toBe(false)\n })\n\n it('leaves a local-API temp file alone when useTempFiles is false', async () => {\n const tempFilePath = await createTempFile()\n tempFilesToRemove.push(tempFilePath)\n\n const req = {\n file: {\n data: Buffer.alloc(0),\n mimetype: 'video/mp4',\n name: 'clip.mp4',\n size: 10,\n tempFilePath,\n },\n } as unknown as PayloadRequest\n\n await unlinkTempFiles({\n collectionConfig,\n config: { upload: { useTempFiles: false } } as unknown as SanitizedConfig,\n req,\n })\n\n expect(await fileExists(tempFilePath)).toBe(true)\n })\n\n it('removes a multipart temp file when useTempFiles is true', async () => {\n const tempFilePath = await createTempFile()\n tempFilesToRemove.push(tempFilePath)\n\n const req = {\n file: {\n data: Buffer.alloc(0),\n mimetype: 'video/mp4',\n name: 'clip.mp4',\n size: 10,\n tempFilePath,\n },\n } as unknown as PayloadRequest\n\n await unlinkTempFiles({\n collectionConfig,\n config: { upload: { useTempFiles: true } } as unknown as SanitizedConfig,\n req,\n })\n\n expect(await fileExists(tempFilePath)).toBe(false)\n })\n\n it('removes a client-upload temp file tracked on req.context after req.file was cleared', async () => {\n const tempFilePath = await createTempFile()\n tempFilesToRemove.push(tempFilePath)\n\n // Mirrors plugin-cloud-storage's afterChange hook, which clears req.file after uploading\n // generated image sizes but leaves req.context untouched.\n const req = {\n context: { [CLIENT_UPLOAD_TEMP_FILE_PATH_CONTEXT_KEY]: tempFilePath },\n file: undefined,\n } as unknown as PayloadRequest\n\n await unlinkTempFiles({\n collectionConfig,\n config: { upload: { useTempFiles: false } } as unknown as SanitizedConfig,\n req,\n })\n\n expect(await fileExists(tempFilePath)).toBe(false)\n expect(req.context[CLIENT_UPLOAD_TEMP_FILE_PATH_CONTEXT_KEY]).toBeUndefined()\n })\n\n it('does not attempt a second unlink when the context-tracked path matches req.file.tempFilePath', async () => {\n const tempFilePath = await createTempFile()\n tempFilesToRemove.push(tempFilePath)\n\n const req = {\n context: { [CLIENT_UPLOAD_TEMP_FILE_PATH_CONTEXT_KEY]: tempFilePath },\n file: {\n clientUploadContext: undefined,\n data: Buffer.alloc(0),\n mimetype: 'video/mp4',\n name: 'clip.mp4',\n size: 10,\n tempFilePath,\n },\n } as unknown as PayloadRequest\n\n await expect(\n unlinkTempFiles({\n collectionConfig,\n config: { upload: { useTempFiles: false } } as unknown as SanitizedConfig,\n req,\n }),\n ).resolves.not.toThrow()\n\n expect(await fileExists(tempFilePath)).toBe(false)\n })\n})\n"],"names":["fs","os","path","afterEach","describe","expect","it","CLIENT_UPLOAD_TEMP_FILE_PATH_CONTEXT_KEY","unlinkTempFiles","createTempFile","contents","tempFilePath","join","tmpdir","Date","now","Math","random","writeFile","fileExists","filePath","access","collectionConfig","upload","disableLocalStorage","tempFilesToRemove","rm","force","length","push","req","file","clientUploadContext","undefined","data","Buffer","alloc","mimetype","name","size","config","useTempFiles","toBe","context","toBeUndefined","resolves","not","toThrow"],"mappings":"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"}
1
+ {"version":3,"sources":["../../src/uploads/unlinkTempFiles.spec.ts"],"sourcesContent":["import type { SanitizedCollectionConfig } from '../collections/config/types.js'\nimport type { SanitizedConfig } from '../config/types.js'\nimport type { PayloadRequest } from '../types/index.js'\n\nimport fs from 'fs/promises'\nimport os from 'os'\nimport path from 'path'\nimport { afterEach, describe, expect, it, vi } from 'vitest'\n\nimport { CLIENT_UPLOAD_TEMP_FILE_PATH_CONTEXT_KEY } from './getFileFromClientUpload.js'\nimport { unlinkTempFiles } from './unlinkTempFiles.js'\n\nconst createTempFile = async (contents = 'temp-file-contents'): Promise<string> => {\n const tempFilePath = path.join(\n os.tmpdir(),\n `unlink-temp-files-spec-${Date.now()}-${Math.random()}`,\n )\n await fs.writeFile(tempFilePath, contents)\n return tempFilePath\n}\n\nconst fileExists = async (filePath: string): Promise<boolean> => {\n try {\n await fs.access(filePath)\n return true\n } catch {\n return false\n }\n}\n\nconst collectionConfig = {\n upload: { disableLocalStorage: true },\n} as unknown as SanitizedCollectionConfig\n\nconst nonUploadCollectionConfig = {} as unknown as SanitizedCollectionConfig\n\ndescribe('unlinkTempFiles', () => {\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('removes a client-upload materialized temp file even when useTempFiles is false', async () => {\n const tempFilePath = await createTempFile()\n tempFilesToRemove.push(tempFilePath)\n\n const req = {\n file: {\n clientUploadContext: undefined,\n data: Buffer.alloc(0),\n mimetype: 'video/mp4',\n name: 'clip.mp4',\n size: 10,\n tempFilePath,\n },\n } as unknown as PayloadRequest\n\n await unlinkTempFiles({\n collectionConfig,\n config: { upload: { useTempFiles: false } } as unknown as SanitizedConfig,\n req,\n })\n\n expect(await fileExists(tempFilePath)).toBe(false)\n })\n\n it('leaves a local-API temp file alone when useTempFiles is false', async () => {\n const tempFilePath = await createTempFile()\n tempFilesToRemove.push(tempFilePath)\n\n const req = {\n file: {\n data: Buffer.alloc(0),\n mimetype: 'video/mp4',\n name: 'clip.mp4',\n size: 10,\n tempFilePath,\n },\n } as unknown as PayloadRequest\n\n await unlinkTempFiles({\n collectionConfig,\n config: { upload: { useTempFiles: false } } as unknown as SanitizedConfig,\n req,\n })\n\n expect(await fileExists(tempFilePath)).toBe(true)\n })\n\n it('removes a multipart temp file when useTempFiles is true', async () => {\n const tempFilePath = await createTempFile()\n tempFilesToRemove.push(tempFilePath)\n\n const req = {\n file: {\n data: Buffer.alloc(0),\n mimetype: 'video/mp4',\n name: 'clip.mp4',\n size: 10,\n tempFilePath,\n },\n } as unknown as PayloadRequest\n\n await unlinkTempFiles({\n collectionConfig,\n config: { upload: { useTempFiles: true } } as unknown as SanitizedConfig,\n req,\n })\n\n expect(await fileExists(tempFilePath)).toBe(false)\n })\n\n it('removes a client-upload temp file tracked on req.context after req.file was cleared', async () => {\n const tempFilePath = await createTempFile()\n tempFilesToRemove.push(tempFilePath)\n\n // Mirrors plugin-cloud-storage's afterChange hook, which clears req.file after uploading\n // generated image sizes but leaves req.context untouched.\n const req = {\n context: { [CLIENT_UPLOAD_TEMP_FILE_PATH_CONTEXT_KEY]: tempFilePath },\n file: undefined,\n } as unknown as PayloadRequest\n\n await unlinkTempFiles({\n collectionConfig,\n config: { upload: { useTempFiles: false } } as unknown as SanitizedConfig,\n req,\n })\n\n expect(await fileExists(tempFilePath)).toBe(false)\n expect(req.context[CLIENT_UPLOAD_TEMP_FILE_PATH_CONTEXT_KEY]).toBeUndefined()\n })\n\n it('does not attempt a second unlink when the context-tracked path matches req.file.tempFilePath', async () => {\n const tempFilePath = await createTempFile()\n tempFilesToRemove.push(tempFilePath)\n\n const req = {\n context: { [CLIENT_UPLOAD_TEMP_FILE_PATH_CONTEXT_KEY]: tempFilePath },\n file: {\n clientUploadContext: undefined,\n data: Buffer.alloc(0),\n mimetype: 'video/mp4',\n name: 'clip.mp4',\n size: 10,\n tempFilePath,\n },\n } as unknown as PayloadRequest\n\n await expect(\n unlinkTempFiles({\n collectionConfig,\n config: { upload: { useTempFiles: false } } as unknown as SanitizedConfig,\n req,\n }),\n ).resolves.not.toThrow()\n\n expect(await fileExists(tempFilePath)).toBe(false)\n })\n\n it('removes a client-upload temp file when the collection is not an upload collection', async () => {\n const tempFilePath = await createTempFile()\n tempFilesToRemove.push(tempFilePath)\n\n // A forged `collectionSlug` in the multipart file field materializes a temp file for a\n // collection that never accepts uploads, so nothing in the upload branch removes it.\n const req = {\n context: { [CLIENT_UPLOAD_TEMP_FILE_PATH_CONTEXT_KEY]: tempFilePath },\n file: {\n clientUploadContext: { prefix: '' },\n data: Buffer.alloc(0),\n mimetype: 'video/mp4',\n name: 'clip.mp4',\n size: 10,\n tempFilePath,\n },\n } as unknown as PayloadRequest\n\n await unlinkTempFiles({\n collectionConfig: nonUploadCollectionConfig,\n config: { upload: { useTempFiles: false } } as unknown as SanitizedConfig,\n req,\n })\n\n expect(await fileExists(tempFilePath)).toBe(false)\n expect(req.context[CLIENT_UPLOAD_TEMP_FILE_PATH_CONTEXT_KEY]).toBeUndefined()\n })\n\n it('logs instead of throwing when a client-upload temp file can no longer be removed', async () => {\n const req = {\n context: {\n [CLIENT_UPLOAD_TEMP_FILE_PATH_CONTEXT_KEY]: path.join(\n os.tmpdir(),\n 'unlink-temp-files-spec-missing-file',\n ),\n },\n payload: { logger: { error: vi.fn() } },\n } as unknown as PayloadRequest\n\n await expect(\n unlinkTempFiles({\n collectionConfig,\n config: { upload: { useTempFiles: false } } as unknown as SanitizedConfig,\n req,\n }),\n ).resolves.toBeUndefined()\n\n expect(req.payload.logger.error).toHaveBeenCalledWith({\n err: expect.objectContaining({ code: 'ENOENT' }),\n msg: 'Failed to remove client upload temp file',\n })\n })\n})\n"],"names":["fs","os","path","afterEach","describe","expect","it","vi","CLIENT_UPLOAD_TEMP_FILE_PATH_CONTEXT_KEY","unlinkTempFiles","createTempFile","contents","tempFilePath","join","tmpdir","Date","now","Math","random","writeFile","fileExists","filePath","access","collectionConfig","upload","disableLocalStorage","nonUploadCollectionConfig","tempFilesToRemove","rm","force","length","push","req","file","clientUploadContext","undefined","data","Buffer","alloc","mimetype","name","size","config","useTempFiles","toBe","context","toBeUndefined","resolves","not","toThrow","prefix","payload","logger","error","fn","toHaveBeenCalledWith","err","objectContaining","code","msg"],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export declare const UPLOAD_CONTENT_SECURITY_POLICY = "script-src 'none'; frame-src 'none'; object-src 'none'";
2
+ //# sourceMappingURL=uploadContentSecurityPolicy.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"uploadContentSecurityPolicy.d.ts","sourceRoot":"","sources":["../../src/uploads/uploadContentSecurityPolicy.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,8BAA8B,2DACe,CAAA"}
@@ -0,0 +1,3 @@
1
+ export const UPLOAD_CONTENT_SECURITY_POLICY = "script-src 'none'; frame-src 'none'; object-src 'none'";
2
+
3
+ //# sourceMappingURL=uploadContentSecurityPolicy.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/uploads/uploadContentSecurityPolicy.ts"],"sourcesContent":["export const UPLOAD_CONTENT_SECURITY_POLICY =\n \"script-src 'none'; frame-src 'none'; object-src 'none'\"\n"],"names":["UPLOAD_CONTENT_SECURITY_POLICY"],"mappings":"AAAA,OAAO,MAAMA,iCACX,yDAAwD"}
@@ -0,0 +1,4 @@
1
+ export declare const isISOBaseMediaMimeType: (mimeType: string) => boolean;
2
+ export declare const validateISOBaseMediaBuffer: (buffer: Buffer) => Promise<boolean>;
3
+ export declare const validateISOBaseMediaFile: (filePath: string) => Promise<boolean>;
4
+ //# sourceMappingURL=validateISOBaseMediaFile.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validateISOBaseMediaFile.d.ts","sourceRoot":"","sources":["../../src/uploads/validateISOBaseMediaFile.ts"],"names":[],"mappings":"AAuBA,eAAO,MAAM,sBAAsB,aAAc,MAAM,KAAG,OACjB,CAAA;AA8DzC,eAAO,MAAM,0BAA0B,WAAkB,MAAM,KAAG,OAAO,CAAC,OAAO,CAG9E,CAAA;AAEH,eAAO,MAAM,wBAAwB,aAAoB,MAAM,KAAG,OAAO,CAAC,OAAO,CAiBhF,CAAA"}
@@ -0,0 +1,91 @@
1
+ import fs from 'fs/promises';
2
+ const MAX_BOX_COUNT = 10_000;
3
+ const QUICKTIME_FIRST_BOX_TYPES = new Set([
4
+ 'free',
5
+ 'mdat',
6
+ 'moov',
7
+ 'wide'
8
+ ]);
9
+ const ISO_BASE_MEDIA_MIME_TYPES = new Set([
10
+ 'audio/mp4',
11
+ 'audio/x-m4a',
12
+ 'image/avif',
13
+ 'image/heic',
14
+ 'image/heic-sequence',
15
+ 'image/heif',
16
+ 'image/heif-sequence',
17
+ 'image/x-canon-cr3',
18
+ 'video/3gpp',
19
+ 'video/3gpp2',
20
+ 'video/mp4',
21
+ 'video/quicktime',
22
+ 'video/x-m4v'
23
+ ]);
24
+ export const isISOBaseMediaMimeType = (mimeType)=>ISO_BASE_MEDIA_MIME_TYPES.has(mimeType);
25
+ const validateBoxStructure = async (size, readAt)=>{
26
+ if (!Number.isSafeInteger(size) || size < 24) {
27
+ return false;
28
+ }
29
+ let boxCount = 0;
30
+ let position = 0;
31
+ while(position < size){
32
+ if (++boxCount > MAX_BOX_COUNT || size - position < 8) {
33
+ return false;
34
+ }
35
+ const header = await readAt(position, Math.min(16, size - position));
36
+ if (header.length < 8) {
37
+ return false;
38
+ }
39
+ const boxType = header.toString('latin1', 4, 8);
40
+ const size32 = header.readUInt32BE(0);
41
+ let boxSize;
42
+ let headerSize = 8;
43
+ if (size32 === 0) {
44
+ boxSize = size - position;
45
+ } else if (size32 === 1) {
46
+ if (header.length < 16) {
47
+ return false;
48
+ }
49
+ const size64 = header.readBigUInt64BE(8);
50
+ if (size64 > BigInt(Number.MAX_SAFE_INTEGER)) {
51
+ return false;
52
+ }
53
+ boxSize = Number(size64);
54
+ headerSize = 16;
55
+ } else {
56
+ boxSize = size32;
57
+ }
58
+ if (boxSize < headerSize || boxSize > size - position) {
59
+ return false;
60
+ }
61
+ if (position === 0 && boxType === 'ftyp') {
62
+ const payloadSize = boxSize - headerSize;
63
+ if (size32 === 0 || payloadSize < 8 || (payloadSize - 8) % 4 !== 0 || boxSize === size) {
64
+ return false;
65
+ }
66
+ } else if (position === 0 && !QUICKTIME_FIRST_BOX_TYPES.has(boxType)) {
67
+ return false;
68
+ }
69
+ position += boxSize;
70
+ }
71
+ return position === size;
72
+ };
73
+ export const validateISOBaseMediaBuffer = async (buffer)=>validateBoxStructure(buffer.length, (position, length)=>Promise.resolve(buffer.subarray(position, position + length)));
74
+ export const validateISOBaseMediaFile = async (filePath)=>{
75
+ let fileHandle;
76
+ try {
77
+ fileHandle = await fs.open(filePath, 'r');
78
+ const { size } = await fileHandle.stat();
79
+ return await validateBoxStructure(size, async (position, length)=>{
80
+ const buffer = Buffer.allocUnsafe(length);
81
+ const { bytesRead } = await fileHandle.read(buffer, 0, length, position);
82
+ return buffer.subarray(0, bytesRead);
83
+ });
84
+ } catch {
85
+ return false;
86
+ } finally{
87
+ await fileHandle?.close();
88
+ }
89
+ };
90
+
91
+ //# sourceMappingURL=validateISOBaseMediaFile.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/uploads/validateISOBaseMediaFile.ts"],"sourcesContent":["import fs from 'fs/promises'\n\nconst MAX_BOX_COUNT = 10_000\nconst QUICKTIME_FIRST_BOX_TYPES = new Set(['free', 'mdat', 'moov', 'wide'])\n\nconst ISO_BASE_MEDIA_MIME_TYPES = new Set([\n 'audio/mp4',\n 'audio/x-m4a',\n 'image/avif',\n 'image/heic',\n 'image/heic-sequence',\n 'image/heif',\n 'image/heif-sequence',\n 'image/x-canon-cr3',\n 'video/3gpp',\n 'video/3gpp2',\n 'video/mp4',\n 'video/quicktime',\n 'video/x-m4v',\n])\n\ntype ReadAt = (position: number, length: number) => Promise<Buffer>\n\nexport const isISOBaseMediaMimeType = (mimeType: string): boolean =>\n ISO_BASE_MEDIA_MIME_TYPES.has(mimeType)\n\nconst validateBoxStructure = async (size: number, readAt: ReadAt): Promise<boolean> => {\n if (!Number.isSafeInteger(size) || size < 24) {\n return false\n }\n\n let boxCount = 0\n let position = 0\n\n while (position < size) {\n if (++boxCount > MAX_BOX_COUNT || size - position < 8) {\n return false\n }\n\n const header = await readAt(position, Math.min(16, size - position))\n if (header.length < 8) {\n return false\n }\n\n const boxType = header.toString('latin1', 4, 8)\n const size32 = header.readUInt32BE(0)\n let boxSize: number\n let headerSize = 8\n\n if (size32 === 0) {\n boxSize = size - position\n } else if (size32 === 1) {\n if (header.length < 16) {\n return false\n }\n\n const size64 = header.readBigUInt64BE(8)\n if (size64 > BigInt(Number.MAX_SAFE_INTEGER)) {\n return false\n }\n\n boxSize = Number(size64)\n headerSize = 16\n } else {\n boxSize = size32\n }\n\n if (boxSize < headerSize || boxSize > size - position) {\n return false\n }\n\n if (position === 0 && boxType === 'ftyp') {\n const payloadSize = boxSize - headerSize\n if (size32 === 0 || payloadSize < 8 || (payloadSize - 8) % 4 !== 0 || boxSize === size) {\n return false\n }\n } else if (position === 0 && !QUICKTIME_FIRST_BOX_TYPES.has(boxType)) {\n return false\n }\n\n position += boxSize\n }\n\n return position === size\n}\n\nexport const validateISOBaseMediaBuffer = async (buffer: Buffer): Promise<boolean> =>\n validateBoxStructure(buffer.length, (position, length) =>\n Promise.resolve(buffer.subarray(position, position + length)),\n )\n\nexport const validateISOBaseMediaFile = async (filePath: string): Promise<boolean> => {\n let fileHandle: Awaited<ReturnType<typeof fs.open>> | undefined\n\n try {\n fileHandle = await fs.open(filePath, 'r')\n const { size } = await fileHandle.stat()\n\n return await validateBoxStructure(size, async (position, length) => {\n const buffer = Buffer.allocUnsafe(length)\n const { bytesRead } = await fileHandle!.read(buffer, 0, length, position)\n return buffer.subarray(0, bytesRead)\n })\n } catch {\n return false\n } finally {\n await fileHandle?.close()\n }\n}\n"],"names":["fs","MAX_BOX_COUNT","QUICKTIME_FIRST_BOX_TYPES","Set","ISO_BASE_MEDIA_MIME_TYPES","isISOBaseMediaMimeType","mimeType","has","validateBoxStructure","size","readAt","Number","isSafeInteger","boxCount","position","header","Math","min","length","boxType","toString","size32","readUInt32BE","boxSize","headerSize","size64","readBigUInt64BE","BigInt","MAX_SAFE_INTEGER","payloadSize","validateISOBaseMediaBuffer","buffer","Promise","resolve","subarray","validateISOBaseMediaFile","filePath","fileHandle","open","stat","Buffer","allocUnsafe","bytesRead","read","close"],"mappings":"AAAA,OAAOA,QAAQ,cAAa;AAE5B,MAAMC,gBAAgB;AACtB,MAAMC,4BAA4B,IAAIC,IAAI;IAAC;IAAQ;IAAQ;IAAQ;CAAO;AAE1E,MAAMC,4BAA4B,IAAID,IAAI;IACxC;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;CACD;AAID,OAAO,MAAME,yBAAyB,CAACC,WACrCF,0BAA0BG,GAAG,CAACD,UAAS;AAEzC,MAAME,uBAAuB,OAAOC,MAAcC;IAChD,IAAI,CAACC,OAAOC,aAAa,CAACH,SAASA,OAAO,IAAI;QAC5C,OAAO;IACT;IAEA,IAAII,WAAW;IACf,IAAIC,WAAW;IAEf,MAAOA,WAAWL,KAAM;QACtB,IAAI,EAAEI,WAAWZ,iBAAiBQ,OAAOK,WAAW,GAAG;YACrD,OAAO;QACT;QAEA,MAAMC,SAAS,MAAML,OAAOI,UAAUE,KAAKC,GAAG,CAAC,IAAIR,OAAOK;QAC1D,IAAIC,OAAOG,MAAM,GAAG,GAAG;YACrB,OAAO;QACT;QAEA,MAAMC,UAAUJ,OAAOK,QAAQ,CAAC,UAAU,GAAG;QAC7C,MAAMC,SAASN,OAAOO,YAAY,CAAC;QACnC,IAAIC;QACJ,IAAIC,aAAa;QAEjB,IAAIH,WAAW,GAAG;YAChBE,UAAUd,OAAOK;QACnB,OAAO,IAAIO,WAAW,GAAG;YACvB,IAAIN,OAAOG,MAAM,GAAG,IAAI;gBACtB,OAAO;YACT;YAEA,MAAMO,SAASV,OAAOW,eAAe,CAAC;YACtC,IAAID,SAASE,OAAOhB,OAAOiB,gBAAgB,GAAG;gBAC5C,OAAO;YACT;YAEAL,UAAUZ,OAAOc;YACjBD,aAAa;QACf,OAAO;YACLD,UAAUF;QACZ;QAEA,IAAIE,UAAUC,cAAcD,UAAUd,OAAOK,UAAU;YACrD,OAAO;QACT;QAEA,IAAIA,aAAa,KAAKK,YAAY,QAAQ;YACxC,MAAMU,cAAcN,UAAUC;YAC9B,IAAIH,WAAW,KAAKQ,cAAc,KAAK,AAACA,CAAAA,cAAc,CAAA,IAAK,MAAM,KAAKN,YAAYd,MAAM;gBACtF,OAAO;YACT;QACF,OAAO,IAAIK,aAAa,KAAK,CAACZ,0BAA0BK,GAAG,CAACY,UAAU;YACpE,OAAO;QACT;QAEAL,YAAYS;IACd;IAEA,OAAOT,aAAaL;AACtB;AAEA,OAAO,MAAMqB,6BAA6B,OAAOC,SAC/CvB,qBAAqBuB,OAAOb,MAAM,EAAE,CAACJ,UAAUI,SAC7Cc,QAAQC,OAAO,CAACF,OAAOG,QAAQ,CAACpB,UAAUA,WAAWI,UACtD;AAEH,OAAO,MAAMiB,2BAA2B,OAAOC;IAC7C,IAAIC;IAEJ,IAAI;QACFA,aAAa,MAAMrC,GAAGsC,IAAI,CAACF,UAAU;QACrC,MAAM,EAAE3B,IAAI,EAAE,GAAG,MAAM4B,WAAWE,IAAI;QAEtC,OAAO,MAAM/B,qBAAqBC,MAAM,OAAOK,UAAUI;YACvD,MAAMa,SAASS,OAAOC,WAAW,CAACvB;YAClC,MAAM,EAAEwB,SAAS,EAAE,GAAG,MAAML,WAAYM,IAAI,CAACZ,QAAQ,GAAGb,QAAQJ;YAChE,OAAOiB,OAAOG,QAAQ,CAAC,GAAGQ;QAC5B;IACF,EAAE,OAAM;QACN,OAAO;IACT,SAAU;QACR,MAAML,YAAYO;IACpB;AACF,EAAC"}