Skip to content

feat(uploads): let apps serve chosen active content types inline - #2975

Merged
Tobbe merged 1 commit into
mainfrom
feat/uploads-inline-types
Oct 10, 2026
Merged

Tobbe merged 1 commit into
mainfrom
feat/uploads-inline-types

Conversation

@Tobbe

@Tobbe Tobbe commented Oct 10, 2026 •

Copy link
Copy Markdown
Member

Fixes #2970

The uploads serve route sends active content (HTML, SVG, XML, JavaScript and PDF) as Content-Disposition: attachment, even when the signed URL asks for inline. That's a safe default, but it means an app can't preview stored PDFs in the browser: an <iframe src={signedUrl}> opens a download dialog and shows a blank frame.

cedarUploadsPlugin now takes an inlineTypes option that lists active-content MIME types the serve route may send inline when the signed URL asks for inline:

await server.register(cedarUploadsPlugin, {
  tokenSecret: process.env.UPLOAD_TOKEN_SECRET,
  targets,
  db,
  inlineTypes: ['application/pdf'],
})
  • The default is unchanged. Without inlineTypes, every active type is still served as an attachment.
  • A listed type is served inline only when the signed URL asks for inline. Signed URLs still default to attachment.
  • Types are compared case-insensitively and without parameters.
  • S3 targets are unaffected. Their presigned URLs point at the bucket, and the disposition signed into the URL is already used as-is.

The issue also suggests serving inline active content with Content-Security-Policy: sandbox. This PR doesn't include that, because Chrome refuses to render PDFs in sandboxed documents, which would defeat the point for PDFs.

The uploads docs describe the option under "Reading files back" and list it with the other plugin options.

@netlify

netlify Bot commented Oct 10, 2026 •

Copy link
Copy Markdown

✅ Deploy Preview for cedarjs ready!

Name Link
🔨 Latest commit e080b82
🔍 Latest deploy log https://app.netlify.com/projects/cedarjs/deploys/6aca420815dedb0008ef7d54
😎 Deploy Preview https://deploy-preview-2975--cedarjs.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.
🤖 Make changes Run an agent on this branch

To edit notification comments on pull requests, go to your Netlify project configuration.

@coderabbitai

coderabbitai Bot commented Oct 10, 2026 •

Copy link
Copy Markdown

Review in Change Stack →

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration
  • Configuration used: Organization UI
  • Review profile: ASSERTIVE
  • Plan: Advanced
  • Run ID: d5f67983-24ec-44ce-b864-520321f10a87

📥 Commits

Reviewing files that changed from the base of the PR and between edb0659 and e080b82.


📒 Files selected for processing (3)
  • docs/docs/uploads.md
  • packages/uploads/src/__tests__/plugin.test.ts
  • packages/uploads/src/fastify/plugin.ts

Included review availability: This review used your included allowance. Your plan provides up to 2 included reviews per hour; 0 remain after this review.



📝 Summary

Summary by CodeRabbit

  • New Features
    • Uploads can now be configured to display selected active content types inline. Other active content types continue to download rather than render in the browser.
    • For configured types, the disposition requested by the signed URL is respected, including explicit attachment requests.
  • Documentation
    • Clarified how inline content handling works for filesystem uploads and S3, and documented the inlineTypes option.

Walkthrough

The uploads plugin adds an inlineTypes option for active MIME types. The filesystem serve route uses the signed URL’s requested disposition for configured types and continues to force attachments for other active types. Tests and documentation cover the option and its behavior.

Changes

Upload inline serving

Layer / File(s) Summary
Define and normalize inline types
packages/uploads/src/fastify/plugin.ts, docs/docs/uploads.md
UploadPluginOptions adds inlineTypes. The plugin trims, removes MIME parameters, and lowercases configured values before comparison. The option is also documented.
Apply and verify serve disposition
packages/uploads/src/fastify/plugin.ts, packages/uploads/src/__tests__/plugin.test.ts, docs/docs/uploads.md
The serve route uses the signed URL’s requested disposition for allowlisted active MIME types. Tests cover configured PDFs, explicit attachments, unlisted active SVG content, and behavior without the option. Documentation describes filesystem and S3 disposition behavior.

Priority: ➖ Normal

Severity of issue fixed: Medium

Merge Risk: ⚪ Minimal · up to e080b

This adds an opt-in setting for serving chosen file types inline. The default behavior is unchanged, and no merge-blocking risk was identified.

Pre-merge checks | Passed 4 | Failed 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage Warning Docstring coverage is 20.00% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 5 functions across 2 files. (1 skipped: 1… Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check Passed The title clearly and concisely identifies the main change: allowing applications to serve selected active content types inline.
Description check Passed The description directly explains the inlineTypes option, default attachment behavior, MIME type matching, S3 behavior, testing, and the excluded sandbox CSP proposal.
Linked Issues check Passed [Issue #2970] The plugin adds inlineTypes and normalizes configured and stored MIME types by removing parameters, trimming whitespace, and lowercasing. The serve route permits inline only for conf…
Out of Scope Changes check Passed The changed implementation, tests, and documentation all support [Issue #2970]. The implementation adds the requested plugin option and serve-route behavior. The tests verify the safety default and di…

Full details: Docstring Coverage

Explanation

Docstring coverage is 20.00% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 5 functions across 2 files. (1 skipped: 1 unsupported.)


  • Fix all pre-merge checks with AI
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

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.

@greptile-apps

greptile-apps Bot commented Oct 10, 2026 •

Copy link
Copy Markdown
Contributor

RetriggerConfidence Score: 4/5

[Medium impact] Adds opt-in inline serving for specific file types in uploads.

The PR appears safe to merge, with a non-blocking gap in the MIME matching tests.

Findings

  1. P2 MIME parameters lack test coverage ▶

Summary

Adds inlineTypes so apps can allow selected active-content MIME types to render inline through the upload serve route.

  • Apps can preview chosen active upload types in the browser.

Reviews (1) · Last reviewed commit: "feat(uploads): let apps serve chosen act..." · Reviewed by Greptile

Comment on lines +452 to +456
test('serves a listed active type inline when inline was signed', async () => {
const res = await servePdf(inlineApp, 'inline')

expect(res.statusCode).toBe(200)
expect(res.headers['content-disposition']).toMatch(/^inline;/)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P2 MIME parameters lack test coverage

The new tests cover mixed case in inlineTypes, but neither the option nor the stored MIME type includes parameters. Add cases with parameters on each side, plus a mixed-case stored type. Otherwise, breaking the promised parameter-insensitive matching could pass these tests and make PDF previews download instead.

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Not adding these. A stored type can't carry parameters: storeFile rejects a MIME type like application/pdf; version=1.7 as invalid, so a stored type with parameters can't reach the serve route. Case-insensitive matching is already covered through inlineTypes, and both sides go through the same normalize helper, so a stored-side case test would exercise the same code path again.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

You're right. storeFile rejects MIME types containing parameters, so a parameterized stored MIME value isn't reachable through that path. Since normalizeMimeType is shared by both inlineTypes and the serve-side value, the existing mixed-case inlineTypes test already covers the case-insensitive normalization behavior. I'll withdraw the request for those additional tests.

@github-actions github-actions Bot added this to the next-release milestone Oct 10, 2026
@nx-cloud

nx-cloud Bot commented Oct 10, 2026 •

Copy link
Copy Markdown

View your CI Pipeline Execution ↗ for commit e080b82

Command Status Duration Result
nx run-many -t build:pack --exclude create-ceda... ✅ Succeeded 4s View ↗
nx run-many -t build ✅ Succeeded <1s View ↗
nx run-many -t build --output-style=stream ✅ Succeeded 2m 51s View ↗

💡 Verify your cache is correct by running tasks in a sandbox. Read docs ↗


☁️ Nx Cloud last updated this comment at 2026-10-10 13:55:34 UTC

@Tobbe
Tobbe merged commit 51d9daf into main Oct 10, 2026
38 checks passed
@Tobbe
Tobbe deleted the feat/uploads-inline-types branch October 10, 2026 14:31
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.

uploads: let apps serve PDFs inline (today every PDF is forced to attachment)

1 participant