Skip to content

Commit 5ca9bd4

Browse files
fix: handle absolute paths correctly with tempFileDir upload option (#14436)
### What? This PR fixes `tempFileDir` configuration not respecting absolute paths when `useTempFiles` is enabled for uploads. ### Why? 1. **Absolute paths ignored**: Setting `tempFileDir: '/tmp'` would still create temp files under the working directory (e.g., `/Users/project/tmp/...`) instead of `/tmp/...` 2. **Path duplication**: The default `tempFileDir` could result in duplicated working directory segments in the path ### How? Uses `path.resolve()` to handle both cases: - Absolute paths (e.g., `/tmp`) are returned as-is - Relative paths (e.g., `tmp`) are resolved against `process.cwd()` Fixes#12910 --------- Co-authored-by: Jessica Chowdhury <jessica@trbl.design>
1 parent fa1cd62 commit 5ca9bd4

6 files changed

Lines changed: 20 additions & 6 deletions

File tree

‎docs/upload/overview.mdx‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,7 @@ Upload options are specifiable on a Collection by Collection basis, you can also
132132
|**`preserveExtension`**| Preserves file extensions with the `safeFileNames` option. Limits file names to 3 characters if `true` or a custom length if a `number`, trimming from the start of the extension. |
133133
|**`responseOnLimit`**| A `string` that is sent in the Response to a client if the file size limit is exceeded when used with `abortOnLimit`. |
134134
|**`safeFileNames`**| Set to `true` to strip non-alphanumeric characters except dashes and underscores. Can also be set to a regex to determine what to strip. Defaults to `false`. |
135-
|**`tempFileDir`**| A `string` path to store temporary files used when the `useTempFiles` option is set to `true`. Defaults to `'./tmp'`. |
135+
|**`tempFileDir`**| A `string` path to store temporary files used when the `useTempFiles` option is set to `true`. Defaults to `'tmp'` in the current working directory. Supports absolute paths.|
136136
|**`uploadTimeout`**| A `number` that defines how long to wait for data before aborting, specified in milliseconds. Set to `0` to disable timeout checks. Defaults to `60000`. |
137137
|**`uriDecodeFileNames`**| Set to `true` to apply uri decoding to file names. Defaults to `false`. |
138138
|**`useTempFiles`**| Set to `true` to store files to a temporary directory instead of in RAM, reducing memory usage for large files or many files. |

‎packages/payload/src/config/types.ts‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -676,7 +676,7 @@ export type FetchAPIFileUploadOptions = {
676676
* Used along with the `useTempFiles` option. By default this module uses `'tmp'` folder
677677
* in the current working directory.
678678
* You can use trailing slash, but it is not necessary.
679-
* @default './tmp'
679+
* @default 'tmp'
680680
*/
681681
tempFileDir?: string|undefined
682682
/**

‎packages/payload/src/uploads/fetchAPI-multipart/handlers.ts‎

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,7 @@ type Handler = (
2121
}
2222

2323
exportconsttempFileHandler: Handler=(options,fieldname,filename)=>{
24-
constdir=path.normalize(options.tempFileDir!)
25-
consttempFilePath=path.join(process.cwd(),dir,getTempFilename())
24+
consttempFilePath=path.resolve(options.tempFileDir!,getTempFilename())
2625
checkAndMakeDir({createParentPath: true},tempFilePath)
2726

2827
debugLog(options,`Temporary file path is ${tempFilePath}`)

‎packages/payload/src/uploads/fetchAPI-multipart/index.ts‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ const DEFAULT_UPLOAD_OPTIONS: FetchAPIFileUploadOptions = {
1717
preserveExtension: false,
1818
responseOnLimit: 'File size limit has been reached',
1919
safeFileNames: false,
20-
tempFileDir: path.join(process.cwd(),'tmp'),
20+
tempFileDir: 'tmp',// Relative path is created inside current workdir.
2121
uploadTimeout: 60000,
2222
uriDecodeFileNames: false,
2323
useTempFiles: false,

‎packages/payload/src/uploads/fetchAPI-multipart/utilities.ts‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,7 @@ export const checkAndMakeDir: CheckAndMakeDir = (fileUploadOptions, filePath) =>
118118
returnfalse
119119
}
120120
// Check whether folder for the file exists.
121-
constparentPath=path.dirname(filePath)
121+
constparentPath=path.dirname(path.resolve(filePath))
122122
// Create folder if it doesn't exist.
123123
if(!fs.existsSync(parentPath)){
124124
fs.mkdirSync(parentPath,{recursive: true})

‎test/uploads/int.spec.ts‎

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ import type { Enlarge, Media } from './payload-types.js'
1515

1616
// eslint-disable-next-line payload/no-relative-monorepo-imports
1717
import{getExternalFile}from'../../packages/payload/src/uploads/getExternalFile.js'
18+
// eslint-disable-next-line payload/no-relative-monorepo-imports
19+
import{tempFileHandler}from'../../packages/payload/src/uploads/fetchAPI-multipart/handlers.js'
1820
import{initPayloadInt}from'../__helpers/shared/initPayloadInt.js'
1921
import{createStreamableFile}from'./createStreamableFile.js'
2022
import{
@@ -1742,6 +1744,19 @@ describe('Collections - Uploads', () => {
17421744
}
17431745
})
17441746
})
1747+
1748+
describe('tempFileDir',()=>{
1749+
it.each([
1750+
{dir: '/tmp',expectedPrefix: '/tmp',description: 'absolute path like /tmp'},
1751+
{dir: 'tmp',expectedPrefix: path.join(process.cwd(),'tmp'),description: 'relative path'},
1752+
])('creates temp files in correct location for $description',({ dir, expectedPrefix })=>{
1753+
consthandler=tempFileHandler({tempFileDir: dir},'field','file.png')
1754+
constfilePath=handler.getFilePath()
1755+
1756+
expect(filePath.startsWith(expectedPrefix)).toBe(true)
1757+
handler.cleanup()
1758+
})
1759+
})
17451760
})
17461761

17471762
asyncfunctionfileExists(fileName: string): Promise<boolean>{

0 commit comments

Comments
 (0)