payload 4.0.0-internal.ea6e8f8 → 4.0.0-internal.ee5d8bd

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 (703) hide show
  1. package/dist/admin/adapters/router.d.ts +1 -1
  2. package/dist/admin/adapters/router.d.ts.map +1 -1
  3. package/dist/admin/adapters/router.js.map +1 -1
  4. package/dist/admin/forms/Diff.d.ts +0 -4
  5. package/dist/admin/forms/Diff.d.ts.map +1 -1
  6. package/dist/admin/forms/Diff.js.map +1 -1
  7. package/dist/admin/forms/Form.d.ts +0 -2
  8. package/dist/admin/forms/Form.d.ts.map +1 -1
  9. package/dist/admin/forms/Form.js.map +1 -1
  10. package/dist/admin/initAdminContext.d.ts.map +1 -1
  11. package/dist/admin/initAdminContext.js +0 -10
  12. package/dist/admin/initAdminContext.js.map +1 -1
  13. package/dist/auth/createAuthToken.d.ts +26 -0
  14. package/dist/auth/createAuthToken.d.ts.map +1 -0
  15. package/dist/auth/createAuthToken.js +39 -0
  16. package/dist/auth/createAuthToken.js.map +1 -0
  17. package/dist/auth/endpoints/refresh.d.ts.map +1 -1
  18. package/dist/auth/endpoints/refresh.js +2 -1
  19. package/dist/auth/endpoints/refresh.js.map +1 -1
  20. package/dist/auth/getFieldsToSign.js.map +1 -1
  21. package/dist/auth/loginWithCookie.d.ts.map +1 -1
  22. package/dist/auth/loginWithCookie.js +1 -0
  23. package/dist/auth/loginWithCookie.js.map +1 -1
  24. package/dist/auth/operations/local/login.d.ts.map +1 -1
  25. package/dist/auth/operations/local/login.js +1 -0
  26. package/dist/auth/operations/local/login.js.map +1 -1
  27. package/dist/auth/operations/login.d.ts +2 -0
  28. package/dist/auth/operations/login.d.ts.map +1 -1
  29. package/dist/auth/operations/login.js +6 -19
  30. package/dist/auth/operations/login.js.map +1 -1
  31. package/dist/auth/operations/refresh.d.ts +8 -0
  32. package/dist/auth/operations/refresh.d.ts.map +1 -1
  33. package/dist/auth/operations/refresh.js +50 -19
  34. package/dist/auth/operations/refresh.js.map +1 -1
  35. package/dist/auth/operations/resetPassword.d.ts.map +1 -1
  36. package/dist/auth/operations/resetPassword.js +54 -20
  37. package/dist/auth/operations/resetPassword.js.map +1 -1
  38. package/dist/auth/refreshAuthToken.d.ts +32 -0
  39. package/dist/auth/refreshAuthToken.d.ts.map +1 -0
  40. package/dist/auth/refreshAuthToken.js +113 -0
  41. package/dist/auth/refreshAuthToken.js.map +1 -0
  42. package/dist/auth/serverFunctions/cookies.js.map +1 -1
  43. package/dist/auth/serverFunctions/login.js.map +1 -1
  44. package/dist/auth/sessions.d.ts +9 -2
  45. package/dist/auth/sessions.d.ts.map +1 -1
  46. package/dist/auth/sessions.js +6 -5
  47. package/dist/auth/sessions.js.map +1 -1
  48. package/dist/auth/types.d.ts +25 -1
  49. package/dist/auth/types.d.ts.map +1 -1
  50. package/dist/auth/types.js.map +1 -1
  51. package/dist/cli/commands/data/utilities.d.ts +1 -1
  52. package/dist/cli/commands/data/utilities.d.ts.map +1 -1
  53. package/dist/cli/commands/data/utilities.js.map +1 -1
  54. package/dist/cli/defineCLICommand.js +1 -1
  55. package/dist/cli/defineCLICommand.js.map +1 -1
  56. package/dist/collections/config/client.d.ts +1 -1
  57. package/dist/collections/config/client.d.ts.map +1 -1
  58. package/dist/collections/config/client.js +0 -1
  59. package/dist/collections/config/client.js.map +1 -1
  60. package/dist/collections/config/defaults.d.ts +2 -0
  61. package/dist/collections/config/defaults.d.ts.map +1 -1
  62. package/dist/collections/config/defaults.js +4 -0
  63. package/dist/collections/config/defaults.js.map +1 -1
  64. package/dist/collections/config/sanitize.d.ts.map +1 -1
  65. package/dist/collections/config/sanitize.js +3 -0
  66. package/dist/collections/config/sanitize.js.map +1 -1
  67. package/dist/collections/config/sanitizeCompoundIndexes.d.ts.map +1 -1
  68. package/dist/collections/config/sanitizeCompoundIndexes.js +0 -9
  69. package/dist/collections/config/sanitizeCompoundIndexes.js.map +1 -1
  70. package/dist/collections/config/types.d.ts +4 -21
  71. package/dist/collections/config/types.d.ts.map +1 -1
  72. package/dist/collections/config/types.js.map +1 -1
  73. package/dist/collections/dataloader.d.ts +1 -10
  74. package/dist/collections/dataloader.d.ts.map +1 -1
  75. package/dist/collections/dataloader.js +6 -14
  76. package/dist/collections/dataloader.js.map +1 -1
  77. package/dist/collections/operations/create.d.ts.map +1 -1
  78. package/dist/collections/operations/create.js +0 -13
  79. package/dist/collections/operations/create.js.map +1 -1
  80. package/dist/collections/operations/delete.d.ts.map +1 -1
  81. package/dist/collections/operations/delete.js +121 -638
  82. package/dist/collections/operations/delete.js.map +1 -1
  83. package/dist/collections/operations/deleteByID.d.ts.map +1 -1
  84. package/dist/collections/operations/deleteByID.js +32 -238
  85. package/dist/collections/operations/deleteByID.js.map +1 -1
  86. package/dist/collections/operations/findByID.d.ts.map +1 -1
  87. package/dist/collections/operations/findByID.js +0 -6
  88. package/dist/collections/operations/findByID.js.map +1 -1
  89. package/dist/collections/operations/findDistinct.d.ts.map +1 -1
  90. package/dist/collections/operations/findDistinct.js +6 -7
  91. package/dist/collections/operations/findDistinct.js.map +1 -1
  92. package/dist/collections/operations/findVersionByID.d.ts.map +1 -1
  93. package/dist/collections/operations/findVersionByID.js +7 -0
  94. package/dist/collections/operations/findVersionByID.js.map +1 -1
  95. package/dist/collections/operations/findVersions.d.ts.map +1 -1
  96. package/dist/collections/operations/findVersions.js +5 -0
  97. package/dist/collections/operations/findVersions.js.map +1 -1
  98. package/dist/collections/operations/local/count.d.ts +4 -9
  99. package/dist/collections/operations/local/count.d.ts.map +1 -1
  100. package/dist/collections/operations/local/count.js.map +1 -1
  101. package/dist/collections/operations/local/countVersions.d.ts +0 -4
  102. package/dist/collections/operations/local/countVersions.d.ts.map +1 -1
  103. package/dist/collections/operations/local/countVersions.js.map +1 -1
  104. package/dist/collections/operations/local/create.d.ts +4 -9
  105. package/dist/collections/operations/local/create.d.ts.map +1 -1
  106. package/dist/collections/operations/local/create.js.map +1 -1
  107. package/dist/collections/operations/local/delete.d.ts +4 -9
  108. package/dist/collections/operations/local/delete.d.ts.map +1 -1
  109. package/dist/collections/operations/local/delete.js.map +1 -1
  110. package/dist/collections/operations/local/duplicate.d.ts +0 -5
  111. package/dist/collections/operations/local/duplicate.d.ts.map +1 -1
  112. package/dist/collections/operations/local/duplicate.js.map +1 -1
  113. package/dist/collections/operations/local/find.d.ts +4 -9
  114. package/dist/collections/operations/local/find.d.ts.map +1 -1
  115. package/dist/collections/operations/local/find.js.map +1 -1
  116. package/dist/collections/operations/local/findByID.d.ts +4 -9
  117. package/dist/collections/operations/local/findByID.d.ts.map +1 -1
  118. package/dist/collections/operations/local/findByID.js.map +1 -1
  119. package/dist/collections/operations/local/findDistinct.d.ts +0 -5
  120. package/dist/collections/operations/local/findDistinct.d.ts.map +1 -1
  121. package/dist/collections/operations/local/findDistinct.js.map +1 -1
  122. package/dist/collections/operations/local/findVersionByID.d.ts +0 -5
  123. package/dist/collections/operations/local/findVersionByID.d.ts.map +1 -1
  124. package/dist/collections/operations/local/findVersionByID.js.map +1 -1
  125. package/dist/collections/operations/local/findVersions.d.ts +0 -5
  126. package/dist/collections/operations/local/findVersions.d.ts.map +1 -1
  127. package/dist/collections/operations/local/findVersions.js.map +1 -1
  128. package/dist/collections/operations/local/restoreVersion.d.ts +0 -5
  129. package/dist/collections/operations/local/restoreVersion.d.ts.map +1 -1
  130. package/dist/collections/operations/local/restoreVersion.js.map +1 -1
  131. package/dist/collections/operations/local/update.d.ts +4 -9
  132. package/dist/collections/operations/local/update.d.ts.map +1 -1
  133. package/dist/collections/operations/local/update.js.map +1 -1
  134. package/dist/collections/operations/renameFile.js +1 -1
  135. package/dist/collections/operations/renameFile.js.map +1 -1
  136. package/dist/collections/operations/restoreVersion.d.ts.map +1 -1
  137. package/dist/collections/operations/restoreVersion.js +76 -157
  138. package/dist/collections/operations/restoreVersion.js.map +1 -1
  139. package/dist/collections/operations/update.d.ts.map +1 -1
  140. package/dist/collections/operations/update.js +171 -357
  141. package/dist/collections/operations/update.js.map +1 -1
  142. package/dist/collections/operations/updateByID.d.ts +0 -15
  143. package/dist/collections/operations/updateByID.d.ts.map +1 -1
  144. package/dist/collections/operations/updateByID.js +60 -265
  145. package/dist/collections/operations/updateByID.js.map +1 -1
  146. package/dist/collections/operations/utilities/buildBeforeOperation.d.ts.map +1 -1
  147. package/dist/collections/operations/utilities/buildBeforeOperation.js +0 -7
  148. package/dist/collections/operations/utilities/buildBeforeOperation.js.map +1 -1
  149. package/dist/collections/operations/utilities/update.d.ts +1 -14
  150. package/dist/collections/operations/utilities/update.d.ts.map +1 -1
  151. package/dist/collections/operations/utilities/update.js +20 -92
  152. package/dist/collections/operations/utilities/update.js.map +1 -1
  153. package/dist/collections/operations/validate.js +4 -4
  154. package/dist/collections/operations/validate.js.map +1 -1
  155. package/dist/config/client.d.ts +1 -3
  156. package/dist/config/client.d.ts.map +1 -1
  157. package/dist/config/client.js +1 -9
  158. package/dist/config/client.js.map +1 -1
  159. package/dist/config/defaults.d.ts.map +1 -1
  160. package/dist/config/defaults.js +1 -0
  161. package/dist/config/defaults.js.map +1 -1
  162. package/dist/config/definePlugin.js.map +1 -1
  163. package/dist/config/sanitize.d.ts.map +1 -1
  164. package/dist/config/sanitize.js +2 -40
  165. package/dist/config/sanitize.js.map +1 -1
  166. package/dist/config/types.d.ts +13 -21
  167. package/dist/config/types.d.ts.map +1 -1
  168. package/dist/config/types.js.map +1 -1
  169. package/dist/database/defaultCopy.d.ts.map +1 -1
  170. package/dist/database/defaultCopy.js +0 -1
  171. package/dist/database/defaultCopy.js.map +1 -1
  172. package/dist/database/types.d.ts +4 -75
  173. package/dist/database/types.d.ts.map +1 -1
  174. package/dist/database/types.js.map +1 -1
  175. package/dist/exports/build-config.d.ts +9 -0
  176. package/dist/exports/build-config.d.ts.map +1 -0
  177. package/dist/exports/build-config.js +38 -0
  178. package/dist/exports/build-config.js.map +1 -0
  179. package/dist/exports/shared.d.ts +0 -2
  180. package/dist/exports/shared.d.ts.map +1 -1
  181. package/dist/exports/shared.js +0 -2
  182. package/dist/exports/shared.js.map +1 -1
  183. package/dist/fields/baseFields/authorship/index.d.ts +1 -2
  184. package/dist/fields/baseFields/authorship/index.d.ts.map +1 -1
  185. package/dist/fields/baseFields/authorship/index.js +0 -12
  186. package/dist/fields/baseFields/authorship/index.js.map +1 -1
  187. package/dist/fields/config/client.js.map +1 -1
  188. package/dist/fields/config/reservedFieldNames.d.ts.map +1 -1
  189. package/dist/fields/config/reservedFieldNames.js.map +1 -1
  190. package/dist/fields/config/types.d.ts.map +1 -1
  191. package/dist/fields/config/types.js.map +1 -1
  192. package/dist/fields/hooks/afterChange/promise.js.map +1 -1
  193. package/dist/fields/hooks/afterRead/index.d.ts +0 -8
  194. package/dist/fields/hooks/afterRead/index.d.ts.map +1 -1
  195. package/dist/fields/hooks/afterRead/index.js +2 -6
  196. package/dist/fields/hooks/afterRead/index.js.map +1 -1
  197. package/dist/fields/hooks/afterRead/promise.d.ts +1 -3
  198. package/dist/fields/hooks/afterRead/promise.d.ts.map +1 -1
  199. package/dist/fields/hooks/afterRead/promise.js +17 -41
  200. package/dist/fields/hooks/afterRead/promise.js.map +1 -1
  201. package/dist/fields/hooks/afterRead/relationshipPopulationPromise.d.ts.map +1 -1
  202. package/dist/fields/hooks/afterRead/relationshipPopulationPromise.js +0 -2
  203. package/dist/fields/hooks/afterRead/relationshipPopulationPromise.js.map +1 -1
  204. package/dist/fields/hooks/afterRead/traverseFields.d.ts +1 -3
  205. package/dist/fields/hooks/afterRead/traverseFields.d.ts.map +1 -1
  206. package/dist/fields/hooks/afterRead/traverseFields.js +2 -4
  207. package/dist/fields/hooks/afterRead/traverseFields.js.map +1 -1
  208. package/dist/fields/hooks/afterRead/virtualFieldPopulationPromise.d.ts.map +1 -1
  209. package/dist/fields/hooks/afterRead/virtualFieldPopulationPromise.js +0 -3
  210. package/dist/fields/hooks/afterRead/virtualFieldPopulationPromise.js.map +1 -1
  211. package/dist/fields/hooks/beforeChange/flattenValidationData.d.ts +14 -0
  212. package/dist/fields/hooks/beforeChange/flattenValidationData.d.ts.map +1 -0
  213. package/dist/fields/hooks/beforeChange/flattenValidationData.js +36 -0
  214. package/dist/fields/hooks/beforeChange/flattenValidationData.js.map +1 -0
  215. package/dist/fields/hooks/beforeChange/promise.d.ts +2 -1
  216. package/dist/fields/hooks/beforeChange/promise.d.ts.map +1 -1
  217. package/dist/fields/hooks/beforeChange/promise.js +96 -22
  218. package/dist/fields/hooks/beforeChange/promise.js.map +1 -1
  219. package/dist/fields/hooks/beforeChange/traverseFields.d.ts +2 -1
  220. package/dist/fields/hooks/beforeChange/traverseFields.d.ts.map +1 -1
  221. package/dist/fields/hooks/beforeChange/traverseFields.js +2 -1
  222. package/dist/fields/hooks/beforeChange/traverseFields.js.map +1 -1
  223. package/dist/fields/hooks/beforeValidate/promise.d.ts.map +1 -1
  224. package/dist/fields/hooks/beforeValidate/promise.js +0 -8
  225. package/dist/fields/hooks/beforeValidate/promise.js.map +1 -1
  226. package/dist/fields/validations.d.ts.map +1 -1
  227. package/dist/fields/validations.js +4 -1
  228. package/dist/fields/validations.js.map +1 -1
  229. package/dist/globals/config/types.d.ts +2 -6
  230. package/dist/globals/config/types.d.ts.map +1 -1
  231. package/dist/globals/config/types.js.map +1 -1
  232. package/dist/globals/operations/countGlobalVersions.d.ts.map +1 -1
  233. package/dist/globals/operations/countGlobalVersions.js +0 -7
  234. package/dist/globals/operations/countGlobalVersions.js.map +1 -1
  235. package/dist/globals/operations/findOne.d.ts.map +1 -1
  236. package/dist/globals/operations/findOne.js +0 -7
  237. package/dist/globals/operations/findOne.js.map +1 -1
  238. package/dist/globals/operations/findVersionByID.d.ts.map +1 -1
  239. package/dist/globals/operations/findVersionByID.js +6 -6
  240. package/dist/globals/operations/findVersionByID.js.map +1 -1
  241. package/dist/globals/operations/findVersions.d.ts.map +1 -1
  242. package/dist/globals/operations/findVersions.js +4 -6
  243. package/dist/globals/operations/findVersions.js.map +1 -1
  244. package/dist/globals/operations/local/countVersions.d.ts +0 -5
  245. package/dist/globals/operations/local/countVersions.d.ts.map +1 -1
  246. package/dist/globals/operations/local/countVersions.js.map +1 -1
  247. package/dist/globals/operations/local/findOne.d.ts +0 -5
  248. package/dist/globals/operations/local/findOne.d.ts.map +1 -1
  249. package/dist/globals/operations/local/findOne.js.map +1 -1
  250. package/dist/globals/operations/local/findVersionByID.d.ts +0 -5
  251. package/dist/globals/operations/local/findVersionByID.d.ts.map +1 -1
  252. package/dist/globals/operations/local/findVersionByID.js.map +1 -1
  253. package/dist/globals/operations/local/findVersions.d.ts +0 -5
  254. package/dist/globals/operations/local/findVersions.d.ts.map +1 -1
  255. package/dist/globals/operations/local/findVersions.js.map +1 -1
  256. package/dist/globals/operations/local/restoreVersion.d.ts +0 -5
  257. package/dist/globals/operations/local/restoreVersion.d.ts.map +1 -1
  258. package/dist/globals/operations/local/restoreVersion.js.map +1 -1
  259. package/dist/globals/operations/local/update.d.ts +0 -5
  260. package/dist/globals/operations/local/update.d.ts.map +1 -1
  261. package/dist/globals/operations/local/update.js +18 -61
  262. package/dist/globals/operations/local/update.js.map +1 -1
  263. package/dist/globals/operations/restoreVersion.d.ts +2 -3
  264. package/dist/globals/operations/restoreVersion.d.ts.map +1 -1
  265. package/dist/globals/operations/restoreVersion.js +24 -61
  266. package/dist/globals/operations/restoreVersion.js.map +1 -1
  267. package/dist/globals/operations/update.d.ts.map +1 -1
  268. package/dist/globals/operations/update.js +8 -86
  269. package/dist/globals/operations/update.js.map +1 -1
  270. package/dist/globals/operations/validate.js +1 -1
  271. package/dist/globals/operations/validate.js.map +1 -1
  272. package/dist/hierarchy/addHierarchyToCollection.d.ts.map +1 -1
  273. package/dist/hierarchy/addHierarchyToCollection.js +32 -21
  274. package/dist/hierarchy/addHierarchyToCollection.js.map +1 -1
  275. package/dist/hierarchy/createFolderField.js.map +1 -1
  276. package/dist/hierarchy/getInitialTreeData.d.ts +1 -3
  277. package/dist/hierarchy/getInitialTreeData.d.ts.map +1 -1
  278. package/dist/hierarchy/getInitialTreeData.js +1 -4
  279. package/dist/hierarchy/getInitialTreeData.js.map +1 -1
  280. package/dist/hierarchy/resolveHierarchyCollections.js +9 -3
  281. package/dist/hierarchy/resolveHierarchyCollections.js.map +1 -1
  282. package/dist/hierarchy/utils/computePaths.d.ts.map +1 -1
  283. package/dist/hierarchy/utils/computePaths.js.map +1 -1
  284. package/dist/index.bundled.d.ts +4336 -5501
  285. package/dist/index.d.ts +27 -51
  286. package/dist/index.d.ts.map +1 -1
  287. package/dist/index.js +14 -37
  288. package/dist/index.js.map +1 -1
  289. package/dist/llm-instructions/getInstructionsCollection.d.ts.map +1 -1
  290. package/dist/llm-instructions/getInstructionsCollection.js +2 -0
  291. package/dist/llm-instructions/getInstructionsCollection.js.map +1 -1
  292. package/dist/preferences/keys.d.ts +4 -11
  293. package/dist/preferences/keys.d.ts.map +1 -1
  294. package/dist/preferences/keys.js +3 -10
  295. package/dist/preferences/keys.js.map +1 -1
  296. package/dist/preferences/types.d.ts +0 -19
  297. package/dist/preferences/types.d.ts.map +1 -1
  298. package/dist/preferences/types.js.map +1 -1
  299. package/dist/queues/operations/runJobs/runJob/getRunTaskFunction.js +1 -1
  300. package/dist/queues/operations/runJobs/runJob/getRunTaskFunction.js.map +1 -1
  301. package/dist/types/index.d.ts +0 -13
  302. package/dist/types/index.d.ts.map +1 -1
  303. package/dist/types/index.js.map +1 -1
  304. package/dist/uploads/deleteAssociatedFiles.d.ts.map +1 -1
  305. package/dist/uploads/deleteAssociatedFiles.js +29 -108
  306. package/dist/uploads/deleteAssociatedFiles.js.map +1 -1
  307. package/dist/uploads/endpoints/getFile.d.ts.map +1 -1
  308. package/dist/uploads/endpoints/getFile.js +0 -5
  309. package/dist/uploads/endpoints/getFile.js.map +1 -1
  310. package/dist/uploads/fileExists.d.ts.map +1 -1
  311. package/dist/uploads/fileExists.js +2 -5
  312. package/dist/uploads/fileExists.js.map +1 -1
  313. package/dist/uploads/fileVersioning/archive.d.ts.map +1 -1
  314. package/dist/uploads/fileVersioning/archive.js +1 -15
  315. package/dist/uploads/fileVersioning/archive.js.map +1 -1
  316. package/dist/uploads/fileVersioning/cleanup.d.ts +0 -7
  317. package/dist/uploads/fileVersioning/cleanup.d.ts.map +1 -1
  318. package/dist/uploads/fileVersioning/cleanup.js +0 -12
  319. package/dist/uploads/fileVersioning/cleanup.js.map +1 -1
  320. package/dist/uploads/fileVersioning/cloudStorage.d.ts.map +1 -1
  321. package/dist/uploads/fileVersioning/cloudStorage.js +1 -16
  322. package/dist/uploads/fileVersioning/cloudStorage.js.map +1 -1
  323. package/dist/uploads/fileVersioning/resolveHistoricalFile.js.map +1 -1
  324. package/dist/uploads/formatFilesize.js +1 -1
  325. package/dist/uploads/formatFilesize.js.map +1 -1
  326. package/dist/uploads/generateFileData.d.ts +0 -5
  327. package/dist/uploads/generateFileData.d.ts.map +1 -1
  328. package/dist/uploads/generateFileData.js +2 -74
  329. package/dist/uploads/generateFileData.js.map +1 -1
  330. package/dist/uploads/getBaseFields.d.ts.map +1 -1
  331. package/dist/uploads/getBaseFields.js +29 -46
  332. package/dist/uploads/getBaseFields.js.map +1 -1
  333. package/dist/uploads/getFileContentRequirement.js.map +1 -1
  334. package/dist/uploads/getFileFromUploadInstructions.js.map +1 -1
  335. package/dist/uploads/getSafeFilename.d.ts.map +1 -1
  336. package/dist/uploads/getSafeFilename.js +3 -5
  337. package/dist/uploads/getSafeFilename.js.map +1 -1
  338. package/dist/uploads/safeFetch.js.map +1 -1
  339. package/dist/uploads/stagedUpload.js.map +1 -1
  340. package/dist/uploads/transformers/handleDynamicFileRequest.js +11 -2
  341. package/dist/uploads/transformers/handleDynamicFileRequest.js.map +1 -1
  342. package/dist/uploads/types.d.ts +0 -11
  343. package/dist/uploads/types.d.ts.map +1 -1
  344. package/dist/uploads/types.js.map +1 -1
  345. package/dist/uploads/uploadFiles.d.ts +1 -4
  346. package/dist/uploads/uploadFiles.d.ts.map +1 -1
  347. package/dist/uploads/uploadFiles.js +5 -29
  348. package/dist/uploads/uploadFiles.js.map +1 -1
  349. package/dist/utilities/addSelectGenericsToGeneretedTypes.d.ts.map +1 -1
  350. package/dist/utilities/addSelectGenericsToGeneretedTypes.js +0 -1
  351. package/dist/utilities/addSelectGenericsToGeneretedTypes.js.map +1 -1
  352. package/dist/utilities/appendDateTimezoneSelectFields.js.map +1 -1
  353. package/dist/utilities/assertNoValidationWrite.d.ts.map +1 -1
  354. package/dist/utilities/assertNoValidationWrite.js +0 -4
  355. package/dist/utilities/assertNoValidationWrite.js.map +1 -1
  356. package/dist/utilities/checkDocumentLockStatus.d.ts +6 -15
  357. package/dist/utilities/checkDocumentLockStatus.d.ts.map +1 -1
  358. package/dist/utilities/checkDocumentLockStatus.js +11 -44
  359. package/dist/utilities/checkDocumentLockStatus.js.map +1 -1
  360. package/dist/utilities/cloneValidationRequest.js.map +1 -1
  361. package/dist/utilities/commitTransaction.d.ts +0 -4
  362. package/dist/utilities/commitTransaction.d.ts.map +1 -1
  363. package/dist/utilities/commitTransaction.js +1 -41
  364. package/dist/utilities/commitTransaction.js.map +1 -1
  365. package/dist/utilities/configToJSONSchema.d.ts.map +1 -1
  366. package/dist/utilities/configToJSONSchema.js +2 -18
  367. package/dist/utilities/configToJSONSchema.js.map +1 -1
  368. package/dist/utilities/createPayloadRequest.d.ts +0 -5
  369. package/dist/utilities/createPayloadRequest.d.ts.map +1 -1
  370. package/dist/utilities/createPayloadRequest.js +3 -50
  371. package/dist/utilities/createPayloadRequest.js.map +1 -1
  372. package/dist/utilities/createPayloadRequestFromWebRequest.d.ts +12 -1
  373. package/dist/utilities/createPayloadRequestFromWebRequest.d.ts.map +1 -1
  374. package/dist/utilities/createPayloadRequestFromWebRequest.js +9 -5
  375. package/dist/utilities/createPayloadRequestFromWebRequest.js.map +1 -1
  376. package/dist/utilities/deepCopyObject.js.map +1 -1
  377. package/dist/utilities/documentMatchingWhereExists.js +1 -1
  378. package/dist/utilities/documentMatchingWhereExists.js.map +1 -1
  379. package/dist/utilities/entityInputSchema/validateEntityData.d.ts.map +1 -1
  380. package/dist/utilities/entityInputSchema/validateEntityData.js.map +1 -1
  381. package/dist/utilities/filterDataToSelectedLocales.js.map +1 -1
  382. package/dist/utilities/getEntityPermissions/getEntityPermissions.d.ts.map +1 -1
  383. package/dist/utilities/getEntityPermissions/getEntityPermissions.js +1 -0
  384. package/dist/utilities/getEntityPermissions/getEntityPermissions.js.map +1 -1
  385. package/dist/utilities/getEntityPermissions/populateFieldPermissions.js.map +1 -1
  386. package/dist/utilities/getVersionsConfig.d.ts +4 -0
  387. package/dist/utilities/getVersionsConfig.d.ts.map +1 -1
  388. package/dist/utilities/getVersionsConfig.js +5 -0
  389. package/dist/utilities/getVersionsConfig.js.map +1 -1
  390. package/dist/utilities/handleEndpoints.d.ts.map +1 -1
  391. package/dist/utilities/handleEndpoints.js +10 -9
  392. package/dist/utilities/handleEndpoints.js.map +1 -1
  393. package/dist/utilities/httpStatus.d.ts +0 -2
  394. package/dist/utilities/httpStatus.d.ts.map +1 -1
  395. package/dist/utilities/httpStatus.js +1 -3
  396. package/dist/utilities/httpStatus.js.map +1 -1
  397. package/dist/utilities/initTransaction.d.ts.map +1 -1
  398. package/dist/utilities/initTransaction.js +7 -35
  399. package/dist/utilities/initTransaction.js.map +1 -1
  400. package/dist/utilities/killTransaction.d.ts.map +1 -1
  401. package/dist/utilities/killTransaction.js +0 -27
  402. package/dist/utilities/killTransaction.js.map +1 -1
  403. package/dist/utilities/parseParams/index.js.map +1 -1
  404. package/dist/utilities/parseValidationLocale.js.map +1 -1
  405. package/dist/utilities/sanitizePopulateParam.js.map +1 -1
  406. package/dist/utilities/telemetry/conf/index.d.ts +4 -1
  407. package/dist/utilities/telemetry/conf/index.d.ts.map +1 -1
  408. package/dist/utilities/telemetry/conf/index.js.map +1 -1
  409. package/dist/utilities/telemetry/featureInfo/getFeatureInfo.js.map +1 -1
  410. package/dist/versions/allLocalesPublicationStatus.js.map +1 -1
  411. package/dist/versions/buildCollectionFields.d.ts.map +1 -1
  412. package/dist/versions/buildCollectionFields.js +0 -23
  413. package/dist/versions/buildCollectionFields.js.map +1 -1
  414. package/dist/versions/buildGlobalFields.d.ts.map +1 -1
  415. package/dist/versions/buildGlobalFields.js +0 -14
  416. package/dist/versions/buildGlobalFields.js.map +1 -1
  417. package/dist/versions/buildVersionCompoundIndexes.d.ts.map +1 -1
  418. package/dist/versions/buildVersionCompoundIndexes.js +2 -8
  419. package/dist/versions/buildVersionCompoundIndexes.js.map +1 -1
  420. package/dist/versions/deleteCollectionVersions.d.ts +1 -2
  421. package/dist/versions/deleteCollectionVersions.d.ts.map +1 -1
  422. package/dist/versions/deleteCollectionVersions.js +8 -37
  423. package/dist/versions/deleteCollectionVersions.js.map +1 -1
  424. package/dist/versions/deleteScheduledPublishJobs.d.ts.map +1 -1
  425. package/dist/versions/deleteScheduledPublishJobs.js +0 -4
  426. package/dist/versions/deleteScheduledPublishJobs.js.map +1 -1
  427. package/dist/versions/drafts/appendVersionToQueryKey.d.ts.map +1 -1
  428. package/dist/versions/drafts/appendVersionToQueryKey.js +1 -9
  429. package/dist/versions/drafts/appendVersionToQueryKey.js.map +1 -1
  430. package/dist/versions/drafts/replaceWithDraftIfAvailable.d.ts.map +1 -1
  431. package/dist/versions/drafts/replaceWithDraftIfAvailable.js +1 -8
  432. package/dist/versions/drafts/replaceWithDraftIfAvailable.js.map +1 -1
  433. package/dist/versions/enforceMaxVersions.d.ts +0 -1
  434. package/dist/versions/enforceMaxVersions.d.ts.map +1 -1
  435. package/dist/versions/enforceMaxVersions.js +6 -22
  436. package/dist/versions/enforceMaxVersions.js.map +1 -1
  437. package/dist/versions/getLatestCollectionVersion.d.ts.map +1 -1
  438. package/dist/versions/getLatestCollectionVersion.js +2 -10
  439. package/dist/versions/getLatestCollectionVersion.js.map +1 -1
  440. package/dist/versions/getLatestGlobalVersion.d.ts +2 -6
  441. package/dist/versions/getLatestGlobalVersion.d.ts.map +1 -1
  442. package/dist/versions/getLatestGlobalVersion.js +21 -65
  443. package/dist/versions/getLatestGlobalVersion.js.map +1 -1
  444. package/dist/versions/isInheritedReadVersionsAccess.js.map +1 -1
  445. package/dist/versions/saveVersion.d.ts +0 -7
  446. package/dist/versions/saveVersion.d.ts.map +1 -1
  447. package/dist/versions/saveVersion.js +4 -27
  448. package/dist/versions/saveVersion.js.map +1 -1
  449. package/dist/versions/updateLatestVersion.d.ts +0 -1
  450. package/dist/versions/updateLatestVersion.d.ts.map +1 -1
  451. package/dist/versions/updateLatestVersion.js +7 -24
  452. package/dist/versions/updateLatestVersion.js.map +1 -1
  453. package/package.json +30 -28
  454. package/skills/payload/reference/ENDPOINTS.md +3 -9
  455. package/skills/payload/reference/PLUGIN-DEVELOPMENT.md +4 -4
  456. package/dist/admin/getAdminPreferences.d.ts +0 -10
  457. package/dist/admin/getAdminPreferences.d.ts.map +0 -1
  458. package/dist/admin/getAdminPreferences.js +0 -53
  459. package/dist/admin/getAdminPreferences.js.map +0 -1
  460. package/dist/admin/getRequestBranch.d.ts +0 -6
  461. package/dist/admin/getRequestBranch.d.ts.map +0 -1
  462. package/dist/admin/getRequestBranch.js +0 -17
  463. package/dist/admin/getRequestBranch.js.map +0 -1
  464. package/dist/branching/appendBranchFilter.d.ts +0 -30
  465. package/dist/branching/appendBranchFilter.d.ts.map +0 -1
  466. package/dist/branching/appendBranchFilter.js +0 -105
  467. package/dist/branching/appendBranchFilter.js.map +0 -1
  468. package/dist/branching/assertBranchAccess.d.ts +0 -10
  469. package/dist/branching/assertBranchAccess.d.ts.map +0 -1
  470. package/dist/branching/assertBranchAccess.js +0 -36
  471. package/dist/branching/assertBranchAccess.js.map +0 -1
  472. package/dist/branching/assertBranchActionAccess.d.ts +0 -10
  473. package/dist/branching/assertBranchActionAccess.d.ts.map +0 -1
  474. package/dist/branching/assertBranchActionAccess.js +0 -15
  475. package/dist/branching/assertBranchActionAccess.js.map +0 -1
  476. package/dist/branching/assertBranchCreatedDocumentsUnreferenced.d.ts +0 -53
  477. package/dist/branching/assertBranchCreatedDocumentsUnreferenced.d.ts.map +0 -1
  478. package/dist/branching/assertBranchCreatedDocumentsUnreferenced.js +0 -833
  479. package/dist/branching/assertBranchCreatedDocumentsUnreferenced.js.map +0 -1
  480. package/dist/branching/assertBranchReadable.d.ts +0 -36
  481. package/dist/branching/assertBranchReadable.d.ts.map +0 -1
  482. package/dist/branching/assertBranchReadable.js +0 -83
  483. package/dist/branching/assertBranchReadable.js.map +0 -1
  484. package/dist/branching/assertBranchUpdateAccess.d.ts +0 -8
  485. package/dist/branching/assertBranchUpdateAccess.d.ts.map +0 -1
  486. package/dist/branching/assertBranchUpdateAccess.js +0 -12
  487. package/dist/branching/assertBranchUpdateAccess.js.map +0 -1
  488. package/dist/branching/assertBranchWritable.d.ts +0 -18
  489. package/dist/branching/assertBranchWritable.d.ts.map +0 -1
  490. package/dist/branching/assertBranchWritable.js +0 -46
  491. package/dist/branching/assertBranchWritable.js.map +0 -1
  492. package/dist/branching/branchIDs.d.ts +0 -38
  493. package/dist/branching/branchIDs.d.ts.map +0 -1
  494. package/dist/branching/branchIDs.js +0 -113
  495. package/dist/branching/branchIDs.js.map +0 -1
  496. package/dist/branching/branchSelect.d.ts +0 -42
  497. package/dist/branching/branchSelect.d.ts.map +0 -1
  498. package/dist/branching/branchSelect.js +0 -97
  499. package/dist/branching/branchSelect.js.map +0 -1
  500. package/dist/branching/checkFieldAccess.d.ts +0 -21
  501. package/dist/branching/checkFieldAccess.d.ts.map +0 -1
  502. package/dist/branching/checkFieldAccess.js +0 -238
  503. package/dist/branching/checkFieldAccess.js.map +0 -1
  504. package/dist/branching/collections.d.ts +0 -14
  505. package/dist/branching/collections.d.ts.map +0 -1
  506. package/dist/branching/collections.js +0 -713
  507. package/dist/branching/collections.js.map +0 -1
  508. package/dist/branching/combineBranchAccess.d.ts +0 -6
  509. package/dist/branching/combineBranchAccess.d.ts.map +0 -1
  510. package/dist/branching/combineBranchAccess.js +0 -22
  511. package/dist/branching/combineBranchAccess.js.map +0 -1
  512. package/dist/branching/copyUploadFilesToBranch.d.ts +0 -9
  513. package/dist/branching/copyUploadFilesToBranch.d.ts.map +0 -1
  514. package/dist/branching/copyUploadFilesToBranch.js +0 -126
  515. package/dist/branching/copyUploadFilesToBranch.js.map +0 -1
  516. package/dist/branching/createShadowRow.d.ts +0 -70
  517. package/dist/branching/createShadowRow.d.ts.map +0 -1
  518. package/dist/branching/createShadowRow.js +0 -296
  519. package/dist/branching/createShadowRow.js.map +0 -1
  520. package/dist/branching/discard.d.ts +0 -52
  521. package/dist/branching/discard.d.ts.map +0 -1
  522. package/dist/branching/discard.js +0 -428
  523. package/dist/branching/discard.js.map +0 -1
  524. package/dist/branching/effectiveOperations.d.ts +0 -55
  525. package/dist/branching/effectiveOperations.d.ts.map +0 -1
  526. package/dist/branching/effectiveOperations.js +0 -472
  527. package/dist/branching/effectiveOperations.js.map +0 -1
  528. package/dist/branching/endpoints/discard.d.ts +0 -15
  529. package/dist/branching/endpoints/discard.d.ts.map +0 -1
  530. package/dist/branching/endpoints/discard.js +0 -55
  531. package/dist/branching/endpoints/discard.js.map +0 -1
  532. package/dist/branching/endpoints/merge.d.ts +0 -34
  533. package/dist/branching/endpoints/merge.d.ts.map +0 -1
  534. package/dist/branching/endpoints/merge.js +0 -119
  535. package/dist/branching/endpoints/merge.js.map +0 -1
  536. package/dist/branching/forkDocument.d.ts +0 -20
  537. package/dist/branching/forkDocument.d.ts.map +0 -1
  538. package/dist/branching/forkDocument.js +0 -169
  539. package/dist/branching/forkDocument.js.map +0 -1
  540. package/dist/branching/globalMergeWrites.d.ts +0 -21
  541. package/dist/branching/globalMergeWrites.d.ts.map +0 -1
  542. package/dist/branching/globalMergeWrites.js +0 -146
  543. package/dist/branching/globalMergeWrites.js.map +0 -1
  544. package/dist/branching/globals.d.ts +0 -49
  545. package/dist/branching/globals.d.ts.map +0 -1
  546. package/dist/branching/globals.js +0 -197
  547. package/dist/branching/globals.js.map +0 -1
  548. package/dist/branching/hooks.d.ts +0 -24
  549. package/dist/branching/hooks.d.ts.map +0 -1
  550. package/dist/branching/hooks.js +0 -92
  551. package/dist/branching/hooks.js.map +0 -1
  552. package/dist/branching/injectBranchFields.d.ts +0 -40
  553. package/dist/branching/injectBranchFields.d.ts.map +0 -1
  554. package/dist/branching/injectBranchFields.js +0 -229
  555. package/dist/branching/injectBranchFields.js.map +0 -1
  556. package/dist/branching/merge/applyMergeChange.d.ts +0 -27
  557. package/dist/branching/merge/applyMergeChange.d.ts.map +0 -1
  558. package/dist/branching/merge/applyMergeChange.js +0 -853
  559. package/dist/branching/merge/applyMergeChange.js.map +0 -1
  560. package/dist/branching/merge/branchMergeStatus.d.ts +0 -12
  561. package/dist/branching/merge/branchMergeStatus.d.ts.map +0 -1
  562. package/dist/branching/merge/branchMergeStatus.js +0 -74
  563. package/dist/branching/merge/branchMergeStatus.js.map +0 -1
  564. package/dist/branching/merge/executeMerge.d.ts +0 -22
  565. package/dist/branching/merge/executeMerge.d.ts.map +0 -1
  566. package/dist/branching/merge/executeMerge.js +0 -600
  567. package/dist/branching/merge/executeMerge.js.map +0 -1
  568. package/dist/branching/merge/finalizeMerge.d.ts +0 -40
  569. package/dist/branching/merge/finalizeMerge.d.ts.map +0 -1
  570. package/dist/branching/merge/finalizeMerge.js +0 -237
  571. package/dist/branching/merge/finalizeMerge.js.map +0 -1
  572. package/dist/branching/merge/mergeLedger.d.ts +0 -40
  573. package/dist/branching/merge/mergeLedger.d.ts.map +0 -1
  574. package/dist/branching/merge/mergeLedger.js +0 -130
  575. package/dist/branching/merge/mergeLedger.js.map +0 -1
  576. package/dist/branching/merge/prepareMerge.d.ts +0 -41
  577. package/dist/branching/merge/prepareMerge.d.ts.map +0 -1
  578. package/dist/branching/merge/prepareMerge.js +0 -234
  579. package/dist/branching/merge/prepareMerge.js.map +0 -1
  580. package/dist/branching/merge/recoverMerge.d.ts +0 -16
  581. package/dist/branching/merge/recoverMerge.d.ts.map +0 -1
  582. package/dist/branching/merge/recoverMerge.js +0 -199
  583. package/dist/branching/merge/recoverMerge.js.map +0 -1
  584. package/dist/branching/merge/retryFailedCleanups.d.ts +0 -36
  585. package/dist/branching/merge/retryFailedCleanups.d.ts.map +0 -1
  586. package/dist/branching/merge/retryFailedCleanups.js +0 -335
  587. package/dist/branching/merge/retryFailedCleanups.js.map +0 -1
  588. package/dist/branching/merge/utilities.d.ts +0 -35
  589. package/dist/branching/merge/utilities.d.ts.map +0 -1
  590. package/dist/branching/merge/utilities.js +0 -54
  591. package/dist/branching/merge/utilities.js.map +0 -1
  592. package/dist/branching/merge.d.ts +0 -88
  593. package/dist/branching/merge.d.ts.map +0 -1
  594. package/dist/branching/merge.js +0 -163
  595. package/dist/branching/merge.js.map +0 -1
  596. package/dist/branching/mergeWriteGuard.d.ts +0 -20
  597. package/dist/branching/mergeWriteGuard.d.ts.map +0 -1
  598. package/dist/branching/mergeWriteGuard.js +0 -27
  599. package/dist/branching/mergeWriteGuard.js.map +0 -1
  600. package/dist/branching/preflight.d.ts +0 -71
  601. package/dist/branching/preflight.d.ts.map +0 -1
  602. package/dist/branching/preflight.js +0 -757
  603. package/dist/branching/preflight.js.map +0 -1
  604. package/dist/branching/readLocalizedBranchWrite.d.ts +0 -14
  605. package/dist/branching/readLocalizedBranchWrite.d.ts.map +0 -1
  606. package/dist/branching/readLocalizedBranchWrite.js +0 -90
  607. package/dist/branching/readLocalizedBranchWrite.js.map +0 -1
  608. package/dist/branching/readMergeSnapshot.d.ts +0 -18
  609. package/dist/branching/readMergeSnapshot.d.ts.map +0 -1
  610. package/dist/branching/readMergeSnapshot.js +0 -99
  611. package/dist/branching/readMergeSnapshot.js.map +0 -1
  612. package/dist/branching/resolveBranch.d.ts +0 -153
  613. package/dist/branching/resolveBranch.d.ts.map +0 -1
  614. package/dist/branching/resolveBranch.js +0 -363
  615. package/dist/branching/resolveBranch.js.map +0 -1
  616. package/dist/branching/resolveBranchActionAccess.d.ts +0 -8
  617. package/dist/branching/resolveBranchActionAccess.d.ts.map +0 -1
  618. package/dist/branching/resolveBranchActionAccess.js +0 -9
  619. package/dist/branching/resolveBranchActionAccess.js.map +0 -1
  620. package/dist/branching/resolveBranchQuery.d.ts +0 -48
  621. package/dist/branching/resolveBranchQuery.d.ts.map +0 -1
  622. package/dist/branching/resolveBranchQuery.js +0 -115
  623. package/dist/branching/resolveBranchQuery.js.map +0 -1
  624. package/dist/branching/resolveBranchRowID.d.ts +0 -22
  625. package/dist/branching/resolveBranchRowID.d.ts.map +0 -1
  626. package/dist/branching/resolveBranchRowID.js +0 -70
  627. package/dist/branching/resolveBranchRowID.js.map +0 -1
  628. package/dist/branching/sanitizeBranchingConfig.d.ts +0 -31
  629. package/dist/branching/sanitizeBranchingConfig.d.ts.map +0 -1
  630. package/dist/branching/sanitizeBranchingConfig.js +0 -110
  631. package/dist/branching/sanitizeBranchingConfig.js.map +0 -1
  632. package/dist/branching/schedule/job.d.ts +0 -51
  633. package/dist/branching/schedule/job.d.ts.map +0 -1
  634. package/dist/branching/schedule/job.js +0 -151
  635. package/dist/branching/schedule/job.js.map +0 -1
  636. package/dist/branching/selectBranchChanges.d.ts +0 -8
  637. package/dist/branching/selectBranchChanges.d.ts.map +0 -1
  638. package/dist/branching/selectBranchChanges.js +0 -9
  639. package/dist/branching/selectBranchChanges.js.map +0 -1
  640. package/dist/branching/stripBranchMergeData.d.ts +0 -11
  641. package/dist/branching/stripBranchMergeData.d.ts.map +0 -1
  642. package/dist/branching/stripBranchMergeData.js +0 -20
  643. package/dist/branching/stripBranchMergeData.js.map +0 -1
  644. package/dist/branching/tombstone.d.ts +0 -91
  645. package/dist/branching/tombstone.d.ts.map +0 -1
  646. package/dist/branching/tombstone.js +0 -546
  647. package/dist/branching/tombstone.js.map +0 -1
  648. package/dist/branching/types.d.ts +0 -158
  649. package/dist/branching/types.d.ts.map +0 -1
  650. package/dist/branching/types.js +0 -54
  651. package/dist/branching/types.js.map +0 -1
  652. package/dist/branching/validation.d.ts +0 -47
  653. package/dist/branching/validation.d.ts.map +0 -1
  654. package/dist/branching/validation.js +0 -272
  655. package/dist/branching/validation.js.map +0 -1
  656. package/dist/branching/versions.d.ts +0 -131
  657. package/dist/branching/versions.d.ts.map +0 -1
  658. package/dist/branching/versions.js +0 -572
  659. package/dist/branching/versions.js.map +0 -1
  660. package/dist/collections/operations/utilities/createOperationRetryRequest.d.ts +0 -23
  661. package/dist/collections/operations/utilities/createOperationRetryRequest.d.ts.map +0 -1
  662. package/dist/collections/operations/utilities/createOperationRetryRequest.js +0 -683
  663. package/dist/collections/operations/utilities/createOperationRetryRequest.js.map +0 -1
  664. package/dist/fields/hooks/beforeValidate/throwOnAccessDenied.d.ts +0 -3
  665. package/dist/fields/hooks/beforeValidate/throwOnAccessDenied.d.ts.map +0 -1
  666. package/dist/fields/hooks/beforeValidate/throwOnAccessDenied.js +0 -3
  667. package/dist/fields/hooks/beforeValidate/throwOnAccessDenied.js.map +0 -1
  668. package/dist/uploads/appendBranchToFileURL.d.ts +0 -6
  669. package/dist/uploads/appendBranchToFileURL.d.ts.map +0 -1
  670. package/dist/uploads/appendBranchToFileURL.js +0 -24
  671. package/dist/uploads/appendBranchToFileURL.js.map +0 -1
  672. package/dist/uploads/deleteUploadFilesExclusiveToDocument.d.ts +0 -15
  673. package/dist/uploads/deleteUploadFilesExclusiveToDocument.d.ts.map +0 -1
  674. package/dist/uploads/deleteUploadFilesExclusiveToDocument.js +0 -62
  675. package/dist/uploads/deleteUploadFilesExclusiveToDocument.js.map +0 -1
  676. package/dist/uploads/fileIdentity.d.ts +0 -24
  677. package/dist/uploads/fileIdentity.d.ts.map +0 -1
  678. package/dist/uploads/fileIdentity.js +0 -36
  679. package/dist/uploads/fileIdentity.js.map +0 -1
  680. package/dist/uploads/fileQuarantine.d.ts +0 -17
  681. package/dist/uploads/fileQuarantine.d.ts.map +0 -1
  682. package/dist/uploads/fileQuarantine.js +0 -52
  683. package/dist/uploads/fileQuarantine.js.map +0 -1
  684. package/dist/uploads/linkFileWithoutOverwrite.d.ts +0 -13
  685. package/dist/uploads/linkFileWithoutOverwrite.d.ts.map +0 -1
  686. package/dist/uploads/linkFileWithoutOverwrite.js +0 -13
  687. package/dist/uploads/linkFileWithoutOverwrite.js.map +0 -1
  688. package/dist/uploads/uploadFileRollback.d.ts +0 -31
  689. package/dist/uploads/uploadFileRollback.d.ts.map +0 -1
  690. package/dist/uploads/uploadFileRollback.js +0 -269
  691. package/dist/uploads/uploadFileRollback.js.map +0 -1
  692. package/dist/utilities/extractRelationshipID.d.ts +0 -4
  693. package/dist/utilities/extractRelationshipID.d.ts.map +0 -1
  694. package/dist/utilities/extractRelationshipID.js +0 -14
  695. package/dist/utilities/extractRelationshipID.js.map +0 -1
  696. package/dist/utilities/transactionCallbacks.d.ts +0 -77
  697. package/dist/utilities/transactionCallbacks.d.ts.map +0 -1
  698. package/dist/utilities/transactionCallbacks.js +0 -299
  699. package/dist/utilities/transactionCallbacks.js.map +0 -1
  700. package/dist/utilities/transactionMutationTracker.d.ts +0 -21
  701. package/dist/utilities/transactionMutationTracker.d.ts.map +0 -1
  702. package/dist/utilities/transactionMutationTracker.js +0 -71
  703. package/dist/utilities/transactionMutationTracker.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/uploads/getFileFromUploadInstructions.ts"],"sourcesContent":["import type { ReadableStream } from 'node:stream/web'\n\nimport { randomUUID } from 'node:crypto'\nimport fs from 'node:fs'\nimport { mkdir, rm, stat } from 'node:fs/promises'\nimport os from 'node:os'\nimport path from 'node:path'\nimport { Readable } from 'node:stream'\nimport { pipeline } from 'node:stream/promises'\n\nimport type { PayloadRequest } from '../types/index.js'\nimport type { SanitizedUploadConfig, UploadEdits, UploadInstructions } from './types.js'\n\nimport { APIError } from '../errors/APIError.js'\nimport { sanitizeFilename } from '../utilities/sanitizeFilename.js'\nimport { sanitizeUploadPrefix } from '../utilities/sanitizeUploadPrefix.js'\nimport { verifyClientUploadReceipt } from './clientUploadReceipt.js'\nimport { docWithFilenameExists } from './docWithFilenameExists.js'\nimport { getOriginalFilename, normalizeStorageKey } from './fileVersioning/naming.js'\nimport { getFileContentRequirement, HEADER_PROBE_BYTE_LENGTH } from './getFileContentRequirement.js'\nimport { getImageSize } from './getImageSize.js'\nimport { hasCropOrResizeEdit } from './hasCropOrResizeEdit.js'\nimport { getStagedFile } from './stagedUpload.js'\nimport { planTransformerPipeline } from './transformers/planTransformerPipeline.js'\nimport { getUploadTransformerInternal } from './transformers/uploadTransformerBridge.js'\n\nexport const getFileFromUploadInstructions = async ({\n collectionSlug,\n file,\n req,\n}: {\n collectionSlug: string\n file: UploadInstructions['file']\n req: PayloadRequest\n}): Promise<NonNullable<PayloadRequest['file']>> => {\n if (req.context) {\n delete req.context._payloadVerifiedProviderOriginal\n }\n\n if (\n !file ||\n typeof file !== 'object' ||\n typeof file.filename !== 'string' ||\n typeof file.mimeType !== 'string' ||\n !Number.isSafeInteger(file.size) ||\n file.size < 0 ||\n !file.uploadReference ||\n typeof file.uploadReference !== 'object' ||\n Array.isArray(file.uploadReference)\n ) {\n throw new APIError('Invalid upload reference.', 400)\n }\n\n /**\n * Handlers fetch files uploaded to a storage provider. An uploadId points to a temporary file\n * already stored by Payload, so no handler is needed.\n */\n if ('uploadId' in file.uploadReference) {\n return getStagedFile({ collectionSlug, req, uploadReference: file.uploadReference })\n }\n\n const uploadConfig = req.payload.collections[collectionSlug]!.config.upload\n let allowOverwrite = false\n let providerFilename = file.filename\n let verifiedOriginal:\n | {\n _objectKey?: string\n filename: string\n key: string\n prefix?: string\n signedReceipt: string\n }\n | undefined\n\n if (uploadConfig?.uploadInstructions?.requiresUploadReceipt) {\n const signedReceipt =\n 'signedReceipt' in file.uploadReference ? file.uploadReference.signedReceipt : undefined\n const receipt = verifyClientUploadReceipt({\n collectionSlug,\n filename: file.filename,\n req,\n signedReceipt,\n })\n allowOverwrite = receipt.allowOverwrite === true\n let originalFilename: string\n let storageFilePath: string\n\n try {\n originalFilename = getOriginalFilename({ filename: file.filename })\n storageFilePath = normalizeStorageKey({ key: receipt.storageFilePath })\n } catch {\n throw new APIError('Invalid upload reference.', 400)\n }\n\n const expectedKeySuffix = [receipt.filePrefix, receipt._objectKey, originalFilename]\n .filter(Boolean)\n .join('/')\n\n if (\n (!allowOverwrite &&\n (!receipt._objectKey ||\n path.posix.basename(storageFilePath) !== originalFilename ||\n !`/${storageFilePath}`.endsWith(`/${expectedKeySuffix}`))) ||\n ('prefix' in file.uploadReference && file.uploadReference.prefix !== receipt.filePrefix) ||\n ('_objectKey' in file.uploadReference &&\n file.uploadReference._objectKey !== receipt._objectKey)\n ) {\n throw new APIError('Invalid upload reference.', 400)\n }\n\n providerFilename = allowOverwrite ? file.filename : originalFilename\n if (!allowOverwrite) {\n verifiedOriginal = {\n _objectKey: receipt._objectKey,\n filename: originalFilename,\n key: storageFilePath,\n prefix: receipt.filePrefix,\n signedReceipt: signedReceipt as string,\n }\n }\n file = {\n ...file,\n uploadReference: {\n _objectKey: receipt._objectKey,\n prefix: receipt.filePrefix,\n signedReceipt,\n },\n }\n }\n\n const prefix =\n 'prefix' in file.uploadReference && typeof file.uploadReference.prefix === 'string'\n ? file.uploadReference.prefix\n : undefined\n\n let sanitizedFilename: string\n\n try {\n sanitizedFilename = sanitizeFilename(file.filename)\n } catch {\n throw new APIError('Invalid upload reference.', 400)\n }\n\n if (\n sanitizedFilename !== file.filename ||\n (typeof prefix === 'string' && sanitizeUploadPrefix(prefix) !== prefix)\n ) {\n throw new APIError('Invalid upload reference.', 400)\n }\n\n // Provider-backed references are submitted with the document request. They may only claim a\n // new object identity; existing top-level and generated filenames already belong to another\n // document and must continue through that document's read access checks.\n if (\n !allowOverwrite &&\n (await docWithFilenameExists({\n collectionSlug,\n filename: file.filename,\n matchAnyPrefix: true,\n path: '',\n prefix,\n req,\n }))\n ) {\n throw new APIError('Invalid upload reference.', 400)\n }\n\n if (!uploadConfig || !uploadConfig.handlers) {\n throw new APIError('uploadConfig.handlers is not present for ' + collectionSlug)\n }\n\n const contentRequirement = getFileContentRequirement({\n hasSizeEdits: requestHasSizeEdits(req),\n hasTransformFileStages: await hasTransformFileStages({\n collectionSlug,\n mimeType: file.mimeType,\n req,\n }),\n mimeType: file.mimeType,\n uploadConfig,\n })\n const providerFile = { ...file, filename: providerFilename }\n const rememberVerifiedOriginal = () => {\n if (verifiedOriginal) {\n req.context ??= {}\n req.context._payloadVerifiedProviderOriginal = verifiedOriginal\n }\n }\n\n // Nothing downstream reads this file's content - use the client-reported metadata directly\n // instead of re-downloading a file that, for a chunked upload, can be far larger than\n // the server's available memory or disk.\n if (contentRequirement === 'none') {\n const response = await fetchUploadResponse({\n collectionSlug,\n file: providerFile,\n rangeHeader: file.size > 0 ? 'bytes=0-0' : undefined,\n req,\n uploadConfig,\n })\n assertProviderFileSize({ expectedSize: file.size, response })\n const prefix = await readBoundedPrefix(response, 1)\n if (file.size > 0 && prefix.length === 0) {\n throw new APIError('Uploaded source is not readable.', 400)\n }\n rememberVerifiedOriginal()\n\n return {\n name: file.filename,\n data: Buffer.alloc(0),\n mimetype: file.mimeType,\n size: file.size,\n uploadReference: file.uploadReference,\n }\n }\n\n if (contentRequirement === 'header') {\n const headerFile = await fetchHeaderOnly({\n collectionSlug,\n file: providerFile,\n req,\n uploadConfig,\n })\n if (headerFile) {\n rememberVerifiedOriginal()\n return { ...headerFile, name: file.filename }\n }\n // The header wasn't enough to determine the image's dimensions - fall through to a full fetch.\n }\n\n const response = await fetchUploadResponse({\n collectionSlug,\n file: providerFile,\n req,\n uploadConfig,\n })\n\n const tempFilePath = await streamResponseToTempFile({ req, response })\n if ((await stat(tempFilePath)).size !== file.size) {\n await rm(tempFilePath, { force: true })\n throw new APIError('Uploaded source size does not match the declared size.', 400)\n }\n req.context ??= {}\n req.context._payloadClientUploadTempFile = true\n rememberVerifiedOriginal()\n\n return {\n name: file.filename,\n data: Buffer.alloc(0),\n mimetype: response.headers.get('Content-Type') || file.mimeType,\n size: file.size,\n tempFilePath,\n uploadReference: file.uploadReference,\n }\n}\n\n/**\n * Whether the request's `uploadEdits` query param carries a crop or resize edit - reads the raw\n * `req.query.uploadEdits`, since a full parse (with its `data`/`originalDoc` focal-point\n * fallback, done in generateFileData.ts) isn't available yet at this point in the request\n * lifecycle.\n */\nconst requestHasSizeEdits = (req: PayloadRequest): boolean => {\n const uploadEdits = req.query?.uploadEdits\n if (typeof uploadEdits !== 'object' || uploadEdits === null) {\n return false\n }\n\n return hasCropOrResizeEdit(uploadEdits as UploadEdits)\n}\n\n/**\n * Whether a transformer that reads the whole file will run `transformFile` on this upload. A\n * bridge transformer (e.g. `sharpTransformer`) is excluded: it projects what it needs onto the\n * sanitized upload config (`hasImageAdjustments`, `variants`) at startup instead.\n */\nconst hasTransformFileStages = async ({\n collectionSlug,\n mimeType,\n req,\n}: {\n collectionSlug: string\n mimeType: string\n req: PayloadRequest\n}): Promise<boolean> => {\n const transformers = req.payload.config.upload?.transformers ?? []\n\n if (transformers.length === 0) {\n return false\n }\n\n const pipeline = await planTransformerPipeline({\n args: { collectionSlug, mimeType, operation: 'upload', req },\n capability: 'transformFile',\n transformers,\n })\n\n return pipeline.some((transformer) => !getUploadTransformerInternal(transformer)?.prepareUpload)\n}\n\n/**\n * Fetches only the first `HEADER_PROBE_BYTE_LENGTH` bytes of the upload (via a best-effort byte\n * range request) and uses them to probe an image's dimensions, without downloading the rest of\n * the file. Returns null if that isn't enough to determine the dimensions, so the caller can\n * fall back to a full fetch.\n */\nconst fetchHeaderOnly = async ({\n collectionSlug,\n file,\n req,\n uploadConfig,\n}: {\n collectionSlug: string\n file: UploadInstructions['file']\n req: PayloadRequest\n uploadConfig: SanitizedUploadConfig\n}): Promise<NonNullable<PayloadRequest['file']> | null> => {\n const response = await fetchUploadResponse({\n collectionSlug,\n file,\n rangeHeader: `bytes=0-${HEADER_PROBE_BYTE_LENGTH - 1}`,\n req,\n uploadConfig,\n })\n assertProviderFileSize({ expectedSize: file.size, response })\n\n const headerBuffer = await readBoundedPrefix(response, HEADER_PROBE_BYTE_LENGTH)\n\n try {\n await getImageSize({\n file: {\n name: file.filename,\n data: headerBuffer,\n mimetype: file.mimeType,\n size: file.size,\n },\n })\n } catch {\n return null\n }\n\n return {\n name: file.filename,\n data: headerBuffer,\n mimetype: response.headers.get('Content-Type') || file.mimeType,\n size: file.size,\n uploadReference: file.uploadReference,\n }\n}\n\nconst assertProviderFileSize = ({\n expectedSize,\n response,\n}: {\n expectedSize: number\n response: Response\n}): void => {\n const contentRange = response.headers.get('Content-Range')\n const reportedSize =\n response.status === 206\n ? contentRange?.match(/^bytes \\d+-\\d+\\/(\\d+)$/)?.[1]\n : response.headers.get('Content-Length')\n\n if (\n reportedSize === undefined ||\n reportedSize === null ||\n Number(reportedSize) !== expectedSize\n ) {\n throw new APIError('Uploaded source size does not match the declared size.', 400)\n }\n}\n\n/**\n * Runs the collection's upload handlers, following a single redirect if one is returned.\n * `rangeHeader`, when passed, is a best-effort hint - handlers that ignore it simply return the\n * full file, which callers must still bound their own reads against.\n */\nconst fetchUploadResponse = async ({\n collectionSlug,\n file,\n rangeHeader,\n req,\n uploadConfig,\n}: {\n collectionSlug: string\n file: UploadInstructions['file']\n rangeHeader?: string\n req: PayloadRequest\n uploadConfig: SanitizedUploadConfig\n}): Promise<Response> => {\n const scopedReq = rangeHeader ? withRangeHeader(req, rangeHeader) : req\n\n let response: null | Response = null\n let error: unknown\n\n for (const handler of uploadConfig.handlers!) {\n try {\n const result = await handler(scopedReq, {\n doc: null!,\n params: {\n collection: collectionSlug,\n filename: file.filename,\n uploadReference: file.uploadReference,\n },\n })\n if (result) {\n response = result\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 *\n * @see packages/payload/src/uploads/types.ts\n */\n break\n }\n } catch (err) {\n error = err\n }\n }\n\n if (!response) {\n if (error) {\n req.payload.logger.error(error)\n }\n\n throw new APIError('Expected response from the upload handler.')\n }\n\n if (response.status >= 300 && response.status < 400) {\n const redirectUrl = response.headers.get('Location')\n if (redirectUrl) {\n response = await fetch(redirectUrl, {\n ...(rangeHeader && { headers: { Range: rangeHeader } }),\n })\n }\n }\n\n if (!response.ok) {\n throw new APIError('Uploaded source is not readable.', 400)\n }\n\n return response\n}\n\n/**\n * Overrides `req.headers` with a `Range` header while leaving the real incoming request\n * untouched. Uses a Proxy, rather than cloning `req`, because `req` is a native `Request`\n * instance at runtime - accessors like `.signal` are brand-checked against `req`'s internal\n * slots, so a plain clone (e.g. `Object.create(req)`) throws once a handler reads one of them.\n * Forwarding reads through `Reflect.get(req, prop, req)` keeps `this` bound to the real `req`\n * so those accessors keep working.\n */\nconst withRangeHeader = (req: PayloadRequest, rangeHeader: string): PayloadRequest => {\n const headers = new Headers(req.headers)\n headers.set('range', rangeHeader)\n\n return new Proxy(req, {\n get(target, prop) {\n return prop === 'headers' ? headers : Reflect.get(target, prop, target)\n },\n })\n}\n\n/**\n * Reads at most `maxBytes` from the response body, then cancels the reader - so a handler that\n * ignores the range hint and starts streaming the whole file is still cut short on our end.\n */\nconst readBoundedPrefix = async (response: Response, maxBytes: number): Promise<Buffer> => {\n if (!response.body) {\n return Buffer.alloc(0)\n }\n\n const reader = response.body.getReader()\n const chunks: Buffer[] = []\n let total = 0\n\n try {\n while (total < maxBytes) {\n const { done, value } = await reader.read()\n if (done || !value) {\n break\n }\n\n const remaining = maxBytes - total\n const chunk = value.byteLength > remaining ? value.subarray(0, remaining) : value\n chunks.push(Buffer.from(chunk))\n total += chunk.byteLength\n }\n } finally {\n await reader.cancel().catch(() => {})\n }\n\n return Buffer.concat(chunks, total)\n}\n\n/**\n * Streams the fetched upload straight to disk instead of buffering it in memory. A client upload\n * (e.g. Azure's chunkLargeFiles) can be far larger than the server's available memory, so this\n * avoids re-downloading the whole file into a single in-memory buffer just to read it back out.\n */\nconst streamResponseToTempFile = async ({\n req,\n response,\n}: {\n req: PayloadRequest\n response: Response\n}): Promise<string> => {\n if (!response.body) {\n throw new APIError('Expected a response body from the upload handler.')\n }\n\n const tempFileDir = req.payload.config.upload?.tempFileDir || os.tmpdir()\n await mkdir(tempFileDir, { recursive: true })\n const tempFilePath = path.join(tempFileDir, `payload-client-upload-${randomUUID()}`)\n\n try {\n await pipeline(\n Readable.fromWeb(response.body as ReadableStream<Uint8Array>),\n fs.createWriteStream(tempFilePath),\n )\n } catch (error) {\n await rm(tempFilePath, { force: true })\n throw error\n }\n\n return tempFilePath\n}\n"],"names":["randomUUID","fs","mkdir","rm","stat","os","path","Readable","pipeline","APIError","sanitizeFilename","sanitizeUploadPrefix","verifyClientUploadReceipt","docWithFilenameExists","getOriginalFilename","normalizeStorageKey","getFileContentRequirement","HEADER_PROBE_BYTE_LENGTH","getImageSize","hasCropOrResizeEdit","getStagedFile","planTransformerPipeline","getUploadTransformerInternal","getFileFromUploadInstructions","collectionSlug","file","req","context","_payloadVerifiedProviderOriginal","filename","mimeType","Number","isSafeInteger","size","uploadReference","Array","isArray","uploadConfig","payload","collections","config","upload","allowOverwrite","providerFilename","verifiedOriginal","uploadInstructions","requiresUploadReceipt","signedReceipt","undefined","receipt","originalFilename","storageFilePath","key","expectedKeySuffix","filePrefix","_objectKey","filter","Boolean","join","posix","basename","endsWith","prefix","sanitizedFilename","matchAnyPrefix","handlers","contentRequirement","hasSizeEdits","requestHasSizeEdits","hasTransformFileStages","providerFile","rememberVerifiedOriginal","response","fetchUploadResponse","rangeHeader","assertProviderFileSize","expectedSize","readBoundedPrefix","length","name","data","Buffer","alloc","mimetype","headerFile","fetchHeaderOnly","tempFilePath","streamResponseToTempFile","force","_payloadClientUploadTempFile","headers","get","uploadEdits","query","transformers","args","operation","capability","some","transformer","prepareUpload","headerBuffer","contentRange","reportedSize","status","match","scopedReq","withRangeHeader","error","handler","result","doc","params","collection","err","logger","redirectUrl","fetch","Range","ok","Headers","set","Proxy","target","prop","Reflect","maxBytes","body","reader","getReader","chunks","total","done","value","read","remaining","chunk","byteLength","subarray","push","from","cancel","catch","concat","tempFileDir","tmpdir","recursive","fromWeb","createWriteStream"],"mappings":"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"}
1
+ {"version":3,"sources":["../../src/uploads/getFileFromUploadInstructions.ts"],"sourcesContent":["import type { ReadableStream } from 'node:stream/web'\n\nimport { randomUUID } from 'node:crypto'\nimport fs from 'node:fs'\nimport { mkdir, rm, stat } from 'node:fs/promises'\nimport os from 'node:os'\nimport path from 'node:path'\nimport { Readable } from 'node:stream'\nimport { pipeline } from 'node:stream/promises'\n\nimport type { PayloadRequest } from '../types/index.js'\nimport type { SanitizedUploadConfig, UploadEdits, UploadInstructions } from './types.js'\n\nimport { APIError } from '../errors/APIError.js'\nimport { sanitizeFilename } from '../utilities/sanitizeFilename.js'\nimport { sanitizeUploadPrefix } from '../utilities/sanitizeUploadPrefix.js'\nimport { verifyClientUploadReceipt } from './clientUploadReceipt.js'\nimport { docWithFilenameExists } from './docWithFilenameExists.js'\nimport { getOriginalFilename, normalizeStorageKey } from './fileVersioning/naming.js'\nimport { getFileContentRequirement, HEADER_PROBE_BYTE_LENGTH } from './getFileContentRequirement.js'\nimport { getImageSize } from './getImageSize.js'\nimport { hasCropOrResizeEdit } from './hasCropOrResizeEdit.js'\nimport { getStagedFile } from './stagedUpload.js'\nimport { planTransformerPipeline } from './transformers/planTransformerPipeline.js'\nimport { getUploadTransformerInternal } from './transformers/uploadTransformerBridge.js'\n\nexport const getFileFromUploadInstructions = async ({\n collectionSlug,\n file,\n req,\n}: {\n collectionSlug: string\n file: UploadInstructions['file']\n req: PayloadRequest\n}): Promise<NonNullable<PayloadRequest['file']>> => {\n if (req.context) {\n delete req.context._payloadVerifiedProviderOriginal\n }\n\n if (\n !file ||\n typeof file !== 'object' ||\n typeof file.filename !== 'string' ||\n typeof file.mimeType !== 'string' ||\n !Number.isSafeInteger(file.size) ||\n file.size < 0 ||\n !file.uploadReference ||\n typeof file.uploadReference !== 'object' ||\n Array.isArray(file.uploadReference)\n ) {\n throw new APIError('Invalid upload reference.', 400)\n }\n\n /**\n * Handlers fetch files uploaded to a storage provider. An uploadId points to a temporary file\n * already stored by Payload, so no handler is needed.\n */\n if ('uploadId' in file.uploadReference) {\n return getStagedFile({ collectionSlug, req, uploadReference: file.uploadReference })\n }\n\n const uploadConfig = req.payload.collections[collectionSlug]!.config.upload\n let allowOverwrite = false\n let providerFilename = file.filename\n let verifiedOriginal:\n | {\n _objectKey?: string\n filename: string\n key: string\n prefix?: string\n signedReceipt: string\n }\n | undefined\n\n if (uploadConfig?.uploadInstructions?.requiresUploadReceipt) {\n const signedReceipt =\n 'signedReceipt' in file.uploadReference ? file.uploadReference.signedReceipt : undefined\n const receipt = verifyClientUploadReceipt({\n collectionSlug,\n filename: file.filename,\n req,\n signedReceipt,\n })\n allowOverwrite = receipt.allowOverwrite === true\n let originalFilename: string\n let storageFilePath: string\n\n try {\n originalFilename = getOriginalFilename({ filename: file.filename })\n storageFilePath = normalizeStorageKey({ key: receipt.storageFilePath })\n } catch {\n throw new APIError('Invalid upload reference.', 400)\n }\n\n const expectedKeySuffix = [receipt.filePrefix, receipt._objectKey, originalFilename]\n .filter(Boolean)\n .join('/')\n\n if (\n (!allowOverwrite &&\n (!receipt._objectKey ||\n path.posix.basename(storageFilePath) !== originalFilename ||\n !`/${storageFilePath}`.endsWith(`/${expectedKeySuffix}`))) ||\n ('prefix' in file.uploadReference && file.uploadReference.prefix !== receipt.filePrefix) ||\n ('_objectKey' in file.uploadReference &&\n file.uploadReference._objectKey !== receipt._objectKey)\n ) {\n throw new APIError('Invalid upload reference.', 400)\n }\n\n providerFilename = allowOverwrite ? file.filename : originalFilename\n if (!allowOverwrite) {\n verifiedOriginal = {\n _objectKey: receipt._objectKey,\n filename: originalFilename,\n key: storageFilePath,\n prefix: receipt.filePrefix,\n signedReceipt: signedReceipt as string,\n }\n }\n file = {\n ...file,\n uploadReference: {\n _objectKey: receipt._objectKey,\n prefix: receipt.filePrefix,\n signedReceipt,\n },\n }\n }\n\n const prefix =\n 'prefix' in file.uploadReference && typeof file.uploadReference.prefix === 'string'\n ? file.uploadReference.prefix\n : undefined\n\n let sanitizedFilename: string\n\n try {\n sanitizedFilename = sanitizeFilename(file.filename)\n } catch {\n throw new APIError('Invalid upload reference.', 400)\n }\n\n if (\n sanitizedFilename !== file.filename ||\n (typeof prefix === 'string' && sanitizeUploadPrefix(prefix) !== prefix)\n ) {\n throw new APIError('Invalid upload reference.', 400)\n }\n\n // Provider-backed references are submitted with the document request. They may only claim a\n // new object identity; existing top-level and generated filenames already belong to another\n // document and must continue through that document's read access checks.\n if (\n !allowOverwrite &&\n (await docWithFilenameExists({\n collectionSlug,\n filename: file.filename,\n matchAnyPrefix: true,\n path: '',\n prefix,\n req,\n }))\n ) {\n throw new APIError('Invalid upload reference.', 400)\n }\n\n if (!uploadConfig || !uploadConfig.handlers) {\n throw new APIError('uploadConfig.handlers is not present for ' + collectionSlug)\n }\n\n const contentRequirement = getFileContentRequirement({\n hasSizeEdits: requestHasSizeEdits(req),\n hasTransformFileStages: await hasTransformFileStages({\n collectionSlug,\n mimeType: file.mimeType,\n req,\n }),\n mimeType: file.mimeType,\n uploadConfig,\n })\n const providerFile = { ...file, filename: providerFilename }\n const rememberVerifiedOriginal = () => {\n if (verifiedOriginal) {\n req.context ??= {}\n req.context._payloadVerifiedProviderOriginal = verifiedOriginal\n }\n }\n\n // Nothing downstream reads this file's content - use the client-reported metadata directly\n // instead of re-downloading a file that, for a chunked upload, can be far larger than\n // the server's available memory or disk.\n if (contentRequirement === 'none') {\n const response = await fetchUploadResponse({\n collectionSlug,\n file: providerFile,\n rangeHeader: file.size > 0 ? 'bytes=0-0' : undefined,\n req,\n uploadConfig,\n })\n assertProviderFileSize({ expectedSize: file.size, response })\n const prefix = await readBoundedPrefix(response, 1)\n if (file.size > 0 && prefix.length === 0) {\n throw new APIError('Uploaded source is not readable.', 400)\n }\n rememberVerifiedOriginal()\n\n return {\n name: file.filename,\n data: Buffer.alloc(0),\n mimetype: file.mimeType,\n size: file.size,\n uploadReference: file.uploadReference,\n }\n }\n\n if (contentRequirement === 'header') {\n const headerFile = await fetchHeaderOnly({\n collectionSlug,\n file: providerFile,\n req,\n uploadConfig,\n })\n if (headerFile) {\n rememberVerifiedOriginal()\n return { ...headerFile, name: file.filename }\n }\n // The header wasn't enough to determine the image's dimensions - fall through to a full fetch.\n }\n\n const response = await fetchUploadResponse({\n collectionSlug,\n file: providerFile,\n req,\n uploadConfig,\n })\n\n const tempFilePath = await streamResponseToTempFile({ req, response })\n if ((await stat(tempFilePath)).size !== file.size) {\n await rm(tempFilePath, { force: true })\n throw new APIError('Uploaded source size does not match the declared size.', 400)\n }\n req.context ??= {}\n req.context._payloadClientUploadTempFile = true\n rememberVerifiedOriginal()\n\n return {\n name: file.filename,\n data: Buffer.alloc(0),\n mimetype: response.headers.get('Content-Type') || file.mimeType,\n size: file.size,\n tempFilePath,\n uploadReference: file.uploadReference,\n }\n}\n\n/**\n * Whether the request's `uploadEdits` query param carries a crop or resize edit - reads the raw\n * `req.query.uploadEdits`, since a full parse (with its `data`/`originalDoc` focal-point\n * fallback, done in generateFileData.ts) isn't available yet at this point in the request\n * lifecycle.\n */\nconst requestHasSizeEdits = (req: PayloadRequest): boolean => {\n const uploadEdits = req.query?.uploadEdits\n if (typeof uploadEdits !== 'object' || uploadEdits === null) {\n return false\n }\n\n return hasCropOrResizeEdit(uploadEdits)\n}\n\n/**\n * Whether a transformer that reads the whole file will run `transformFile` on this upload. A\n * bridge transformer (e.g. `sharpTransformer`) is excluded: it projects what it needs onto the\n * sanitized upload config (`hasImageAdjustments`, `variants`) at startup instead.\n */\nconst hasTransformFileStages = async ({\n collectionSlug,\n mimeType,\n req,\n}: {\n collectionSlug: string\n mimeType: string\n req: PayloadRequest\n}): Promise<boolean> => {\n const transformers = req.payload.config.upload?.transformers ?? []\n\n if (transformers.length === 0) {\n return false\n }\n\n const pipeline = await planTransformerPipeline({\n args: { collectionSlug, mimeType, operation: 'upload', req },\n capability: 'transformFile',\n transformers,\n })\n\n return pipeline.some((transformer) => !getUploadTransformerInternal(transformer)?.prepareUpload)\n}\n\n/**\n * Fetches only the first `HEADER_PROBE_BYTE_LENGTH` bytes of the upload (via a best-effort byte\n * range request) and uses them to probe an image's dimensions, without downloading the rest of\n * the file. Returns null if that isn't enough to determine the dimensions, so the caller can\n * fall back to a full fetch.\n */\nconst fetchHeaderOnly = async ({\n collectionSlug,\n file,\n req,\n uploadConfig,\n}: {\n collectionSlug: string\n file: UploadInstructions['file']\n req: PayloadRequest\n uploadConfig: SanitizedUploadConfig\n}): Promise<NonNullable<PayloadRequest['file']> | null> => {\n const response = await fetchUploadResponse({\n collectionSlug,\n file,\n rangeHeader: `bytes=0-${HEADER_PROBE_BYTE_LENGTH - 1}`,\n req,\n uploadConfig,\n })\n assertProviderFileSize({ expectedSize: file.size, response })\n\n const headerBuffer = await readBoundedPrefix(response, HEADER_PROBE_BYTE_LENGTH)\n\n try {\n await getImageSize({\n file: {\n name: file.filename,\n data: headerBuffer,\n mimetype: file.mimeType,\n size: file.size,\n },\n })\n } catch {\n return null\n }\n\n return {\n name: file.filename,\n data: headerBuffer,\n mimetype: response.headers.get('Content-Type') || file.mimeType,\n size: file.size,\n uploadReference: file.uploadReference,\n }\n}\n\nconst assertProviderFileSize = ({\n expectedSize,\n response,\n}: {\n expectedSize: number\n response: Response\n}): void => {\n const contentRange = response.headers.get('Content-Range')\n const reportedSize =\n response.status === 206\n ? contentRange?.match(/^bytes \\d+-\\d+\\/(\\d+)$/)?.[1]\n : response.headers.get('Content-Length')\n\n if (\n reportedSize === undefined ||\n reportedSize === null ||\n Number(reportedSize) !== expectedSize\n ) {\n throw new APIError('Uploaded source size does not match the declared size.', 400)\n }\n}\n\n/**\n * Runs the collection's upload handlers, following a single redirect if one is returned.\n * `rangeHeader`, when passed, is a best-effort hint - handlers that ignore it simply return the\n * full file, which callers must still bound their own reads against.\n */\nconst fetchUploadResponse = async ({\n collectionSlug,\n file,\n rangeHeader,\n req,\n uploadConfig,\n}: {\n collectionSlug: string\n file: UploadInstructions['file']\n rangeHeader?: string\n req: PayloadRequest\n uploadConfig: SanitizedUploadConfig\n}): Promise<Response> => {\n const scopedReq = rangeHeader ? withRangeHeader(req, rangeHeader) : req\n\n let response: null | Response = null\n let error: unknown\n\n for (const handler of uploadConfig.handlers!) {\n try {\n const result = await handler(scopedReq, {\n doc: null!,\n params: {\n collection: collectionSlug,\n filename: file.filename,\n uploadReference: file.uploadReference,\n },\n })\n if (result) {\n response = result\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 *\n * @see packages/payload/src/uploads/types.ts\n */\n break\n }\n } catch (err) {\n error = err\n }\n }\n\n if (!response) {\n if (error) {\n req.payload.logger.error(error)\n }\n\n throw new APIError('Expected response from the upload handler.')\n }\n\n if (response.status >= 300 && response.status < 400) {\n const redirectUrl = response.headers.get('Location')\n if (redirectUrl) {\n response = await fetch(redirectUrl, {\n ...(rangeHeader && { headers: { Range: rangeHeader } }),\n })\n }\n }\n\n if (!response.ok) {\n throw new APIError('Uploaded source is not readable.', 400)\n }\n\n return response\n}\n\n/**\n * Overrides `req.headers` with a `Range` header while leaving the real incoming request\n * untouched. Uses a Proxy, rather than cloning `req`, because `req` is a native `Request`\n * instance at runtime - accessors like `.signal` are brand-checked against `req`'s internal\n * slots, so a plain clone (e.g. `Object.create(req)`) throws once a handler reads one of them.\n * Forwarding reads through `Reflect.get(req, prop, req)` keeps `this` bound to the real `req`\n * so those accessors keep working.\n */\nconst withRangeHeader = (req: PayloadRequest, rangeHeader: string): PayloadRequest => {\n const headers = new Headers(req.headers)\n headers.set('range', rangeHeader)\n\n return new Proxy(req, {\n get(target, prop) {\n return prop === 'headers' ? headers : Reflect.get(target, prop, target)\n },\n })\n}\n\n/**\n * Reads at most `maxBytes` from the response body, then cancels the reader - so a handler that\n * ignores the range hint and starts streaming the whole file is still cut short on our end.\n */\nconst readBoundedPrefix = async (response: Response, maxBytes: number): Promise<Buffer> => {\n if (!response.body) {\n return Buffer.alloc(0)\n }\n\n const reader = response.body.getReader()\n const chunks: Buffer[] = []\n let total = 0\n\n try {\n while (total < maxBytes) {\n const { done, value } = await reader.read()\n if (done || !value) {\n break\n }\n\n const remaining = maxBytes - total\n const chunk = value.byteLength > remaining ? value.subarray(0, remaining) : value\n chunks.push(Buffer.from(chunk))\n total += chunk.byteLength\n }\n } finally {\n await reader.cancel().catch(() => {})\n }\n\n return Buffer.concat(chunks, total)\n}\n\n/**\n * Streams the fetched upload straight to disk instead of buffering it in memory. A client upload\n * (e.g. Azure's chunkLargeFiles) can be far larger than the server's available memory, so this\n * avoids re-downloading the whole file into a single in-memory buffer just to read it back out.\n */\nconst streamResponseToTempFile = async ({\n req,\n response,\n}: {\n req: PayloadRequest\n response: Response\n}): Promise<string> => {\n if (!response.body) {\n throw new APIError('Expected a response body from the upload handler.')\n }\n\n const tempFileDir = req.payload.config.upload?.tempFileDir || os.tmpdir()\n await mkdir(tempFileDir, { recursive: true })\n const tempFilePath = path.join(tempFileDir, `payload-client-upload-${randomUUID()}`)\n\n try {\n await pipeline(\n Readable.fromWeb(response.body as ReadableStream<Uint8Array>),\n fs.createWriteStream(tempFilePath),\n )\n } catch (error) {\n await rm(tempFilePath, { force: true })\n throw error\n }\n\n return tempFilePath\n}\n"],"names":["randomUUID","fs","mkdir","rm","stat","os","path","Readable","pipeline","APIError","sanitizeFilename","sanitizeUploadPrefix","verifyClientUploadReceipt","docWithFilenameExists","getOriginalFilename","normalizeStorageKey","getFileContentRequirement","HEADER_PROBE_BYTE_LENGTH","getImageSize","hasCropOrResizeEdit","getStagedFile","planTransformerPipeline","getUploadTransformerInternal","getFileFromUploadInstructions","collectionSlug","file","req","context","_payloadVerifiedProviderOriginal","filename","mimeType","Number","isSafeInteger","size","uploadReference","Array","isArray","uploadConfig","payload","collections","config","upload","allowOverwrite","providerFilename","verifiedOriginal","uploadInstructions","requiresUploadReceipt","signedReceipt","undefined","receipt","originalFilename","storageFilePath","key","expectedKeySuffix","filePrefix","_objectKey","filter","Boolean","join","posix","basename","endsWith","prefix","sanitizedFilename","matchAnyPrefix","handlers","contentRequirement","hasSizeEdits","requestHasSizeEdits","hasTransformFileStages","providerFile","rememberVerifiedOriginal","response","fetchUploadResponse","rangeHeader","assertProviderFileSize","expectedSize","readBoundedPrefix","length","name","data","Buffer","alloc","mimetype","headerFile","fetchHeaderOnly","tempFilePath","streamResponseToTempFile","force","_payloadClientUploadTempFile","headers","get","uploadEdits","query","transformers","args","operation","capability","some","transformer","prepareUpload","headerBuffer","contentRange","reportedSize","status","match","scopedReq","withRangeHeader","error","handler","result","doc","params","collection","err","logger","redirectUrl","fetch","Range","ok","Headers","set","Proxy","target","prop","Reflect","maxBytes","body","reader","getReader","chunks","total","done","value","read","remaining","chunk","byteLength","subarray","push","from","cancel","catch","concat","tempFileDir","tmpdir","recursive","fromWeb","createWriteStream"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"getSafeFilename.d.ts","sourceRoot":"","sources":["../../src/uploads/getSafeFilename.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAA;AAKvD;;;;;;GAMG;AACH,eAAO,MAAM,aAAa,SAAU,MAAM,KAAG,MAiB5C,CAAA;AAED,KAAK,IAAI,GAAG;IACV,cAAc,EAAE,MAAM,CAAA;IACtB,eAAe,EAAE,MAAM,CAAA;IACvB,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,GAAG,EAAE,cAAc,CAAA;IACnB;;;;OAIG;IACH,UAAU,CAAC,EAAE,MAAM,CAAA;CACpB,CAAA;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAsB,eAAe,CAAC,EACpC,cAAc,EACd,eAAe,EACf,MAAM,EACN,GAAG,EACH,UAAU,GACX,EAAE,IAAI,GAAG,OAAO,CAAC,MAAM,CAAC,CAiBxB"}
1
+ {"version":3,"file":"getSafeFilename.d.ts","sourceRoot":"","sources":["../../src/uploads/getSafeFilename.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAA;AAKvD;;;;;;GAMG;AACH,eAAO,MAAM,aAAa,SAAU,MAAM,KAAG,MAe5C,CAAA;AAED,KAAK,IAAI,GAAG;IACV,cAAc,EAAE,MAAM,CAAA;IACtB,eAAe,EAAE,MAAM,CAAA;IACvB,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,GAAG,EAAE,cAAc,CAAA;IACnB;;;;OAIG;IACH,UAAU,CAAC,EAAE,MAAM,CAAA;CACpB,CAAA;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAsB,eAAe,CAAC,EACpC,cAAc,EACd,eAAe,EACf,MAAM,EACN,GAAG,EACH,UAAU,GACX,EAAE,IAAI,GAAG,OAAO,CAAC,MAAM,CAAC,CAiBxB"}
@@ -8,10 +8,8 @@ import { fileExists } from './fileExists.js';
8
8
  * incrementName('file-1.jpg') // 'file-2.jpg'
9
9
  * incrementName('file-99.jpg') // 'file-100.jpg'
10
10
  */ export const incrementName = (name)=>{
11
- const extensionSeparatorIndex = name.lastIndexOf('.');
12
- const hasExtension = extensionSeparatorIndex > 0 && extensionSeparatorIndex < name.length - 1;
13
- const extension = hasExtension ? name.slice(extensionSeparatorIndex + 1) : undefined;
14
- const baseFilename = sanitize(hasExtension ? name.slice(0, extensionSeparatorIndex) : name);
11
+ const extension = name.split('.').pop();
12
+ const baseFilename = sanitize(name.substring(0, name.lastIndexOf('.')) || name);
15
13
  let incrementedName = baseFilename;
16
14
  const regex = /(.*)-(\d+)$/;
17
15
  const found = baseFilename.match(regex);
@@ -23,7 +21,7 @@ import { fileExists } from './fileExists.js';
23
21
  const incremented = Number(matchedNumber) + 1;
24
22
  incrementedName = `${matchedName}-${incremented}`;
25
23
  }
26
- return extension ? `${incrementedName}.${extension}` : incrementedName;
24
+ return `${incrementedName}.${extension}`;
27
25
  };
28
26
  /**
29
27
  * Generates a safe, unique filename by checking for conflicts in the database
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/uploads/getSafeFilename.ts"],"sourcesContent":["import sanitize from 'sanitize-filename'\n\nimport type { PayloadRequest } from '../types/index.js'\n\nimport { docWithFilenameExists } from './docWithFilenameExists.js'\nimport { fileExists } from './fileExists.js'\n\n/**\n * Increments a filename by appending or incrementing a numeric suffix.\n * @example\n * incrementName('file.jpg') // 'file-1.jpg'\n * incrementName('file-1.jpg') // 'file-2.jpg'\n * incrementName('file-99.jpg') // 'file-100.jpg'\n */\nexport const incrementName = (name: string): string => {\n const extensionSeparatorIndex = name.lastIndexOf('.')\n const hasExtension = extensionSeparatorIndex > 0 && extensionSeparatorIndex < name.length - 1\n const extension = hasExtension ? name.slice(extensionSeparatorIndex + 1) : undefined\n const baseFilename = sanitize(hasExtension ? name.slice(0, extensionSeparatorIndex) : name)\n let incrementedName = baseFilename\n const regex = /(.*)-(\\d+)$/\n const found = baseFilename.match(regex)\n if (found === null) {\n incrementedName += '-1'\n } else {\n const matchedName = found[1]\n const matchedNumber = found[2]\n const incremented = Number(matchedNumber) + 1\n incrementedName = `${matchedName}-${incremented}`\n }\n return extension ? `${incrementedName}.${extension}` : incrementedName\n}\n\ntype Args = {\n collectionSlug: string\n desiredFilename: string\n prefix?: string\n req: PayloadRequest\n /**\n * Filesystem path where uploads are stored. When omitted, only the database\n * is consulted for filename conflicts - useful for cloud-storage adapters\n * that have no local filesystem.\n */\n staticPath?: string\n}\n\n/**\n * Generates a safe, unique filename by checking for conflicts in the database\n * and (when a `staticPath` is provided) the local filesystem. If a conflict\n * exists, it increments a numeric suffix until a unique name is found.\n *\n * @param args.collectionSlug - The slug of the upload collection\n * @param args.desiredFilename - The original filename to make safe\n * @param args.prefix - Optional prefix path for cloud storage adapters\n * @param args.req - The Payload request object\n * @param args.staticPath - The filesystem path where uploads are stored\n * @returns A unique filename that doesn't conflict with existing files\n *\n * @example\n * // If 'photo.jpg' already exists, returns 'photo-1.jpg'\n * const safeName = await getSafeFileName({\n * collectionSlug: 'media',\n * desiredFilename: 'photo.jpg',\n * req,\n * staticPath: '/uploads/media',\n * })\n */\nexport async function getSafeFileName({\n collectionSlug,\n desiredFilename,\n prefix,\n req,\n staticPath,\n}: Args): Promise<string> {\n let modifiedFilename = desiredFilename\n\n while (\n (await docWithFilenameExists({\n collectionSlug,\n filename: modifiedFilename,\n path: staticPath ?? '',\n prefix,\n req,\n })) ||\n (staticPath ? await fileExists(`${staticPath}/${modifiedFilename}`) : false)\n ) {\n modifiedFilename = incrementName(modifiedFilename)\n }\n\n return modifiedFilename\n}\n"],"names":["sanitize","docWithFilenameExists","fileExists","incrementName","name","extensionSeparatorIndex","lastIndexOf","hasExtension","length","extension","slice","undefined","baseFilename","incrementedName","regex","found","match","matchedName","matchedNumber","incremented","Number","getSafeFileName","collectionSlug","desiredFilename","prefix","req","staticPath","modifiedFilename","filename","path"],"mappings":"AAAA,OAAOA,cAAc,oBAAmB;AAIxC,SAASC,qBAAqB,QAAQ,6BAA4B;AAClE,SAASC,UAAU,QAAQ,kBAAiB;AAE5C;;;;;;CAMC,GACD,OAAO,MAAMC,gBAAgB,CAACC;IAC5B,MAAMC,0BAA0BD,KAAKE,WAAW,CAAC;IACjD,MAAMC,eAAeF,0BAA0B,KAAKA,0BAA0BD,KAAKI,MAAM,GAAG;IAC5F,MAAMC,YAAYF,eAAeH,KAAKM,KAAK,CAACL,0BAA0B,KAAKM;IAC3E,MAAMC,eAAeZ,SAASO,eAAeH,KAAKM,KAAK,CAAC,GAAGL,2BAA2BD;IACtF,IAAIS,kBAAkBD;IACtB,MAAME,QAAQ;IACd,MAAMC,QAAQH,aAAaI,KAAK,CAACF;IACjC,IAAIC,UAAU,MAAM;QAClBF,mBAAmB;IACrB,OAAO;QACL,MAAMI,cAAcF,KAAK,CAAC,EAAE;QAC5B,MAAMG,gBAAgBH,KAAK,CAAC,EAAE;QAC9B,MAAMI,cAAcC,OAAOF,iBAAiB;QAC5CL,kBAAkB,GAAGI,YAAY,CAAC,EAAEE,aAAa;IACnD;IACA,OAAOV,YAAY,GAAGI,gBAAgB,CAAC,EAAEJ,WAAW,GAAGI;AACzD,EAAC;AAeD;;;;;;;;;;;;;;;;;;;;CAoBC,GACD,OAAO,eAAeQ,gBAAgB,EACpCC,cAAc,EACdC,eAAe,EACfC,MAAM,EACNC,GAAG,EACHC,UAAU,EACL;IACL,IAAIC,mBAAmBJ;IAEvB,MACE,AAAC,MAAMtB,sBAAsB;QAC3BqB;QACAM,UAAUD;QACVE,MAAMH,cAAc;QACpBF;QACAC;IACF,MACCC,CAAAA,aAAa,MAAMxB,WAAW,GAAGwB,WAAW,CAAC,EAAEC,kBAAkB,IAAI,KAAI,EAC1E;QACAA,mBAAmBxB,cAAcwB;IACnC;IAEA,OAAOA;AACT"}
1
+ {"version":3,"sources":["../../src/uploads/getSafeFilename.ts"],"sourcesContent":["import sanitize from 'sanitize-filename'\n\nimport type { PayloadRequest } from '../types/index.js'\n\nimport { docWithFilenameExists } from './docWithFilenameExists.js'\nimport { fileExists } from './fileExists.js'\n\n/**\n * Increments a filename by appending or incrementing a numeric suffix.\n * @example\n * incrementName('file.jpg') // 'file-1.jpg'\n * incrementName('file-1.jpg') // 'file-2.jpg'\n * incrementName('file-99.jpg') // 'file-100.jpg'\n */\nexport const incrementName = (name: string): string => {\n const extension = name.split('.').pop()\n const baseFilename = sanitize(name.substring(0, name.lastIndexOf('.')) || name)\n let incrementedName = baseFilename\n const regex = /(.*)-(\\d+)$/\n const found = baseFilename.match(regex)\n if (found === null) {\n incrementedName += '-1'\n } else {\n const matchedName = found[1]\n const matchedNumber = found[2]\n const incremented = Number(matchedNumber) + 1\n incrementedName = `${matchedName}-${incremented}`\n }\n return `${incrementedName}.${extension}`\n}\n\ntype Args = {\n collectionSlug: string\n desiredFilename: string\n prefix?: string\n req: PayloadRequest\n /**\n * Filesystem path where uploads are stored. When omitted, only the database\n * is consulted for filename conflicts - useful for cloud-storage adapters\n * that have no local filesystem.\n */\n staticPath?: string\n}\n\n/**\n * Generates a safe, unique filename by checking for conflicts in the database\n * and (when a `staticPath` is provided) the local filesystem. If a conflict\n * exists, it increments a numeric suffix until a unique name is found.\n *\n * @param args.collectionSlug - The slug of the upload collection\n * @param args.desiredFilename - The original filename to make safe\n * @param args.prefix - Optional prefix path for cloud storage adapters\n * @param args.req - The Payload request object\n * @param args.staticPath - The filesystem path where uploads are stored\n * @returns A unique filename that doesn't conflict with existing files\n *\n * @example\n * // If 'photo.jpg' already exists, returns 'photo-1.jpg'\n * const safeName = await getSafeFileName({\n * collectionSlug: 'media',\n * desiredFilename: 'photo.jpg',\n * req,\n * staticPath: '/uploads/media',\n * })\n */\nexport async function getSafeFileName({\n collectionSlug,\n desiredFilename,\n prefix,\n req,\n staticPath,\n}: Args): Promise<string> {\n let modifiedFilename = desiredFilename\n\n while (\n (await docWithFilenameExists({\n collectionSlug,\n filename: modifiedFilename,\n path: staticPath ?? '',\n prefix,\n req,\n })) ||\n (staticPath ? await fileExists(`${staticPath}/${modifiedFilename}`) : false)\n ) {\n modifiedFilename = incrementName(modifiedFilename)\n }\n\n return modifiedFilename\n}\n"],"names":["sanitize","docWithFilenameExists","fileExists","incrementName","name","extension","split","pop","baseFilename","substring","lastIndexOf","incrementedName","regex","found","match","matchedName","matchedNumber","incremented","Number","getSafeFileName","collectionSlug","desiredFilename","prefix","req","staticPath","modifiedFilename","filename","path"],"mappings":"AAAA,OAAOA,cAAc,oBAAmB;AAIxC,SAASC,qBAAqB,QAAQ,6BAA4B;AAClE,SAASC,UAAU,QAAQ,kBAAiB;AAE5C;;;;;;CAMC,GACD,OAAO,MAAMC,gBAAgB,CAACC;IAC5B,MAAMC,YAAYD,KAAKE,KAAK,CAAC,KAAKC,GAAG;IACrC,MAAMC,eAAeR,SAASI,KAAKK,SAAS,CAAC,GAAGL,KAAKM,WAAW,CAAC,SAASN;IAC1E,IAAIO,kBAAkBH;IACtB,MAAMI,QAAQ;IACd,MAAMC,QAAQL,aAAaM,KAAK,CAACF;IACjC,IAAIC,UAAU,MAAM;QAClBF,mBAAmB;IACrB,OAAO;QACL,MAAMI,cAAcF,KAAK,CAAC,EAAE;QAC5B,MAAMG,gBAAgBH,KAAK,CAAC,EAAE;QAC9B,MAAMI,cAAcC,OAAOF,iBAAiB;QAC5CL,kBAAkB,GAAGI,YAAY,CAAC,EAAEE,aAAa;IACnD;IACA,OAAO,GAAGN,gBAAgB,CAAC,EAAEN,WAAW;AAC1C,EAAC;AAeD;;;;;;;;;;;;;;;;;;;;CAoBC,GACD,OAAO,eAAec,gBAAgB,EACpCC,cAAc,EACdC,eAAe,EACfC,MAAM,EACNC,GAAG,EACHC,UAAU,EACL;IACL,IAAIC,mBAAmBJ;IAEvB,MACE,AAAC,MAAMpB,sBAAsB;QAC3BmB;QACAM,UAAUD;QACVE,MAAMH,cAAc;QACpBF;QACAC;IACF,MACCC,CAAAA,aAAa,MAAMtB,WAAW,GAAGsB,WAAW,CAAC,EAAEC,kBAAkB,IAAI,KAAI,EAC1E;QACAA,mBAAmBtB,cAAcsB;IACnC;IAEA,OAAOA;AACT"}
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/uploads/safeFetch.ts"],"sourcesContent":["import type { LookupFunction } from 'net'\n\nimport { lookup } from 'dns'\nimport ipaddr from 'ipaddr.js'\nimport { Agent, fetch as undiciFetch } from 'undici'\n\n/**\n * @internal this is used to mock the IP `lookup` function in integration tests\n */\nexport const _internal_safeFetchGlobal = {\n lookup,\n}\n\nconst buildBlockedFetchError = (hostname: string): Error =>\n new Error(\n `Blocked unsafe attempt to ${hostname}. This host resolves to a private or internal address. ` +\n `If this is a trusted destination, allowlist it via the upload collection's \"skipSafeFetch\" option ` +\n `(https://payloadcms.com/docs/upload/overview#skip-safe-fetch).`,\n )\n\nconst isSafeIp = (ip: string) => {\n try {\n if (!ip) {\n return false\n }\n\n if (!ipaddr.isValid(ip)) {\n return false\n }\n\n const parsedIpAddress = ipaddr.parse(ip)\n const range = parsedIpAddress.range()\n if (range !== 'unicast') {\n return false // Private IP Range\n }\n } catch (ignore) {\n return false\n }\n return true\n}\n\nconst ssrfFilterInterceptor: LookupFunction = (hostname, options, callback) => {\n _internal_safeFetchGlobal.lookup(hostname, options, (err, address, family) => {\n if (err) {\n callback(err, address, family)\n } else {\n let ips = [] as string[]\n if (Array.isArray(address)) {\n ips = address.map((a) => a.address)\n } else {\n ips = [address]\n }\n\n if (ips.some((ip) => !isSafeIp(ip))) {\n callback(buildBlockedFetchError(hostname), address, family)\n return\n }\n\n callback(null, address, family)\n }\n })\n}\n\nlet safeDispatcher: Agent | undefined\n\nconst getSafeDispatcher = (): Agent => {\n if (!safeDispatcher) {\n safeDispatcher = new Agent({ connect: { lookup: ssrfFilterInterceptor } })\n }\n return safeDispatcher\n}\n\n/**\n * A \"safe\" version of undici's fetch that prevents SSRF attacks.\n *\n * - Utilizes a custom dispatcher that filters out requests to unsafe IP addresses.\n * - Validates domain names by resolving them to IP addresses and checking if they're safe.\n * - Undici was used because it supported interceptors as well as \"credentials: include\". Native fetch\n */\nexport const safeFetch = async (...args: Parameters<typeof undiciFetch>): Promise<Response> => {\n const [unverifiedUrl, options] = args\n\n try {\n const url = new URL(unverifiedUrl)\n\n let hostname = url.hostname\n\n // Strip brackets from IPv6 addresses (e.g., \"[::1]\" => \"::1\")\n if (hostname.startsWith('[') && hostname.endsWith(']')) {\n hostname = hostname.slice(1, -1)\n }\n\n if (ipaddr.isValid(hostname)) {\n if (!isSafeIp(hostname)) {\n throw buildBlockedFetchError(hostname)\n }\n }\n return (await undiciFetch(url, {\n ...options,\n dispatcher: getSafeDispatcher(),\n redirect: 'manual', // Prevent automatic redirects\n })) as unknown as Response\n } catch (error) {\n if (error instanceof Error) {\n if (error.cause instanceof Error && error.cause.message.includes('unsafe')) {\n // Errors thrown from within interceptors always have 'fetch error' as the message\n // The desired message we want to bubble up is in the cause\n throw new Error(error.cause.message)\n } else {\n let stringifiedUrl: string | undefined = undefined\n if (typeof unverifiedUrl === 'string') {\n stringifiedUrl = unverifiedUrl\n } else if (unverifiedUrl instanceof URL) {\n stringifiedUrl = unverifiedUrl.toString()\n } else if (unverifiedUrl instanceof Request) {\n stringifiedUrl = unverifiedUrl.url\n }\n\n throw new Error(`Failed to fetch from ${stringifiedUrl}, ${error.message}`)\n }\n }\n throw error\n }\n}\n"],"names":["lookup","ipaddr","Agent","fetch","undiciFetch","_internal_safeFetchGlobal","buildBlockedFetchError","hostname","Error","isSafeIp","ip","isValid","parsedIpAddress","parse","range","ignore","ssrfFilterInterceptor","options","callback","err","address","family","ips","Array","isArray","map","a","some","safeDispatcher","getSafeDispatcher","connect","safeFetch","args","unverifiedUrl","url","URL","startsWith","endsWith","slice","dispatcher","redirect","error","cause","message","includes","stringifiedUrl","undefined","toString","Request"],"mappings":"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"}
1
+ {"version":3,"sources":["../../src/uploads/safeFetch.ts"],"sourcesContent":["import type { LookupFunction } from 'net'\n\nimport { lookup } from 'dns'\nimport ipaddr from 'ipaddr.js'\nimport { Agent, fetch as undiciFetch } from 'undici'\n\n/**\n * @internal this is used to mock the IP `lookup` function in integration tests\n */\nexport const _internal_safeFetchGlobal = {\n lookup,\n}\n\nconst buildBlockedFetchError = (hostname: string): Error =>\n new Error(\n `Blocked unsafe attempt to ${hostname}. This host resolves to a private or internal address. ` +\n `If this is a trusted destination, allowlist it via the upload collection's \"skipSafeFetch\" option ` +\n `(https://payloadcms.com/docs/upload/overview#skip-safe-fetch).`,\n )\n\nconst isSafeIp = (ip: string) => {\n try {\n if (!ip) {\n return false\n }\n\n if (!ipaddr.isValid(ip)) {\n return false\n }\n\n const parsedIpAddress = ipaddr.parse(ip)\n const range = parsedIpAddress.range()\n if (range !== 'unicast') {\n return false // Private IP Range\n }\n } catch (ignore) {\n return false\n }\n return true\n}\n\nconst ssrfFilterInterceptor: LookupFunction = (hostname, options, callback) => {\n _internal_safeFetchGlobal.lookup(hostname, options, (err, address, family) => {\n if (err) {\n callback(err, address, family)\n } else {\n let ips = [] as string[]\n if (Array.isArray(address)) {\n ips = address.map((a) => a.address)\n } else {\n ips = [address]\n }\n\n if (ips.some((ip) => !isSafeIp(ip))) {\n callback(buildBlockedFetchError(hostname), address, family)\n return\n }\n\n callback(null, address, family)\n }\n })\n}\n\nlet safeDispatcher: Agent | undefined\n\nconst getSafeDispatcher = (): Agent => {\n if (!safeDispatcher) {\n safeDispatcher = new Agent({ connect: { lookup: ssrfFilterInterceptor } })\n }\n return safeDispatcher\n}\n\n/**\n * A \"safe\" version of undici's fetch that prevents SSRF attacks.\n *\n * - Utilizes a custom dispatcher that filters out requests to unsafe IP addresses.\n * - Validates domain names by resolving them to IP addresses and checking if they're safe.\n * - Undici was used because it supported interceptors as well as \"credentials: include\". Native fetch\n */\nexport const safeFetch = async (...args: Parameters<typeof undiciFetch>): Promise<Response> => {\n const [unverifiedUrl, options] = args\n\n try {\n const url = new URL(unverifiedUrl)\n\n let hostname = url.hostname\n\n // Strip brackets from IPv6 addresses (e.g., \"[::1]\" => \"::1\")\n if (hostname.startsWith('[') && hostname.endsWith(']')) {\n hostname = hostname.slice(1, -1)\n }\n\n if (ipaddr.isValid(hostname)) {\n if (!isSafeIp(hostname)) {\n throw buildBlockedFetchError(hostname)\n }\n }\n return await undiciFetch(url, {\n ...options,\n dispatcher: getSafeDispatcher(),\n redirect: 'manual', // Prevent automatic redirects\n })\n } catch (error) {\n if (error instanceof Error) {\n if (error.cause instanceof Error && error.cause.message.includes('unsafe')) {\n // Errors thrown from within interceptors always have 'fetch error' as the message\n // The desired message we want to bubble up is in the cause\n throw new Error(error.cause.message)\n } else {\n let stringifiedUrl: string | undefined = undefined\n if (typeof unverifiedUrl === 'string') {\n stringifiedUrl = unverifiedUrl\n } else if (unverifiedUrl instanceof URL) {\n stringifiedUrl = unverifiedUrl.toString()\n } else if (unverifiedUrl instanceof Request) {\n stringifiedUrl = unverifiedUrl.url\n }\n\n throw new Error(`Failed to fetch from ${stringifiedUrl}, ${error.message}`)\n }\n }\n throw error\n }\n}\n"],"names":["lookup","ipaddr","Agent","fetch","undiciFetch","_internal_safeFetchGlobal","buildBlockedFetchError","hostname","Error","isSafeIp","ip","isValid","parsedIpAddress","parse","range","ignore","ssrfFilterInterceptor","options","callback","err","address","family","ips","Array","isArray","map","a","some","safeDispatcher","getSafeDispatcher","connect","safeFetch","args","unverifiedUrl","url","URL","startsWith","endsWith","slice","dispatcher","redirect","error","cause","message","includes","stringifiedUrl","undefined","toString","Request"],"mappings":"AAEA,SAASA,MAAM,QAAQ,MAAK;AAC5B,OAAOC,YAAY,YAAW;AAC9B,SAASC,KAAK,EAAEC,SAASC,WAAW,QAAQ,SAAQ;AAEpD;;CAEC,GACD,OAAO,MAAMC,4BAA4B;IACvCL;AACF,EAAC;AAED,MAAMM,yBAAyB,CAACC,WAC9B,IAAIC,MACF,CAAC,0BAA0B,EAAED,SAAS,uDAAuD,CAAC,GAC5F,CAAC,kGAAkG,CAAC,GACpG,CAAC,8DAA8D,CAAC;AAGtE,MAAME,WAAW,CAACC;IAChB,IAAI;QACF,IAAI,CAACA,IAAI;YACP,OAAO;QACT;QAEA,IAAI,CAACT,OAAOU,OAAO,CAACD,KAAK;YACvB,OAAO;QACT;QAEA,MAAME,kBAAkBX,OAAOY,KAAK,CAACH;QACrC,MAAMI,QAAQF,gBAAgBE,KAAK;QACnC,IAAIA,UAAU,WAAW;YACvB,OAAO,MAAM,mBAAmB;;QAClC;IACF,EAAE,OAAOC,QAAQ;QACf,OAAO;IACT;IACA,OAAO;AACT;AAEA,MAAMC,wBAAwC,CAACT,UAAUU,SAASC;IAChEb,0BAA0BL,MAAM,CAACO,UAAUU,SAAS,CAACE,KAAKC,SAASC;QACjE,IAAIF,KAAK;YACPD,SAASC,KAAKC,SAASC;QACzB,OAAO;YACL,IAAIC,MAAM,EAAE;YACZ,IAAIC,MAAMC,OAAO,CAACJ,UAAU;gBAC1BE,MAAMF,QAAQK,GAAG,CAAC,CAACC,IAAMA,EAAEN,OAAO;YACpC,OAAO;gBACLE,MAAM;oBAACF;iBAAQ;YACjB;YAEA,IAAIE,IAAIK,IAAI,CAAC,CAACjB,KAAO,CAACD,SAASC,MAAM;gBACnCQ,SAASZ,uBAAuBC,WAAWa,SAASC;gBACpD;YACF;YAEAH,SAAS,MAAME,SAASC;QAC1B;IACF;AACF;AAEA,IAAIO;AAEJ,MAAMC,oBAAoB;IACxB,IAAI,CAACD,gBAAgB;QACnBA,iBAAiB,IAAI1B,MAAM;YAAE4B,SAAS;gBAAE9B,QAAQgB;YAAsB;QAAE;IAC1E;IACA,OAAOY;AACT;AAEA;;;;;;CAMC,GACD,OAAO,MAAMG,YAAY,OAAO,GAAGC;IACjC,MAAM,CAACC,eAAehB,QAAQ,GAAGe;IAEjC,IAAI;QACF,MAAME,MAAM,IAAIC,IAAIF;QAEpB,IAAI1B,WAAW2B,IAAI3B,QAAQ;QAE3B,8DAA8D;QAC9D,IAAIA,SAAS6B,UAAU,CAAC,QAAQ7B,SAAS8B,QAAQ,CAAC,MAAM;YACtD9B,WAAWA,SAAS+B,KAAK,CAAC,GAAG,CAAC;QAChC;QAEA,IAAIrC,OAAOU,OAAO,CAACJ,WAAW;YAC5B,IAAI,CAACE,SAASF,WAAW;gBACvB,MAAMD,uBAAuBC;YAC/B;QACF;QACA,OAAO,MAAMH,YAAY8B,KAAK;YAC5B,GAAGjB,OAAO;YACVsB,YAAYV;YACZW,UAAU;QACZ;IACF,EAAE,OAAOC,OAAO;QACd,IAAIA,iBAAiBjC,OAAO;YAC1B,IAAIiC,MAAMC,KAAK,YAAYlC,SAASiC,MAAMC,KAAK,CAACC,OAAO,CAACC,QAAQ,CAAC,WAAW;gBAC1E,kFAAkF;gBAClF,2DAA2D;gBAC3D,MAAM,IAAIpC,MAAMiC,MAAMC,KAAK,CAACC,OAAO;YACrC,OAAO;gBACL,IAAIE,iBAAqCC;gBACzC,IAAI,OAAOb,kBAAkB,UAAU;oBACrCY,iBAAiBZ;gBACnB,OAAO,IAAIA,yBAAyBE,KAAK;oBACvCU,iBAAiBZ,cAAcc,QAAQ;gBACzC,OAAO,IAAId,yBAAyBe,SAAS;oBAC3CH,iBAAiBZ,cAAcC,GAAG;gBACpC;gBAEA,MAAM,IAAI1B,MAAM,CAAC,qBAAqB,EAAEqC,eAAe,EAAE,EAAEJ,MAAME,OAAO,EAAE;YAC5E;QACF;QACA,MAAMF;IACR;AACF,EAAC"}
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/uploads/stagedUpload.ts"],"sourcesContent":["import { jwtVerify } from 'jose/jwt/verify'\nimport { randomUUID } from 'node:crypto'\nimport fs from 'node:fs/promises'\nimport os from 'node:os'\nimport path from 'node:path'\n\nimport type { PayloadHandler } from '../config/types.js'\nimport type { PayloadRequest } from '../types/index.js'\nimport type { File, UploadInstructions, UploadInstructionsRequest } from './types.js'\n\nimport { jwtSign } from '../auth/jwt.js'\nimport { APIError, Forbidden } from '../errors/index.js'\nimport { formatAdminURL } from '../utilities/formatAdminURL.js'\nimport { checkFileRestrictions } from './checkFileRestrictions.js'\n\n/**\n * Creates a signed, one-hour URL where the client can send the file bytes. The returned file value\n * is later passed to a document create or update request.\n */\nexport const generateStagedUploadInstructions = async ({\n collectionSlug,\n docPrefix,\n filename,\n filesize,\n mimeType,\n req,\n}: { req: PayloadRequest } & UploadInstructionsRequest): Promise<UploadInstructions> => {\n await removeExpiredUploads(req, collectionSlug)\n\n const { token: uploadId } = await jwtSign({\n fieldsToSign: {\n id: randomUUID(),\n collectionSlug,\n docPrefix,\n filename,\n filesize,\n mimeType,\n user: getUser(req),\n },\n secret: req.payload.secret,\n tokenExpiration,\n })\n\n return {\n type: 'http',\n file: {\n filename,\n mimeType,\n size: filesize,\n uploadReference: { uploadId },\n },\n request: {\n headers: {\n 'Content-Length': String(filesize),\n 'Content-Type': mimeType,\n },\n method: 'PUT',\n url: formatAdminURL({\n apiRoute: req.payload.config.routes.api,\n path: `/upload-instructions/${uploadId}`,\n serverURL: req.payload.config.serverURL,\n }),\n },\n }\n}\n\n/**\n * Saves the bytes sent to a signed upload URL. The file is written as a partial file first and only\n * becomes available when its size exactly matches the size in the upload ID.\n */\nexport const uploadStagedFile: PayloadHandler = async (req) => {\n const upload = await verifyUploadID(req, req.routeParams?.uploadId)\n const directory = await getUploadDirectory(req, upload.collectionSlug)\n const uploadPath = path.join(directory, upload.id)\n const temporaryPath = `${uploadPath}.${randomUUID()}.part`\n const file = await fs.open(temporaryPath, 'wx')\n let uploadedSize = 0\n\n try {\n try {\n const reader = req.body?.getReader()\n\n while (reader) {\n const { done, value } = await reader.read()\n\n if (done) {\n break\n }\n\n uploadedSize += value.byteLength\n if (uploadedSize > upload.filesize) {\n throw new APIError('Uploaded file is larger than expected.', 400)\n }\n\n let offset = 0\n while (offset < value.byteLength) {\n const { bytesWritten } = await file.write(value, offset)\n offset += bytesWritten\n }\n }\n\n if (uploadedSize !== upload.filesize) {\n throw new APIError('Uploaded file size does not match the expected size.', 400)\n }\n } finally {\n await file.close()\n }\n\n const collection = req.payload.collections[upload.collectionSlug]!.config\n await checkFileRestrictions({\n collection,\n file: {\n name: upload.filename,\n data: Buffer.alloc(0),\n mimetype: upload.mimeType,\n size: upload.filesize,\n tempFilePath: temporaryPath,\n },\n req,\n })\n\n await fs.rename(temporaryPath, uploadPath)\n } catch (error) {\n await fs.rm(temporaryPath, { force: true })\n throw error\n }\n\n return new Response(null, { status: 204 })\n}\n\n/** Removes a temporary upload that the client no longer needs. */\nexport const deleteStagedFile: PayloadHandler = async (req) => {\n const upload = await verifyUploadID(req, req.routeParams?.uploadId)\n const directory = await getUploadDirectory(req, upload.collectionSlug)\n\n await fs.rm(path.join(directory, upload.id), { force: true })\n\n return new Response(null, { status: 204 })\n}\n\n/**\n * Loads a completed staged file for a document request. Only the same user and collection can use\n * it, and the temporary file is deleted after it is read.\n */\nexport const getStagedFile = async ({\n collectionSlug,\n req,\n uploadReference,\n}: {\n collectionSlug: string\n req: PayloadRequest\n uploadReference: unknown\n}): Promise<File> => {\n if (\n !uploadReference ||\n typeof uploadReference !== 'object' ||\n Array.isArray(uploadReference) ||\n !('uploadId' in uploadReference) ||\n typeof uploadReference.uploadId !== 'string'\n ) {\n throw new APIError('Invalid staged upload.', 400)\n }\n\n const { uploadId } = uploadReference\n const upload = await verifyUploadID(req, uploadId)\n\n if (upload.collectionSlug !== collectionSlug || upload.user !== getUser(req)) {\n throw new Forbidden(req.t)\n }\n\n const directory = await getUploadDirectory(req, upload.collectionSlug)\n const tempFilePath = path.join(directory, upload.id)\n let data: Buffer\n\n try {\n data = await fs.readFile(tempFilePath)\n } catch {\n throw new APIError('Staged upload was not found.', 400)\n }\n\n if (data.length !== upload.filesize) {\n await fs.rm(tempFilePath, { force: true })\n throw new APIError('Staged upload is incomplete.', 400)\n }\n\n await fs.rm(tempFilePath, { force: true })\n\n return {\n name: upload.filename,\n data,\n mimetype: upload.mimeType,\n size: data.length,\n }\n}\n\n/**\n * Staged uploads hold a file temporarily until a document create or update uses it. The signed\n * upload ID remembers which file and user the upload belongs to.\n */\nconst tokenExpiration = 60 * 60\n\n/** The file details stored inside the signed upload ID. */\ntype StagedUploadToken = {\n id: string\n user: null | string\n} & UploadInstructionsRequest\n\nconst getUser = (req: PayloadRequest) =>\n req.user ? `${req.user.collection}:${String(req.user.id)}` : null\n\n/** Returns the hidden folder where temporary uploads for this collection are stored. */\nconst getUploadDirectory = async (req: PayloadRequest, collectionSlug: string) => {\n const upload = req.payload.collections[collectionSlug]?.config.upload\n const directory = path.resolve(\n upload && !upload.disableLocalStorage\n ? upload.staticDir || collectionSlug\n : req.payload.config.upload.tempFileDir || os.tmpdir(),\n '.payload-staged-uploads',\n )\n\n await fs.mkdir(directory, { recursive: true })\n\n return directory\n}\n\n/** Removes temporary files older than the one-hour upload window. */\nconst removeExpiredUploads = async (req: PayloadRequest, collectionSlug: string) => {\n const directory = await getUploadDirectory(req, collectionSlug)\n const expiresBefore = Date.now() - tokenExpiration * 1000\n\n for (const filename of await fs.readdir(directory)) {\n const filePath = path.join(directory, filename)\n const stats = await fs.stat(filePath).catch(() => null)\n\n if (stats && stats.mtimeMs < expiresBefore) {\n await fs.rm(filePath, { force: true })\n }\n }\n}\n\n/** Verifies that an upload ID was signed by Payload, has not expired, and contains valid details. */\nconst verifyUploadID = async (\n req: PayloadRequest,\n uploadID: unknown,\n): Promise<StagedUploadToken> => {\n try {\n if (typeof uploadID !== 'string') {\n throw new Error()\n }\n\n const secret = new TextEncoder().encode(req.payload.secret)\n const { payload } = await jwtVerify<StagedUploadToken>(uploadID, secret)\n\n if (\n typeof payload.id !== 'string' ||\n !/^[\\da-f-]{36}$/i.test(payload.id) ||\n typeof payload.collectionSlug !== 'string' ||\n typeof payload.filename !== 'string' ||\n !Number.isSafeInteger(payload.filesize) ||\n payload.filesize < 0 ||\n typeof payload.mimeType !== 'string' ||\n (payload.user !== null && typeof payload.user !== 'string')\n ) {\n throw new Error()\n }\n\n return payload as StagedUploadToken\n } catch {\n throw new APIError('Invalid or expired staged upload.', 400)\n }\n}\n"],"names":["jwtVerify","randomUUID","fs","os","path","jwtSign","APIError","Forbidden","formatAdminURL","checkFileRestrictions","generateStagedUploadInstructions","collectionSlug","docPrefix","filename","filesize","mimeType","req","removeExpiredUploads","token","uploadId","fieldsToSign","id","user","getUser","secret","payload","tokenExpiration","type","file","size","uploadReference","request","headers","String","method","url","apiRoute","config","routes","api","serverURL","uploadStagedFile","upload","verifyUploadID","routeParams","directory","getUploadDirectory","uploadPath","join","temporaryPath","open","uploadedSize","reader","body","getReader","done","value","read","byteLength","offset","bytesWritten","write","close","collection","collections","name","data","Buffer","alloc","mimetype","tempFilePath","rename","error","rm","force","Response","status","deleteStagedFile","getStagedFile","Array","isArray","t","readFile","length","resolve","disableLocalStorage","staticDir","tempFileDir","tmpdir","mkdir","recursive","expiresBefore","Date","now","readdir","filePath","stats","stat","catch","mtimeMs","uploadID","Error","TextEncoder","encode","test","Number","isSafeInteger"],"mappings":"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"}
1
+ {"version":3,"sources":["../../src/uploads/stagedUpload.ts"],"sourcesContent":["import { jwtVerify } from 'jose/jwt/verify'\nimport { randomUUID } from 'node:crypto'\nimport fs from 'node:fs/promises'\nimport os from 'node:os'\nimport path from 'node:path'\n\nimport type { PayloadHandler } from '../config/types.js'\nimport type { PayloadRequest } from '../types/index.js'\nimport type { File, UploadInstructions, UploadInstructionsRequest } from './types.js'\n\nimport { jwtSign } from '../auth/jwt.js'\nimport { APIError, Forbidden } from '../errors/index.js'\nimport { formatAdminURL } from '../utilities/formatAdminURL.js'\nimport { checkFileRestrictions } from './checkFileRestrictions.js'\n\n/**\n * Creates a signed, one-hour URL where the client can send the file bytes. The returned file value\n * is later passed to a document create or update request.\n */\nexport const generateStagedUploadInstructions = async ({\n collectionSlug,\n docPrefix,\n filename,\n filesize,\n mimeType,\n req,\n}: { req: PayloadRequest } & UploadInstructionsRequest): Promise<UploadInstructions> => {\n await removeExpiredUploads(req, collectionSlug)\n\n const { token: uploadId } = await jwtSign({\n fieldsToSign: {\n id: randomUUID(),\n collectionSlug,\n docPrefix,\n filename,\n filesize,\n mimeType,\n user: getUser(req),\n },\n secret: req.payload.secret,\n tokenExpiration,\n })\n\n return {\n type: 'http',\n file: {\n filename,\n mimeType,\n size: filesize,\n uploadReference: { uploadId },\n },\n request: {\n headers: {\n 'Content-Length': String(filesize),\n 'Content-Type': mimeType,\n },\n method: 'PUT',\n url: formatAdminURL({\n apiRoute: req.payload.config.routes.api,\n path: `/upload-instructions/${uploadId}`,\n serverURL: req.payload.config.serverURL,\n }),\n },\n }\n}\n\n/**\n * Saves the bytes sent to a signed upload URL. The file is written as a partial file first and only\n * becomes available when its size exactly matches the size in the upload ID.\n */\nexport const uploadStagedFile: PayloadHandler = async (req) => {\n const upload = await verifyUploadID(req, req.routeParams?.uploadId)\n const directory = await getUploadDirectory(req, upload.collectionSlug)\n const uploadPath = path.join(directory, upload.id)\n const temporaryPath = `${uploadPath}.${randomUUID()}.part`\n const file = await fs.open(temporaryPath, 'wx')\n let uploadedSize = 0\n\n try {\n try {\n const reader = req.body?.getReader()\n\n while (reader) {\n const { done, value } = await reader.read()\n\n if (done) {\n break\n }\n\n uploadedSize += value.byteLength\n if (uploadedSize > upload.filesize) {\n throw new APIError('Uploaded file is larger than expected.', 400)\n }\n\n let offset = 0\n while (offset < value.byteLength) {\n const { bytesWritten } = await file.write(value, offset)\n offset += bytesWritten\n }\n }\n\n if (uploadedSize !== upload.filesize) {\n throw new APIError('Uploaded file size does not match the expected size.', 400)\n }\n } finally {\n await file.close()\n }\n\n const collection = req.payload.collections[upload.collectionSlug]!.config\n await checkFileRestrictions({\n collection,\n file: {\n name: upload.filename,\n data: Buffer.alloc(0),\n mimetype: upload.mimeType,\n size: upload.filesize,\n tempFilePath: temporaryPath,\n },\n req,\n })\n\n await fs.rename(temporaryPath, uploadPath)\n } catch (error) {\n await fs.rm(temporaryPath, { force: true })\n throw error\n }\n\n return new Response(null, { status: 204 })\n}\n\n/** Removes a temporary upload that the client no longer needs. */\nexport const deleteStagedFile: PayloadHandler = async (req) => {\n const upload = await verifyUploadID(req, req.routeParams?.uploadId)\n const directory = await getUploadDirectory(req, upload.collectionSlug)\n\n await fs.rm(path.join(directory, upload.id), { force: true })\n\n return new Response(null, { status: 204 })\n}\n\n/**\n * Loads a completed staged file for a document request. Only the same user and collection can use\n * it, and the temporary file is deleted after it is read.\n */\nexport const getStagedFile = async ({\n collectionSlug,\n req,\n uploadReference,\n}: {\n collectionSlug: string\n req: PayloadRequest\n uploadReference: unknown\n}): Promise<File> => {\n if (\n !uploadReference ||\n typeof uploadReference !== 'object' ||\n Array.isArray(uploadReference) ||\n !('uploadId' in uploadReference) ||\n typeof uploadReference.uploadId !== 'string'\n ) {\n throw new APIError('Invalid staged upload.', 400)\n }\n\n const { uploadId } = uploadReference\n const upload = await verifyUploadID(req, uploadId)\n\n if (upload.collectionSlug !== collectionSlug || upload.user !== getUser(req)) {\n throw new Forbidden(req.t)\n }\n\n const directory = await getUploadDirectory(req, upload.collectionSlug)\n const tempFilePath = path.join(directory, upload.id)\n let data: Buffer\n\n try {\n data = await fs.readFile(tempFilePath)\n } catch {\n throw new APIError('Staged upload was not found.', 400)\n }\n\n if (data.length !== upload.filesize) {\n await fs.rm(tempFilePath, { force: true })\n throw new APIError('Staged upload is incomplete.', 400)\n }\n\n await fs.rm(tempFilePath, { force: true })\n\n return {\n name: upload.filename,\n data,\n mimetype: upload.mimeType,\n size: data.length,\n }\n}\n\n/**\n * Staged uploads hold a file temporarily until a document create or update uses it. The signed\n * upload ID remembers which file and user the upload belongs to.\n */\nconst tokenExpiration = 60 * 60\n\n/** The file details stored inside the signed upload ID. */\ntype StagedUploadToken = {\n id: string\n user: null | string\n} & UploadInstructionsRequest\n\nconst getUser = (req: PayloadRequest) =>\n req.user ? `${req.user.collection}:${String(req.user.id)}` : null\n\n/** Returns the hidden folder where temporary uploads for this collection are stored. */\nconst getUploadDirectory = async (req: PayloadRequest, collectionSlug: string) => {\n const upload = req.payload.collections[collectionSlug]?.config.upload\n const directory = path.resolve(\n upload && !upload.disableLocalStorage\n ? upload.staticDir || collectionSlug\n : req.payload.config.upload.tempFileDir || os.tmpdir(),\n '.payload-staged-uploads',\n )\n\n await fs.mkdir(directory, { recursive: true })\n\n return directory\n}\n\n/** Removes temporary files older than the one-hour upload window. */\nconst removeExpiredUploads = async (req: PayloadRequest, collectionSlug: string) => {\n const directory = await getUploadDirectory(req, collectionSlug)\n const expiresBefore = Date.now() - tokenExpiration * 1000\n\n for (const filename of await fs.readdir(directory)) {\n const filePath = path.join(directory, filename)\n const stats = await fs.stat(filePath).catch(() => null)\n\n if (stats && stats.mtimeMs < expiresBefore) {\n await fs.rm(filePath, { force: true })\n }\n }\n}\n\n/** Verifies that an upload ID was signed by Payload, has not expired, and contains valid details. */\nconst verifyUploadID = async (\n req: PayloadRequest,\n uploadID: unknown,\n): Promise<StagedUploadToken> => {\n try {\n if (typeof uploadID !== 'string') {\n throw new Error()\n }\n\n const secret = new TextEncoder().encode(req.payload.secret)\n const { payload } = await jwtVerify<StagedUploadToken>(uploadID, secret)\n\n if (\n typeof payload.id !== 'string' ||\n !/^[\\da-f-]{36}$/i.test(payload.id) ||\n typeof payload.collectionSlug !== 'string' ||\n typeof payload.filename !== 'string' ||\n !Number.isSafeInteger(payload.filesize) ||\n payload.filesize < 0 ||\n typeof payload.mimeType !== 'string' ||\n (payload.user !== null && typeof payload.user !== 'string')\n ) {\n throw new Error()\n }\n\n return payload\n } catch {\n throw new APIError('Invalid or expired staged upload.', 400)\n }\n}\n"],"names":["jwtVerify","randomUUID","fs","os","path","jwtSign","APIError","Forbidden","formatAdminURL","checkFileRestrictions","generateStagedUploadInstructions","collectionSlug","docPrefix","filename","filesize","mimeType","req","removeExpiredUploads","token","uploadId","fieldsToSign","id","user","getUser","secret","payload","tokenExpiration","type","file","size","uploadReference","request","headers","String","method","url","apiRoute","config","routes","api","serverURL","uploadStagedFile","upload","verifyUploadID","routeParams","directory","getUploadDirectory","uploadPath","join","temporaryPath","open","uploadedSize","reader","body","getReader","done","value","read","byteLength","offset","bytesWritten","write","close","collection","collections","name","data","Buffer","alloc","mimetype","tempFilePath","rename","error","rm","force","Response","status","deleteStagedFile","getStagedFile","Array","isArray","t","readFile","length","resolve","disableLocalStorage","staticDir","tempFileDir","tmpdir","mkdir","recursive","expiresBefore","Date","now","readdir","filePath","stats","stat","catch","mtimeMs","uploadID","Error","TextEncoder","encode","test","Number","isSafeInteger"],"mappings":"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"}
@@ -119,7 +119,7 @@ import { withFileTransformAccessContext } from './withFileTransformAccessContext
119
119
  if (result.response) {
120
120
  if (handedOutResponse && result.response !== handedOutResponse) {
121
121
  await discardResponse(handedOutResponse);
122
- } else if (previousResponse && result.response !== previousResponse) {
122
+ } else if (!handedOutResponse && previousResponse && result.response !== previousResponse) {
123
123
  await discardResponse(previousResponse);
124
124
  }
125
125
  currentResponse = result.response;
@@ -169,7 +169,16 @@ import { withFileTransformAccessContext } from './withFileTransformAccessContext
169
169
  if (!response.body) {
170
170
  return response;
171
171
  }
172
- return new Response(response.body.pipeThrough(new TransformStream(), {
172
+ const stream = new TransformStream({
173
+ start (controller) {
174
+ // Pipe abort waits for pending writes, which can stall on an abandoned reader.
175
+ // Error the transform to unblock those writes before the pipe cancels its source.
176
+ signal.addEventListener('abort', ()=>controller.error(signal.reason), {
177
+ once: true
178
+ });
179
+ }
180
+ });
181
+ return new Response(response.body.pipeThrough(stream, {
173
182
  signal
174
183
  }), {
175
184
  headers: response.headers,
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/uploads/transformers/handleDynamicFileRequest.ts"],"sourcesContent":["import type { Collection } from '../../collections/config/types.js'\nimport type { PayloadRequest } from '../../types/index.js'\nimport type { ResolvedUploadDocument } from './resolveUploadDocument.js'\nimport type { UploadTransformer } from './types.js'\n\nimport { Forbidden } from '../../errors/Forbidden.js'\nimport { NotFound } from '../../errors/NotFound.js'\nimport { TransformerContractError } from '../../errors/TransformerContractError.js'\nimport { checkFileAccess } from '../checkFileAccess.js'\nimport { retrieveFileResponse } from '../endpoints/getFile.js'\nimport { createLazySourceGetter } from './createLazySourceGetter.js'\nimport { finalizeFileResponse } from './finalizeFileResponse.js'\nimport { getSourceFileResponse } from './getSourceFileResponse.js'\nimport { getCandidateTransformers, planTransformerPipeline } from './planTransformerPipeline.js'\nimport { getRequestedFile, resolveUploadDocument } from './resolveUploadDocument.js'\nimport { withFileTransformAccessContext } from './withFileTransformAccessContext.js'\n\n/**\n * Orchestrates a dynamic file request end to end: resolve the document, plan the\n * request-capable transformer pipeline from the requested file's authoritative\n * MIME type (the primary file or the matched image size), enforce\n * transform-aware read access, then run every eligible transformer in declaration\n * order against a lazily-fetched source. Called from `getFileHandler` only when at\n * least one transformer is configured — the zero-transformer path never reaches\n * this function.\n */\nexport async function handleDynamicFileRequest({\n collection,\n filename,\n prefix,\n req,\n}: {\n collection: Collection\n filename: string\n prefix?: string\n req: PayloadRequest\n}): Promise<Response> {\n const resolvedDocument = await resolveUploadDocument({ collection, filename, prefix, req })\n\n if (!resolvedDocument) {\n // There's no mimeType to plan a pipeline from, so both access modes must pass\n // before admitting the file doesn't exist — otherwise the status code would leak\n // file existence to an access function keyed on req.fileTransform.\n for (const isTransform of [true, false]) {\n await withFileTransformAccessContext({\n callback: () => checkFileAccess({ collection, filename, prefix, req }),\n isTransform,\n req,\n })\n }\n throw new NotFound(req.t)\n }\n\n if (\n resolvedDocument.original?.filename === filename &&\n (resolvedDocument.filename !== filename || req.searchParams.size === 0)\n ) {\n const permittedDocument = await withFileTransformAccessContext({\n callback: () => checkFileAccess({ collection, filename, prefix, req }),\n isTransform: false,\n req,\n })\n\n return retrieveFileResponse({\n collection,\n doc: (permittedDocument ?? resolvedDocument) as ResolvedUploadDocument,\n filename,\n prefix,\n req,\n })\n }\n\n const { document, pipeline } = await authorizeDocument({\n collection,\n filename,\n prefix,\n req,\n resolvedDocument,\n })\n\n const requestedFile = getRequestedFile({ document, filename })\n\n const source = createLazySourceGetter({\n retrieve: () => getSourceFileResponse({ collection, document, filename, prefix, req }),\n })\n\n let currentResponse: Response | undefined\n // Each stage has its own controller so a discarded body can be closed even when the\n // transformer locked it with a reader. Every remaining controller is aborted on failure.\n const handedOutBodyControllers = new Map<Response, AbortController>()\n\n const discardResponse = async (response: Response): Promise<void> => {\n await cancelUnusedBody(response)\n handedOutBodyControllers.get(response)?.abort()\n handedOutBodyControllers.delete(response)\n }\n\n try {\n for (const transformer of pipeline) {\n const previousResponse = currentResponse\n let handedOutResponse: Response | undefined\n const handedOutBodyController = new AbortController()\n const stageSource = createLazySourceGetter({\n retrieve: async () => {\n handedOutResponse = withAbortableBody({\n response: currentResponse ?? (await source.get()),\n signal: handedOutBodyController.signal,\n })\n handedOutBodyControllers.set(handedOutResponse, handedOutBodyController)\n\n return handedOutResponse\n },\n })\n\n const result = await transformer.handleRequest!({\n collectionSlug: collection.config.slug,\n documentID: document.id,\n filename: requestedFile.filename,\n getSourceFile: stageSource.get,\n mimeType: requestedFile.mimeType,\n req,\n })\n\n if (result.response) {\n if (handedOutResponse && result.response !== handedOutResponse) {\n await discardResponse(handedOutResponse)\n } else if (previousResponse && result.response !== previousResponse) {\n await discardResponse(previousResponse)\n }\n\n currentResponse = result.response\n } else if (stageSource.wasCalled()) {\n throw new TransformerContractError(\n 'A transformer that consumes its source must return a response.',\n )\n }\n\n if (result.status === 'complete') {\n return finalizeFileResponse({ collection, req, response: currentResponse! })\n }\n }\n } catch (err) {\n req.payload.logger.error({ err, msg: 'Error running the file transformer pipeline' })\n for (const handedOutBodyController of handedOutBodyControllers.values()) {\n handedOutBodyController.abort(err)\n }\n await cancelUnusedBody(currentResponse)\n throw err\n }\n\n if (currentResponse) {\n return finalizeFileResponse({ collection, req, response: currentResponse })\n }\n\n // No transformer produced a response — serve the original file through the\n // normal path (Range/ETag/redirect support, existing `modifyResponseHeaders` order).\n return retrieveFileResponse({ collection, doc: document, filename, prefix, req })\n}\n\n/**\n * Re-wraps `response` so its body can be cancelled through `signal`, closing the underlying\n * source stream (file handle, storage connection) regardless of who holds a reader on it.\n */\nfunction withAbortableBody({\n response,\n signal,\n}: {\n response: Response\n signal: AbortSignal\n}): Response {\n if (!response.body) {\n return response\n }\n\n return new Response(response.body.pipeThrough(new TransformStream(), { signal }), {\n headers: response.headers,\n status: response.status,\n statusText: response.statusText,\n })\n}\n\n/**\n * Cancels a response body nothing has started reading. A locked body was handed to a transformer\n * through `withAbortableBody`, and is closed by aborting its signal instead.\n */\nasync function cancelUnusedBody(response: Response | undefined): Promise<void> {\n if (!response?.body || response.body.locked) {\n return\n }\n\n try {\n await response.body.cancel()\n } catch {\n // A clean-up failure must not replace the pipeline result or error.\n }\n}\n\nfunction planRequestPipeline({\n collection,\n document,\n filename,\n req,\n}: {\n collection: Collection\n document: ResolvedUploadDocument\n filename: string\n req: PayloadRequest\n}): Promise<UploadTransformer[]> {\n return planTransformerPipeline({\n args: {\n collectionSlug: collection.config.slug,\n documentID: document.id,\n mimeType: getRequestedFile({ document, filename }).mimeType,\n operation: 'request',\n req,\n },\n capability: 'handleRequest',\n transformers: req.payload.config.upload.transformers,\n })\n}\n\ntype AccessResult = { document?: ResolvedUploadDocument; isAllowed: true } | { isAllowed: false }\n\n/**\n * Decides which document is served and which pipeline runs, checking read access\n * before any application-defined transformer code (`canTransform`) executes.\n *\n * 1. The first access mode comes from MIME matching alone: a transform-aware check\n * when any transformer could handle the file, otherwise an ordinary read.\n * 2. If the transform-aware check is denied, an ordinary read may still be allowed\n * (e.g. public originals, signed-in-only variants), so that mode is tried next.\n * 3. Only once a check has passed does `canTransform` plan the real pipeline.\n * 4. The access mode the final pipeline requires must itself have passed — a\n * \"variants only\" policy must not leak the original when no transformer applies.\n *\n * `resolveUploadDocument` is unfiltered, so without a `prefix` it can match a\n * document the user can't read that shares the filename (filenames are only\n * unique per prefix). Whenever `checkFileAccess` returns a document, that\n * authorized document is the one served — storage adapters trust `doc` to\n * resolve the object key.\n */\nasync function authorizeDocument({\n collection,\n filename,\n prefix,\n req,\n resolvedDocument,\n}: {\n collection: Collection\n filename: string\n prefix?: string\n req: PayloadRequest\n resolvedDocument: ResolvedUploadDocument\n}): Promise<{ document: ResolvedUploadDocument; pipeline: UploadTransformer[] }> {\n const accessResults = new Map<boolean, Promise<AccessResult>>()\n\n const checkAccess = ({ isTransform }: { isTransform: boolean }): Promise<AccessResult> => {\n if (!accessResults.has(isTransform)) {\n accessResults.set(\n isTransform,\n withFileTransformAccessContext({\n callback: () => checkFileAccess({ collection, filename, prefix, req }),\n isTransform,\n req,\n }).then(\n (document) => ({\n document: document as ResolvedUploadDocument | undefined,\n isAllowed: true as const,\n }),\n (err: unknown) => {\n if (err instanceof Forbidden) {\n return { isAllowed: false as const }\n }\n\n throw err\n },\n ),\n )\n }\n\n return accessResults.get(isTransform)!\n }\n\n const hasCandidateTransformers =\n getCandidateTransformers({\n capability: 'handleRequest',\n mimeType: getRequestedFile({ document: resolvedDocument, filename }).mimeType,\n transformers: req.payload.config.upload.transformers,\n }).length > 0\n\n let isTransformAccess = hasCandidateTransformers\n let access = await checkAccess({ isTransform: isTransformAccess })\n\n if (!access.isAllowed && isTransformAccess) {\n isTransformAccess = false\n access = await checkAccess({ isTransform: isTransformAccess })\n }\n\n if (!access.isAllowed) {\n throw new Forbidden(req.t)\n }\n\n const document =\n access.document && access.document.id !== resolvedDocument.id\n ? access.document\n : resolvedDocument\n\n const pipeline = await planRequestPipeline({ collection, document, filename, req })\n const isTransform = pipeline.length > 0\n\n if (isTransform !== isTransformAccess) {\n const requiredAccess = await checkAccess({ isTransform })\n\n if (\n !requiredAccess.isAllowed ||\n (requiredAccess.document && requiredAccess.document.id !== document.id)\n ) {\n throw new Forbidden(req.t)\n }\n }\n\n return { document, pipeline }\n}\n"],"names":["Forbidden","NotFound","TransformerContractError","checkFileAccess","retrieveFileResponse","createLazySourceGetter","finalizeFileResponse","getSourceFileResponse","getCandidateTransformers","planTransformerPipeline","getRequestedFile","resolveUploadDocument","withFileTransformAccessContext","handleDynamicFileRequest","collection","filename","prefix","req","resolvedDocument","isTransform","callback","t","original","searchParams","size","permittedDocument","doc","document","pipeline","authorizeDocument","requestedFile","source","retrieve","currentResponse","handedOutBodyControllers","Map","discardResponse","response","cancelUnusedBody","get","abort","delete","transformer","previousResponse","handedOutResponse","handedOutBodyController","AbortController","stageSource","withAbortableBody","signal","set","result","handleRequest","collectionSlug","config","slug","documentID","id","getSourceFile","mimeType","wasCalled","status","err","payload","logger","error","msg","values","body","Response","pipeThrough","TransformStream","headers","statusText","locked","cancel","planRequestPipeline","args","operation","capability","transformers","upload","accessResults","checkAccess","has","then","isAllowed","hasCandidateTransformers","length","isTransformAccess","access","requiredAccess"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../src/uploads/transformers/handleDynamicFileRequest.ts"],"sourcesContent":["import type { Collection } from '../../collections/config/types.js'\nimport type { PayloadRequest } from '../../types/index.js'\nimport type { ResolvedUploadDocument } from './resolveUploadDocument.js'\nimport type { UploadTransformer } from './types.js'\n\nimport { Forbidden } from '../../errors/Forbidden.js'\nimport { NotFound } from '../../errors/NotFound.js'\nimport { TransformerContractError } from '../../errors/TransformerContractError.js'\nimport { checkFileAccess } from '../checkFileAccess.js'\nimport { retrieveFileResponse } from '../endpoints/getFile.js'\nimport { createLazySourceGetter } from './createLazySourceGetter.js'\nimport { finalizeFileResponse } from './finalizeFileResponse.js'\nimport { getSourceFileResponse } from './getSourceFileResponse.js'\nimport { getCandidateTransformers, planTransformerPipeline } from './planTransformerPipeline.js'\nimport { getRequestedFile, resolveUploadDocument } from './resolveUploadDocument.js'\nimport { withFileTransformAccessContext } from './withFileTransformAccessContext.js'\n\n/**\n * Orchestrates a dynamic file request end to end: resolve the document, plan the\n * request-capable transformer pipeline from the requested file's authoritative\n * MIME type (the primary file or the matched image size), enforce\n * transform-aware read access, then run every eligible transformer in declaration\n * order against a lazily-fetched source. Called from `getFileHandler` only when at\n * least one transformer is configured — the zero-transformer path never reaches\n * this function.\n */\nexport async function handleDynamicFileRequest({\n collection,\n filename,\n prefix,\n req,\n}: {\n collection: Collection\n filename: string\n prefix?: string\n req: PayloadRequest\n}): Promise<Response> {\n const resolvedDocument = await resolveUploadDocument({ collection, filename, prefix, req })\n\n if (!resolvedDocument) {\n // There's no mimeType to plan a pipeline from, so both access modes must pass\n // before admitting the file doesn't exist — otherwise the status code would leak\n // file existence to an access function keyed on req.fileTransform.\n for (const isTransform of [true, false]) {\n await withFileTransformAccessContext({\n callback: () => checkFileAccess({ collection, filename, prefix, req }),\n isTransform,\n req,\n })\n }\n throw new NotFound(req.t)\n }\n\n if (\n resolvedDocument.original?.filename === filename &&\n (resolvedDocument.filename !== filename || req.searchParams.size === 0)\n ) {\n const permittedDocument = await withFileTransformAccessContext({\n callback: () => checkFileAccess({ collection, filename, prefix, req }),\n isTransform: false,\n req,\n })\n\n return retrieveFileResponse({\n collection,\n doc: permittedDocument ?? resolvedDocument,\n filename,\n prefix,\n req,\n })\n }\n\n const { document, pipeline } = await authorizeDocument({\n collection,\n filename,\n prefix,\n req,\n resolvedDocument,\n })\n\n const requestedFile = getRequestedFile({ document, filename })\n\n const source = createLazySourceGetter({\n retrieve: () => getSourceFileResponse({ collection, document, filename, prefix, req }),\n })\n\n let currentResponse: Response | undefined\n // Each stage has its own controller so a discarded body can be closed even when the\n // transformer locked it with a reader. Every remaining controller is aborted on failure.\n const handedOutBodyControllers = new Map<Response, AbortController>()\n\n const discardResponse = async (response: Response): Promise<void> => {\n await cancelUnusedBody(response)\n handedOutBodyControllers.get(response)?.abort()\n handedOutBodyControllers.delete(response)\n }\n\n try {\n for (const transformer of pipeline) {\n const previousResponse = currentResponse\n let handedOutResponse: Response | undefined\n const handedOutBodyController = new AbortController()\n const stageSource = createLazySourceGetter({\n retrieve: async () => {\n handedOutResponse = withAbortableBody({\n response: currentResponse ?? (await source.get()),\n signal: handedOutBodyController.signal,\n })\n handedOutBodyControllers.set(handedOutResponse, handedOutBodyController)\n\n return handedOutResponse\n },\n })\n\n const result = await transformer.handleRequest!({\n collectionSlug: collection.config.slug,\n documentID: document.id,\n filename: requestedFile.filename,\n getSourceFile: stageSource.get,\n mimeType: requestedFile.mimeType,\n req,\n })\n\n if (result.response) {\n if (handedOutResponse && result.response !== handedOutResponse) {\n await discardResponse(handedOutResponse)\n } else if (!handedOutResponse && previousResponse && result.response !== previousResponse) {\n await discardResponse(previousResponse)\n }\n\n currentResponse = result.response\n } else if (stageSource.wasCalled()) {\n throw new TransformerContractError(\n 'A transformer that consumes its source must return a response.',\n )\n }\n\n if (result.status === 'complete') {\n return finalizeFileResponse({ collection, req, response: currentResponse! })\n }\n }\n } catch (err) {\n req.payload.logger.error({ err, msg: 'Error running the file transformer pipeline' })\n for (const handedOutBodyController of handedOutBodyControllers.values()) {\n handedOutBodyController.abort(err)\n }\n await cancelUnusedBody(currentResponse)\n throw err\n }\n\n if (currentResponse) {\n return finalizeFileResponse({ collection, req, response: currentResponse })\n }\n\n // No transformer produced a response — serve the original file through the\n // normal path (Range/ETag/redirect support, existing `modifyResponseHeaders` order).\n return retrieveFileResponse({ collection, doc: document, filename, prefix, req })\n}\n\n/**\n * Re-wraps `response` so its body can be cancelled through `signal`, closing the underlying\n * source stream (file handle, storage connection) regardless of who holds a reader on it.\n */\nfunction withAbortableBody({\n response,\n signal,\n}: {\n response: Response\n signal: AbortSignal\n}): Response {\n if (!response.body) {\n return response\n }\n\n const stream = new TransformStream({\n start(controller) {\n // Pipe abort waits for pending writes, which can stall on an abandoned reader.\n // Error the transform to unblock those writes before the pipe cancels its source.\n signal.addEventListener('abort', () => controller.error(signal.reason), { once: true })\n },\n })\n\n return new Response(response.body.pipeThrough(stream, { signal }), {\n headers: response.headers,\n status: response.status,\n statusText: response.statusText,\n })\n}\n\n/**\n * Cancels a response body nothing has started reading. A locked body was handed to a transformer\n * through `withAbortableBody`, and is closed by aborting its signal instead.\n */\nasync function cancelUnusedBody(response: Response | undefined): Promise<void> {\n if (!response?.body || response.body.locked) {\n return\n }\n\n try {\n await response.body.cancel()\n } catch {\n // A clean-up failure must not replace the pipeline result or error.\n }\n}\n\nfunction planRequestPipeline({\n collection,\n document,\n filename,\n req,\n}: {\n collection: Collection\n document: ResolvedUploadDocument\n filename: string\n req: PayloadRequest\n}): Promise<UploadTransformer[]> {\n return planTransformerPipeline({\n args: {\n collectionSlug: collection.config.slug,\n documentID: document.id,\n mimeType: getRequestedFile({ document, filename }).mimeType,\n operation: 'request',\n req,\n },\n capability: 'handleRequest',\n transformers: req.payload.config.upload.transformers,\n })\n}\n\ntype AccessResult = { document?: ResolvedUploadDocument; isAllowed: true } | { isAllowed: false }\n\n/**\n * Decides which document is served and which pipeline runs, checking read access\n * before any application-defined transformer code (`canTransform`) executes.\n *\n * 1. The first access mode comes from MIME matching alone: a transform-aware check\n * when any transformer could handle the file, otherwise an ordinary read.\n * 2. If the transform-aware check is denied, an ordinary read may still be allowed\n * (e.g. public originals, signed-in-only variants), so that mode is tried next.\n * 3. Only once a check has passed does `canTransform` plan the real pipeline.\n * 4. The access mode the final pipeline requires must itself have passed — a\n * \"variants only\" policy must not leak the original when no transformer applies.\n *\n * `resolveUploadDocument` is unfiltered, so without a `prefix` it can match a\n * document the user can't read that shares the filename (filenames are only\n * unique per prefix). Whenever `checkFileAccess` returns a document, that\n * authorized document is the one served — storage adapters trust `doc` to\n * resolve the object key.\n */\nasync function authorizeDocument({\n collection,\n filename,\n prefix,\n req,\n resolvedDocument,\n}: {\n collection: Collection\n filename: string\n prefix?: string\n req: PayloadRequest\n resolvedDocument: ResolvedUploadDocument\n}): Promise<{ document: ResolvedUploadDocument; pipeline: UploadTransformer[] }> {\n const accessResults = new Map<boolean, Promise<AccessResult>>()\n\n const checkAccess = ({ isTransform }: { isTransform: boolean }): Promise<AccessResult> => {\n if (!accessResults.has(isTransform)) {\n accessResults.set(\n isTransform,\n withFileTransformAccessContext({\n callback: () => checkFileAccess({ collection, filename, prefix, req }),\n isTransform,\n req,\n }).then(\n (document) => ({\n document: document as ResolvedUploadDocument | undefined,\n isAllowed: true as const,\n }),\n (err: unknown) => {\n if (err instanceof Forbidden) {\n return { isAllowed: false as const }\n }\n\n throw err\n },\n ),\n )\n }\n\n return accessResults.get(isTransform)!\n }\n\n const hasCandidateTransformers =\n getCandidateTransformers({\n capability: 'handleRequest',\n mimeType: getRequestedFile({ document: resolvedDocument, filename }).mimeType,\n transformers: req.payload.config.upload.transformers,\n }).length > 0\n\n let isTransformAccess = hasCandidateTransformers\n let access = await checkAccess({ isTransform: isTransformAccess })\n\n if (!access.isAllowed && isTransformAccess) {\n isTransformAccess = false\n access = await checkAccess({ isTransform: isTransformAccess })\n }\n\n if (!access.isAllowed) {\n throw new Forbidden(req.t)\n }\n\n const document =\n access.document && access.document.id !== resolvedDocument.id\n ? access.document\n : resolvedDocument\n\n const pipeline = await planRequestPipeline({ collection, document, filename, req })\n const isTransform = pipeline.length > 0\n\n if (isTransform !== isTransformAccess) {\n const requiredAccess = await checkAccess({ isTransform })\n\n if (\n !requiredAccess.isAllowed ||\n (requiredAccess.document && requiredAccess.document.id !== document.id)\n ) {\n throw new Forbidden(req.t)\n }\n }\n\n return { document, pipeline }\n}\n"],"names":["Forbidden","NotFound","TransformerContractError","checkFileAccess","retrieveFileResponse","createLazySourceGetter","finalizeFileResponse","getSourceFileResponse","getCandidateTransformers","planTransformerPipeline","getRequestedFile","resolveUploadDocument","withFileTransformAccessContext","handleDynamicFileRequest","collection","filename","prefix","req","resolvedDocument","isTransform","callback","t","original","searchParams","size","permittedDocument","doc","document","pipeline","authorizeDocument","requestedFile","source","retrieve","currentResponse","handedOutBodyControllers","Map","discardResponse","response","cancelUnusedBody","get","abort","delete","transformer","previousResponse","handedOutResponse","handedOutBodyController","AbortController","stageSource","withAbortableBody","signal","set","result","handleRequest","collectionSlug","config","slug","documentID","id","getSourceFile","mimeType","wasCalled","status","err","payload","logger","error","msg","values","body","stream","TransformStream","start","controller","addEventListener","reason","once","Response","pipeThrough","headers","statusText","locked","cancel","planRequestPipeline","args","operation","capability","transformers","upload","accessResults","checkAccess","has","then","isAllowed","hasCandidateTransformers","length","isTransformAccess","access","requiredAccess"],"mappings":"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"}
@@ -188,17 +188,6 @@ export type UploadConfig = {
188
188
  * @default true
189
189
  */
190
190
  crop?: boolean;
191
- /**
192
- * Deletes files from adapter-managed storage when an internal operation removes file references
193
- * without deleting the owning document.
194
- *
195
- * @internal
196
- */
197
- deleteFiles?: (args: {
198
- req: PayloadRequest;
199
- retainedDoc?: null | object;
200
- sourceDoc: object;
201
- }) => Promise<void>;
202
191
  /**
203
192
  * Disable the ability to save files to disk.
204
193
  * @default false
@@ -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 { CollectionConfig, TypeWithID } from '../collections/config/types.js'\nimport type { PayloadComponent } from '../config/types.js'\nimport type { UploadCollectionSlug } from '../index.js'\nimport type { PayloadRequest } from '../types/index.js'\nimport type { StagedObject } from './fileVersioning/fileOperationManager.js'\n\nexport type OriginalFileData = {\n _objectKey?: string\n filename: string\n filesize: number\n height?: null | number\n mimeType: string\n prefix?: string\n url: string\n width?: null | number\n}\n\nexport type FileSize = {\n _objectKey?: string\n filename: null | string\n filesize: null | number\n height: null | number\n mimeType: null | string\n prefix?: string\n url: null | string\n width: null | number\n}\n\nexport type FileSizes = {\n [size: string]: FileSize\n}\n\nexport type FileData = {\n _objectKey?: string\n filename: string\n filesize: number\n focalX?: number\n focalY?: number\n height: number\n mimeType: string\n original?: null | OriginalFileData\n prefix?: string\n tempFilePath?: string\n url?: string\n variants: FileSizes\n width: number\n}\n\nexport type ProbedImageSize = {\n height: number\n width: number\n}\n\nexport type GenerateImageName = (args: {\n extension: string\n height: number\n originalName: string\n sizeName: string\n width: number\n}) => string\n\ntype ImageSizeBase = {\n /**\n * Admin UI options that control how this image size appears in list views.\n */\n admin?: {\n /**\n * Controls visibility of this image size in the collection list view.\n * Defaults to hiding the image size from columns, filters, and group-by to reduce noise.\n *\n * - `column` — whether to hide this size from selectable list columns. @default false\n * - `filter` — whether to hide this size from filter options. @default false\n * - `groupBy` — whether to hide this size from group-by options. @default false\n */\n disabled?: {\n column?: boolean\n filter?: boolean\n groupBy?: boolean\n }\n }\n /**\n * Generate a custom name for the file of this image size.\n */\n generateImageName?: GenerateImageName\n name: string\n}\n\n/**\n * Interface to be module-augmented by image processing providers.\n *\n * When no provider is registered, ImageSize carries no processor-specific options.\n * When one or more providers are registered (e.g. `@payloadcms/transformer-sharp`),\n * ImageSize uses the union of their registered options instead.\n *\n * @example\n * declare module 'payload' {\n * interface RegisteredImageSizeOptions {\n * myProvider: MyProviderImageSizeOptions\n * }\n * }\n */\n// eslint-disable-next-line @typescript-eslint/no-empty-object-type -- Intentionally empty so image processing providers can augment it.\nexport interface RegisteredImageSizeOptions {}\n\ntype ImageSizeOptions = keyof RegisteredImageSizeOptions extends never\n ? unknown\n : RegisteredImageSizeOptions[keyof RegisteredImageSizeOptions]\n\nexport type ImageSize = ImageSizeBase & ImageSizeOptions\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\nexport type UploadFilePreviewClientProps = {\n filename: string\n filesize: number\n /** Resolved URL of the file (data.url). */\n fileSrc: string\n height?: number\n mimeType: string\n width?: number\n}\n\ntype UploadFilePreviewMap = {\n [mimeTypePattern: string]: PayloadComponent\n}\n\n/**\n * Distinguishes an ordinary public file request (`read`) from Payload's internal\n * retrieval of a stored file's bytes for a dynamic transformation (`transform`).\n * Defaults to `read` when omitted, for third-party handler compatibility.\n */\nexport type FileHandlerOperation = 'read' | 'transform'\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 * A custom component to render in place of the default Thumbnail in the upload side panel.\n *\n * Can be a single PayloadComponent (renders for all MIME types) or a Record keyed by\n * MIME type patterns. Pattern resolution priority: exact match → category wildcard\n * (e.g. `video/*`) → universal fallback (`*`). Falls back to the default Thumbnail\n * when nothing matches.\n */\n filePreview?: PayloadComponent | UploadFilePreviewMap\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 * Enables cropping of images.\n * @default true\n */\n crop?: boolean\n /**\n * Deletes files from adapter-managed storage when an internal operation removes file references\n * without deleting the owning document.\n *\n * @internal\n */\n deleteFiles?: (args: {\n req: PayloadRequest\n retainedDoc?: null | object\n sourceDoc: object\n }) => Promise<void>\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 /** @internal Set by cloudStoragePlugin for versioned uploads; adapters do not implement this. */\n fileOperations?: {\n /** Copy before the document changes. Must preserve object metadata and reject an occupied key. */\n copy: (args: {\n from: string\n req: PayloadRequest\n to: string\n trackStagedObject: (object: StagedObject) => void\n }) => Promise<void>\n delete: (args: { key: string; req: PayloadRequest }) => Promise<void>\n hasLegacyFile?: (args: {\n doc: Record<string, unknown>\n req: PayloadRequest\n }) => Promise<boolean>\n move?: (args: {\n from: string\n req: PayloadRequest\n to: string\n trackStagedObject: (object: StagedObject) => void\n }) => Promise<void>\n resolveStorageKey: (args: { _objectKey?: string; filename: string; prefix?: string }) => string\n stage: (args: {\n data: Record<string, unknown>\n files: FileToSave[]\n req: PayloadRequest\n trackStagedObject: (object: StagedObject) => void\n }) => Promise<{ metadata: Record<string, unknown> }>\n }\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 * 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 * @default undefined\n */\n handlers?: ((\n req: PayloadRequest,\n args: {\n doc: TypeWithID\n headers?: Headers\n params: {\n collection: string\n filename: string\n /** @default 'read' */\n operation?: FileHandlerOperation\n prefix?: string\n uploadReference?: unknown\n }\n },\n ) => Promise<Response> | Promise<void> | Response | void)[]\n /**\n * Whether a registered transformer performs additional processing on the main\n * uploaded file beyond simple pass-through (e.g. resizing, format conversion,\n * trimming). Written by a transformer's `init()`; not intended to be set\n * directly in collection config. Used by the Admin UI to decide whether to\n * show focal-point controls when no image sizes are configured.\n * @internal\n */\n hasImageAdjustments?: boolean\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 /**\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 * 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 /**\n * Adapter-provided upload instructions.\n * @internal\n */\n uploadInstructions?: UploadInstructionsCapability\n}\n\nexport type UploadInstructionsAccess = (args: {\n collectionSlug: UploadCollectionSlug\n req: PayloadRequest\n}) => boolean | Promise<boolean>\n\nexport type UploadInstructionsRequest = {\n collectionSlug: UploadCollectionSlug\n docPrefix?: string\n filename: string\n filesize: number\n mimeType: string\n}\n\nexport type UploadInstructions = {\n file: {\n filename: string\n mimeType: string\n size: number\n uploadReference: Record<string, unknown>\n }\n} & (\n | {\n data?: unknown\n name: string\n type: 'dispatch'\n }\n | {\n request: {\n headers?: Record<string, string>\n method: 'POST' | 'PUT'\n url: string\n }\n type: 'http'\n }\n)\n\nexport type GenerateUploadInstructions = (\n args: { overrideAccess?: boolean; req: PayloadRequest } & UploadInstructionsRequest,\n) => Promise<UploadInstructions> | UploadInstructions\n\nexport type UploadInstructionsCapability = {\n /** Generates upload instructions. The generator or supporting endpoint must check access. */\n generate: GenerateUploadInstructions\n /** Require a signed server-issued reference before invoking upload handlers. @internal */\n requiresUploadReceipt?: boolean\n /**\n * Whether the Admin panel should use these instructions before saving a document.\n * This can still be useful when upload chunks pass through Payload.\n */\n useInAdmin: boolean\n}\nexport type checkFileRestrictionsParams = {\n /** Set to false when the file bytes have not been uploaded yet. */\n checkFileContents?: boolean\n collection: CollectionConfig\n file: File\n req: PayloadRequest\n}\n\nexport type SanitizedUploadConfig = {\n staticDir: UploadConfig['staticDir']\n /**\n * The collection's image sizes, as written at startup by a registered transformer such as\n * `sharpTransformer({ collections: { <slug>: { variants } } })`. Names and admin options\n * only — not authored on the collection.\n */\n variants?: ImageSize[]\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":"AAmfA,WAKC"}
1
+ {"version":3,"sources":["../../src/uploads/types.ts"],"sourcesContent":["import type { CollectionConfig, TypeWithID } from '../collections/config/types.js'\nimport type { PayloadComponent } from '../config/types.js'\nimport type { UploadCollectionSlug } from '../index.js'\nimport type { PayloadRequest } from '../types/index.js'\nimport type { StagedObject } from './fileVersioning/fileOperationManager.js'\n\nexport type OriginalFileData = {\n _objectKey?: string\n filename: string\n filesize: number\n height?: null | number\n mimeType: string\n prefix?: string\n url: string\n width?: null | number\n}\n\nexport type FileSize = {\n _objectKey?: string\n filename: null | string\n filesize: null | number\n height: null | number\n mimeType: null | string\n prefix?: string\n url: null | string\n width: null | number\n}\n\nexport type FileSizes = {\n [size: string]: FileSize\n}\n\nexport type FileData = {\n _objectKey?: string\n filename: string\n filesize: number\n focalX?: number\n focalY?: number\n height: number\n mimeType: string\n original?: null | OriginalFileData\n prefix?: string\n tempFilePath?: string\n url?: string\n variants: FileSizes\n width: number\n}\n\nexport type ProbedImageSize = {\n height: number\n width: number\n}\n\nexport type GenerateImageName = (args: {\n extension: string\n height: number\n originalName: string\n sizeName: string\n width: number\n}) => string\n\ntype ImageSizeBase = {\n /**\n * Admin UI options that control how this image size appears in list views.\n */\n admin?: {\n /**\n * Controls visibility of this image size in the collection list view.\n * Defaults to hiding the image size from columns, filters, and group-by to reduce noise.\n *\n * - `column` — whether to hide this size from selectable list columns. @default false\n * - `filter` — whether to hide this size from filter options. @default false\n * - `groupBy` — whether to hide this size from group-by options. @default false\n */\n disabled?: {\n column?: boolean\n filter?: boolean\n groupBy?: boolean\n }\n }\n /**\n * Generate a custom name for the file of this image size.\n */\n generateImageName?: GenerateImageName\n name: string\n}\n\n/**\n * Interface to be module-augmented by image processing providers.\n *\n * When no provider is registered, ImageSize carries no processor-specific options.\n * When one or more providers are registered (e.g. `@payloadcms/transformer-sharp`),\n * ImageSize uses the union of their registered options instead.\n *\n * @example\n * declare module 'payload' {\n * interface RegisteredImageSizeOptions {\n * myProvider: MyProviderImageSizeOptions\n * }\n * }\n */\n// eslint-disable-next-line @typescript-eslint/no-empty-object-type -- Intentionally empty so image processing providers can augment it.\nexport interface RegisteredImageSizeOptions {}\n\ntype ImageSizeOptions = keyof RegisteredImageSizeOptions extends never\n ? unknown\n : RegisteredImageSizeOptions[keyof RegisteredImageSizeOptions]\n\nexport type ImageSize = ImageSizeBase & ImageSizeOptions\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\nexport type UploadFilePreviewClientProps = {\n filename: string\n filesize: number\n /** Resolved URL of the file (data.url). */\n fileSrc: string\n height?: number\n mimeType: string\n width?: number\n}\n\ntype UploadFilePreviewMap = {\n [mimeTypePattern: string]: PayloadComponent\n}\n\n/**\n * Distinguishes an ordinary public file request (`read`) from Payload's internal\n * retrieval of a stored file's bytes for a dynamic transformation (`transform`).\n * Defaults to `read` when omitted, for third-party handler compatibility.\n */\nexport type FileHandlerOperation = 'read' | 'transform'\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 * A custom component to render in place of the default Thumbnail in the upload side panel.\n *\n * Can be a single PayloadComponent (renders for all MIME types) or a Record keyed by\n * MIME type patterns. Pattern resolution priority: exact match → category wildcard\n * (e.g. `video/*`) → universal fallback (`*`). Falls back to the default Thumbnail\n * when nothing matches.\n */\n filePreview?: PayloadComponent | UploadFilePreviewMap\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 * 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 /** @internal Set by cloudStoragePlugin for versioned uploads; adapters do not implement this. */\n fileOperations?: {\n /** Copy before the document changes. Must preserve object metadata and reject an occupied key. */\n copy: (args: {\n from: string\n req: PayloadRequest\n to: string\n trackStagedObject: (object: StagedObject) => void\n }) => Promise<void>\n delete: (args: { key: string; req: PayloadRequest }) => Promise<void>\n hasLegacyFile?: (args: {\n doc: Record<string, unknown>\n req: PayloadRequest\n }) => Promise<boolean>\n move?: (args: {\n from: string\n req: PayloadRequest\n to: string\n trackStagedObject: (object: StagedObject) => void\n }) => Promise<void>\n resolveStorageKey: (args: { _objectKey?: string; filename: string; prefix?: string }) => string\n stage: (args: {\n data: Record<string, unknown>\n files: FileToSave[]\n req: PayloadRequest\n trackStagedObject: (object: StagedObject) => void\n }) => Promise<{ metadata: Record<string, unknown> }>\n }\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 * 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 * @default undefined\n */\n handlers?: ((\n req: PayloadRequest,\n args: {\n doc: TypeWithID\n headers?: Headers\n params: {\n collection: string\n filename: string\n /** @default 'read' */\n operation?: FileHandlerOperation\n prefix?: string\n uploadReference?: unknown\n }\n },\n ) => Promise<Response> | Promise<void> | Response | void)[]\n /**\n * Whether a registered transformer performs additional processing on the main\n * uploaded file beyond simple pass-through (e.g. resizing, format conversion,\n * trimming). Written by a transformer's `init()`; not intended to be set\n * directly in collection config. Used by the Admin UI to decide whether to\n * show focal-point controls when no image sizes are configured.\n * @internal\n */\n hasImageAdjustments?: boolean\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 /**\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 * 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 /**\n * Adapter-provided upload instructions.\n * @internal\n */\n uploadInstructions?: UploadInstructionsCapability\n}\n\nexport type UploadInstructionsAccess = (args: {\n collectionSlug: UploadCollectionSlug\n req: PayloadRequest\n}) => boolean | Promise<boolean>\n\nexport type UploadInstructionsRequest = {\n collectionSlug: UploadCollectionSlug\n docPrefix?: string\n filename: string\n filesize: number\n mimeType: string\n}\n\nexport type UploadInstructions = {\n file: {\n filename: string\n mimeType: string\n size: number\n uploadReference: Record<string, unknown>\n }\n} & (\n | {\n data?: unknown\n name: string\n type: 'dispatch'\n }\n | {\n request: {\n headers?: Record<string, string>\n method: 'POST' | 'PUT'\n url: string\n }\n type: 'http'\n }\n)\n\nexport type GenerateUploadInstructions = (\n args: { overrideAccess?: boolean; req: PayloadRequest } & UploadInstructionsRequest,\n) => Promise<UploadInstructions> | UploadInstructions\n\nexport type UploadInstructionsCapability = {\n /** Generates upload instructions. The generator or supporting endpoint must check access. */\n generate: GenerateUploadInstructions\n /** Require a signed server-issued reference before invoking upload handlers. @internal */\n requiresUploadReceipt?: boolean\n /**\n * Whether the Admin panel should use these instructions before saving a document.\n * This can still be useful when upload chunks pass through Payload.\n */\n useInAdmin: boolean\n}\nexport type checkFileRestrictionsParams = {\n /** Set to false when the file bytes have not been uploaded yet. */\n checkFileContents?: boolean\n collection: CollectionConfig\n file: File\n req: PayloadRequest\n}\n\nexport type SanitizedUploadConfig = {\n staticDir: UploadConfig['staticDir']\n /**\n * The collection's image sizes, as written at startup by a registered transformer such as\n * `sharpTransformer({ collections: { <slug>: { variants } } })`. Names and admin options\n * only — not authored on the collection.\n */\n variants?: ImageSize[]\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":"AAweA,WAKC"}
@@ -1,8 +1,5 @@
1
1
  import type { Payload } from '../index.js';
2
2
  import type { PayloadRequest } from '../types/index.js';
3
3
  import type { FileToSave } from './types.js';
4
- import type { UploadFileRollbacks } from './uploadFileRollback.js';
5
- export declare const uploadFiles: (payload: Payload, files: FileToSave[], req: PayloadRequest, { uploadFileRollbacks, }?: {
6
- uploadFileRollbacks?: UploadFileRollbacks;
7
- }) => Promise<void>;
4
+ export declare const uploadFiles: (payload: Payload, files: FileToSave[], req: PayloadRequest) => Promise<void>;
8
5
  //# sourceMappingURL=uploadFiles.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"uploadFiles.d.ts","sourceRoot":"","sources":["../../src/uploads/uploadFiles.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,aAAa,CAAA;AAC1C,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAA;AACvD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAA;AAC5C,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAA;AAOlE,eAAO,MAAM,WAAW,YACb,OAAO,SACT,UAAU,EAAE,OACd,cAAc,6BAGhB;IACD,mBAAmB,CAAC,EAAE,mBAAmB,CAAA;CAC1C,KACA,OAAO,CAAC,IAAI,CAwCd,CAAA"}
1
+ {"version":3,"file":"uploadFiles.d.ts","sourceRoot":"","sources":["../../src/uploads/uploadFiles.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,aAAa,CAAA;AAC1C,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAA;AACvD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAA;AAM5C,eAAO,MAAM,WAAW,YACb,OAAO,SACT,UAAU,EAAE,OACd,cAAc,KAClB,OAAO,CAAC,IAAI,CAiBd,CAAA"}