Skip to content

fix(pushduck): use routeConfig.expiresIn for presigned download URL expiry#182

Open
3nvy wants to merge 1 commit intoabhay-ramesh:mainfrom
3nvy:fix/download-presigned-url-default-expiresin
Open

fix(pushduck): use routeConfig.expiresIn for presigned download URL expiry#182
3nvy wants to merge 1 commit intoabhay-ramesh:mainfrom
3nvy:fix/download-presigned-url-default-expiresin

Conversation

@3nvy
Copy link
Copy Markdown

@3nvy 3nvy commented Mar 11, 2026

📝 Pull Request

📋 Description

Uses expiresIn value from routeConfig for generatePresignedDownloadUrl when generating presigned urls from the upload complete phase

🎯 What does this PR do?

Uses expiresIn value from routeConfig instead of the hardcoded 3600

🔗 Related Issues

  • Closes #
  • Related to #

🧪 Type of Change

  • 🐛 Bug fix (non-breaking change that fixes an issue)
  • ✨ New feature (non-breaking change that adds functionality)
  • 💥 Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • 📚 Documentation update
  • 🔧 Refactoring (no functional changes)
  • ⚡ Performance improvement
  • 🧪 Test improvements
  • 🏗️ Build system changes
  • 📦 Dependencies update

Testing

🧪 How Has This Been Tested?

  • Unit tests
  • Integration tests
  • Manual testing
  • Browser testing (if applicable)

📊 Test Coverage

  • Added tests for new functionality
  • Updated existing tests
  • No tests needed (documentation, etc.)

🔍 Manual Testing Steps


📸 Screenshots / Videos (if applicable)

Before:

After:


🔧 Configuration Changes

  • Environment variables updated
  • Configuration files updated
  • Build scripts updated
  • Package.json changes
  • Dependencies added/removed

📚 Documentation

  • Updated README.md
  • Updated API documentation
  • Updated examples
  • Updated changelog (will be handled by changeset)
  • Added inline code comments
  • No documentation updates needed

🛡️ Security

  • No security implications
  • Reviewed for security vulnerabilities
  • Updated dependencies for security patches
  • Added input validation
  • Reviewed authentication/authorization changes

📦 Bundle Impact

  • Bundle size increase is acceptable (< 5KB)
  • Bundle size decreased
  • No impact on bundle size
  • Needs bundle size review

🚀 Deployment

🔄 Migration Required?

  • No migration needed
  • Database migration required
  • Configuration migration required
  • Breaking changes require user migration

⚠️ Deployment Notes


Pre-Release Checklist

  • 🛡️ Pre-release safety check passed
  • 📝 Changeset added (for releases)
  • 🧪 All CI checks passed
  • 📊 Code coverage maintained/improved
  • 📚 Documentation updated
  • 🎯 Addresses linked issues
  • 🔍 Code review completed
  • ✅ Ready for release

📝 Changeset Information

📦 Package(s) Affected:

  • pushduck
  • create-pushduck

🔖 Version Bump Type:

  • patch (bug fixes)
  • minor (new features)
  • major (breaking changes)

📋 Changeset Summary:


🤝 Reviewer Guidelines

🔍 What to Review:

  • Code quality and style
  • Test coverage and quality
  • Performance implications
  • Security considerations
  • Breaking changes
  • Documentation accuracy

⚡ Priority Review Areas:


📎 Additional Notes


📧 Author: @
🏷️ Labels:
🎯 Milestone:


🙏 Thank You!

Thanks for contributing to pushduck! Your changes help make file uploads easier for everyone. 🚀

Summary by CodeRabbit

  • Improvements
    • Download URLs now support customizable expiration times per route, enabling more flexible control over access duration. Defaults to existing behavior when not configured.

@3nvy 3nvy requested a review from abhay-ramesh as a code owner March 11, 2026 17:06
@vercel
Copy link
Copy Markdown
Contributor

vercel Bot commented Mar 11, 2026

@3nvy is attempting to deploy a commit to the Abhay's projects Team on Vercel.

A member of the Team first needs to authorize it.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Mar 11, 2026

📝 Walkthrough

Walkthrough

The pull request replaces a hard-coded 3600-second expiration value with a configurable routeConfig.expiresIn property for presigned download URLs in the upload completion handler, enabling per-route expiration customization.

Changes

Cohort / File(s) Summary
Download URL Expiration Configuration
packages/pushduck/src/core/router/router-v2.ts
Replaced hard-coded 3600 second expiration with per-route routeConfig.expiresIn for presigned download URL generation in the upload completion flow.

Estimated code review effort

🎯 1 (Trivial) | ⏱️ ~2 minutes

Possibly related PRs

Poem

