Add support for content-disposition to r2.getUrl
- Dominant language
- TypeScript
- Stars
- 49
- Forks
- 26
- Avg merge
- 6h 22m
- Merged PRs (30d)
- 1
Description
### Summary
Please add built-in support in `@convex-dev/r2` for generating signed URLs that force file download with a specific filename (i.e. `Content-Disposition: attachment; filename=...`).
### Problem
Right now, `r2.getUrl(key, { expiresIn })` is great for basic access, but it does not let me control download behavior/filename.
In static frontend apps, this causes browser-dependent behavior:
- PDFs/images often open inline instead of downloading
- `_blank`-based workarounds can trigger popup blockers (notably Safari)
- `` is unreliable for cross-origin signed URLs
To get reliable downloads with a chosen filename, I currently have to bypass the component and manually use AWS SDK presigning with `ResponseContentDisposition`. That adds extra dependencies and duplicated signing logic in app code.
### Proposed API
Any of these would solve allowing downloads with a particular filename:
1. Extend `getUrl` options:
```ts
await r2.getUrl(key, {
expiresIn: 900,
disposition: "attachment",
filename: "Pitch Deck.pdf",
});
```
2. Or add a convenience method:
```ts
await r2.getDownloadUrl(key, {
expiresIn: 900,
filename: "Pitch Deck.pdf",
});
```
Separately for full control, allow user to set the content-disposition:
```ts
r2.getUrl(key, {
expiresIn: 900,
contentDisposition: `attachment; ...`
}
```
### Expected behavior
- Returned URL forces download (attachment), not inline render.
- Download uses the provided filename.
- UTF-8 filename support should be handled correctly.
- Backward-compatible with existing getUrl usage.
Contributor guide
Research direction
Locate the `getUrl` entry point and inspect how signed URL options are passed to Cloudflare R2. Compare the proposed option shapes and determine how content disposition and UTF-8 filenames should be encoded without changing existing usage. Done means generated URLs force attachment downloads with the requested filename while preserving current behavior.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- typescript
- Domain
- api, backend, cloud
- Issue type
- Feature
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 42/100