BUGFIX: Optimize dashboard images and downloads - #8
Conversation
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
📝 WalkthroughWalkthroughChangesThe pull request adds versioned WebP dashboard thumbnails for supported raster images. It adds cached delivery, private access validation, thumbnail-aware download accounting, safer range responses, route handling, runtime configuration, purge cleanup, and deployment instructions. Dashboard thumbnails
Possibly related PRs
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
Comment |
There was a problem hiding this comment.
🧹 Nitpick comments (1)
apps/web/src/lib/server/private-grant.test.ts (1)
72-96: 🔒 Security & Privacy | 🔵 Trivial | ⚡ Quick winAdd the inverse purpose-binding assertion.
The test proves that a purpose-bound grant fails without its purpose. It does not prove that an unscoped grant cannot be accepted when the verifier supplies
purpose: 'thumbnail-source'.Add an unscoped grant assertion:
Proposed test addition
await expect( verifyPrivateGrant({ ...base, purpose: 'thumbnail-source' }) ).resolves.toBe(true); await expect(verifyPrivateGrant(base)).resolves.toBe(false); + + const unscopedGrant = await mint(); + await expect( + verifyPrivateGrant({ + ...base, + expiresAtSeconds: unscopedGrant.expiresAtSeconds, + signature: unscopedGrant.signature, + purpose: 'thumbnail-source' + }) + ).resolves.toBe(false);🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@apps/web/src/lib/server/private-grant.test.ts` around lines 72 - 96, Extend the `binds internal grants to their purpose` test to mint an unscoped grant without a purpose, then verify it with `purpose: 'thumbnail-source'` and assert verification resolves to false. Keep the existing purpose-bound grant assertions unchanged.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Nitpick comments:
In `@apps/web/src/lib/server/private-grant.test.ts`:
- Around line 72-96: Extend the `binds internal grants to their purpose` test to
mint an unscoped grant without a purpose, then verify it with `purpose:
'thumbnail-source'` and assert verification resolves to false. Keep the existing
purpose-bound grant assertions unchanged.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro Plus
Run ID: 6413c45f-3ded-4313-9ff9-6b5933275f38
📒 Files selected for processing (8)
apps/web/src/lib/file-thumbnail.test.tsapps/web/src/lib/file-thumbnail.tsapps/web/src/lib/server/auth-policy.test.tsapps/web/src/lib/server/auth-policy.tsapps/web/src/lib/server/private-grant.test.tsapps/web/src/lib/server/private-grant.tsapps/web/src/routes/f/[id]/+server.tsapps/web/src/routes/t/[id]/[version]/grid.webp/+server.ts
🚧 Files skipped from review as they are similar to previous changes (4)
- apps/web/src/lib/file-thumbnail.test.ts
- apps/web/src/lib/server/auth-policy.test.ts
- apps/web/src/routes/t/[id]/[version]/grid.webp/+server.ts
- apps/web/src/lib/file-thumbnail.ts
|
Addressed the final CodeRabbit test nit in 805bea9: the grant tests now prove both directions of purpose binding, including that an ordinary unscoped grant fails thumbnail-source verification. |
|
Addressed the two CodeRabbit documentation nits in 5d8d41b as well: both setup guides now identify the zone that owns CONTENT_ORIGIN as the Image Transformations zone, and the Custom Domains prerequisite says to remove conflicting CNAMEs because deployment creates the application DNS records. |
Summary
Important files
Validation
Note
Add WebP thumbnail generation and serving for dashboard file grid
/t/[id]/[version]/grid.webpthat generates, caches, and serves Cloudflare Image-transformed WebP thumbnails with ETag/304 support, race-safe storage, and quota enforcement.FileThumb.sveltenow requests sized WebP thumbnails for supported image types and retries with a fresh private grant if the initial fetch fails.thumbnail-sourcepurpose; thumbnail-source reads are excluded from download counts via the newshouldRecordFileDownloadfunction.rangeHeadersis refactored to strictly validate R2 range metadata, returningnullon invalid input and correctly distinguishing full (200) from partial (206) responses.thumbnail_size_bytesand thumbnail keys are removed during version purge.Macroscope summarized 7ee3941.
Greptile Summary
Summary
This change adds cached dashboard thumbnails with scoped access grants and storage accounting, and improves download response handling.
Two previously reported thumbnail issues are resolved: failed Cloudflare image transformations are rejected before caching, and competing thumbnail writers retain matching object-size and quota metadata. The remaining issue is in partial download responses: length-only R2 range metadata can produce a
Content-Rangeheader for a different byte interval than the returned body.Confidence Score: 4/5
Partial downloads can still be labeled as a different byte interval from the body returned by R2.
The remaining blocking failure is in
apps/web/src/lib/server/download-response.ts. Although bmdavis419 stated that length-only metadata now begins at byte zero, the current implementation returnsbytes 100-199/1000for{ length: 100 }when the request isbytes=100-199; the body is a prefix and must be labeledbytes 0-99/1000.Files Needing Attention: apps/web/src/lib/server/download-response.ts
What T-Rex did
Comments Outside Diff (1)
General comment
{ length: 100 }but neitheroffsetnorsuffix,rangeHeadersreturnsContent-Range: bytes 100-199/1000for requestbytes=100-199. The required prefix result isbytes 0-99/1000.apps/web/src/lib/server/download-response.ts:70-78, the no-suffix/no-offset branch falls back torequestedRangeOffset(requestedRange, ...), which uses the request start rather than treating length-only metadata as a prefix range.rangehas a numericlengthbut no numericoffsetand no numericsuffix, set the response offset to0; retain the existing explicit-suffix branch for end-relative behavior.Prompt To Fix All With AI
Reviews (10): Last reviewed commit: "fix: keep unavailable thumbnails private" | Re-trigger Greptile