🐰 A rabbit hops with glee,
Config made flexible as can be!
No more numbers carved in stone,
Per-route expiry, now fully grown! ✨

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately summarizes the main change: using routeConfig.expiresIn instead of a hardcoded value for presigned download URL expiry. It is concise, clear, and specific.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Description check ✅ Passed The PR description includes all critical sections: clear description of changes, type of change selection, and testing information indicating unit tests performed.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@3nvy 3nvy changed the title fix(pushduck): use routeConfig.expiresIn for presigned download URL e… fix(pushduck): use routeConfig.expiresIn for presigned download URL expiry Mar 11, 2026
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@packages/pushduck/src/core/router/router-v2.ts`:
- Around line 990-994: The code is reusing routeConfig.expiresIn
(S3Route.expiresIn / S3RouteConfig.expiresIn) for download links when calling
generatePresignedDownloadUrl with completion.key, which unintentionally shortens
download TTLs; introduce a separate download expiry (e.g.,
S3Route.downloadExpiresIn or S3RouteConfig.downloadExpiresIn), update the route
config/type declarations and docs to describe it, and change the call site to
pass routeConfig.downloadExpiresIn (falling back to a sensible default constant
if unset) instead of routeConfig.expiresIn so upload and download TTLs are
independent.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: a22a511b-3efd-4326-866c-6aa0eb256eb0

📥 Commits

Reviewing files that changed from the base of the PR and between c218dcc and 77be6fa.

📒 Files selected for processing (1)
  • packages/pushduck/src/core/router/router-v2.ts

Comment on lines 990 to 994
const presignedUrl = await generatePresignedDownloadUrl(
this.config,
completion.key,
3600
routeConfig.expiresIn
);
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot Mar 11, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Don't reuse the upload TTL as the download TTL implicitly.

routeConfig.expiresIn is currently documented in this file as the presigned upload URL expiry (S3Route.expiresIn and S3RouteConfig.expiresIn), but this change also applies it to the completion-time download URL. That makes short upload windows also shorten returned download links, which is a visible contract change for existing routes. Please either introduce a separate download-expiry setting or update the route API/docs explicitly so this isn't an undocumented behavior change.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/pushduck/src/core/router/router-v2.ts` around lines 990 - 994, The
code is reusing routeConfig.expiresIn (S3Route.expiresIn /
S3RouteConfig.expiresIn) for download links when calling
generatePresignedDownloadUrl with completion.key, which unintentionally shortens
download TTLs; introduce a separate download expiry (e.g.,
S3Route.downloadExpiresIn or S3RouteConfig.downloadExpiresIn), update the route
config/type declarations and docs to describe it, and change the call site to
pass routeConfig.downloadExpiresIn (falling back to a sensible default constant
if unset) instead of routeConfig.expiresIn so upload and download TTLs are
independent.

Copy link
Copy Markdown
Author

@3nvy 3nvy Mar 11, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Uhm, I guess this makes sense if we want different times for both upload and download, tho not sure this matters for the purpose of the upload flow, as expirations can be set separately afterwards on subsquent requests. I'll leave the choice to you :)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@3nvy, thanks for the context! Here's my take:

The concern is subtle but real. The completion-time download URL isn't just used immediately — onUploadComplete hooks commonly persist it (e.g., save it to a DB), where it must survive until users actually access the file. If a route sets expiresIn(300) for a tight upload window, the returned download URL would silently expire in 5 minutes, which could be surprising.


Option A – Separate downloadExpiresIn (recommended)

This keeps upload and download TTLs independent and explicit:

// In S3RouteConfig
interface S3RouteConfig<TMetadata = any> {
  expiresIn?: number;          // upload URL TTL
  downloadExpiresIn?: number;  // download URL TTL (falls back to expiresIn, then 3600)
  // ...
}
// In S3Route
downloadExpiresIn(seconds: number): this {
  if (seconds <= 0 || seconds > 604800) {
    throw new Error(
      `downloadExpiresIn must be between 1 and 604800 seconds (7 days), got ${seconds}`
    );
  }
  this.config.downloadExpiresIn = seconds;
  return this;
}
// In handleUploadComplete
const presignedUrl = await generatePresignedDownloadUrl(
  this.config,
  completion.key,
  routeConfig.downloadExpiresIn ?? routeConfig.expiresIn  // fallback chain
);

Option B – Keep this PR, update docs only

If you'd prefer to ship the simplest fix now and treat expiresIn as controlling both, at minimum the stale comment on CompletionResponse and the JSDoc on S3Route.expiresIn() should be updated:

/** Presigned upload URL expiration time in seconds (default: 3600 = 1 hour) */
expiresIn?: number;

/** Presigned URL expiration time in seconds for both upload and download URLs (default: 3600 = 1 hour) */
expiresIn?: number;

And in CompletionResponse:

presignedUrl?: string; // Temporary download URL (expires per routeConfig.expiresIn)

Option A is cleaner long-term; Option B is an acceptable minimal fix if scope needs to stay small. Your call!

Copy link
Copy Markdown
Owner

@abhay-ramesh abhay-ramesh Mar 13, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Uhm, I guess this makes sense if we want different times for both upload and download, tho not sure this matters for the purpose of the upload flow, as expirations can be set separately afterwards on subsquent requests. I'll leave the choice to you :)

Yep @3nvy even i was thinking of a better way to get this right, working on beta branch for slightly different api structure

was thinking of doing it like this

.expiriesIn(3600) // Sets Both Upload and Download TTL

// and can also be done like
.expiriesIn({ upload: 3600, download: 600 })

would like your opinion!
might be good if people want to specify per route TTL, if needed they can override anytime (which is already implemented)

upload TTL per route was definitely required, thanks for that @3nvy

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems like the humans are having a chat. I'll hop back into my burrow for now. If you need me again, just tag @coderabbitai in a new comment, and I'll come hopping out!

Copy link
Copy Markdown
Author

@3nvy 3nvy Mar 13, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh yeah that works perfectly 🙌 , is that's something your already doing for the beta api? if so Im happy to close this PR and wait for your changes :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants