Skip to content

Conversation

@ZL-Asica
Copy link
Member

feat(cache): attachment-level image caching, RSC-safe fix

✨ Features Updates && πŸ› Bug Fix && πŸ›  Code Refactor && πŸ“¦ Dependency Update

πŸ“Œ Description

This PR refactors how Airtable-backed images are cached and served. Instead of pushing Airtable’s signed src URLs down to the client and letting the /api/images route warm R2 on demand, image caching is now handled at the attachment level on the server:

  • The Airtable cache store now implements transformAttachment (provided by TS-Airtable), which:
    • Detects image attachments.
    • Ensures AVIF/WebP variants are present in R2 (ensureImageInR2).
    • Rewrites the attachment url to a stable local path (/api/images/{attId}/{variant}/{filename}).
  • The /api/images API route has been simplified to only read from R2. It no longer accepts src or mode query params and simply:
    • Chooses AVIF/WebP based on the Accept header.
    • Falls back to the other format if the preferred one is missing.
    • Returns a default image, also based on the preferred format, when the cache is missed instead of trying to pull from Airtable directly or return faultful 404 error.

On the fetching side, getImgUrlFromAttachmentObj is much simpler: it just returns the url of the first attachment. When used with the updated cache store, that url is already the stable /api/images/... path, so components don’t have to know about Airtable or cache-warming at all.

Alongside the caching changes, this PR also:

  • Updates Next.js / React / ts-airtable / ESLint-related dependencies to the latest compatible patch versions.
    • This also addresses the critical security vulnerability bug CVE-2025-55182 in React and Next.js.
  • Switches Markdownformatting over to ESLint (instead of Prettier), and removes the **.md ignore from the ESLint config so .md/.mdx files are linted automatically.
  • Cleans up a couple of inline eslint-disable comments that referenced a rule we’re no longer using.
  • Updates the DTR β€œApply” content to point to /letters instead of the older agile research paper.
  • Add 5 minutes buffer for Cloudflare R2 garbage collection to avoid GitHub action running exactly 24 hours each.

Overall, this keeps Airtable URLs server-side, makes the image pipeline simpler, and simplifies how components consume image URLs.

πŸ” Feature Changes

  • New component or page
    • New server utility: src/lib/image-cache.ts encapsulates all image caching logic (key building, transcoding, R2 writes, and access tagging).
  • API update
    • /api/images/[...path] now:
      • Only serves from R2 using buildImageObjectKey + r2Get/r2Head.
      • No longer accepts src/mode query parameters.
      • Returns a default image if no cached object exists, expecting the server-side attachment transform to have warmed R2 beforehand.
  • UI/UX improvement
  • Other:
    • Airtable image attachments are now transformed on the server (transformAttachment) (provided by TS-Airtable) so that client code only ever sees stable /api/images/... URLs and never Airtable signed URLs.
    • Cloudflare R2 garbage collection now have 5 minutes buffer for the logic statement.

πŸ”„ Refactor Changes

  • Code optimization
    • Image transcoding now happens once per attachment (via ensureImageInR2), instead of being tied to the API route.
    • The API route uses simple HEAD checks with a small helper (tryHead) to find the best available format.
  • Improve maintainability
    • Image caching concerns are centralized in src/lib/image-cache.ts and reused by both the Airtable cache store and possibly the API route.
    • getImgUrlFromAttachmentObj has a minimal surface (no more variant or prefetch options).
  • Remove unnecessary code
    • Removed warm-only mode and src query handling from /api/images.
    • Removed the perfectionist/sort-imports override for src/lib/airtable/airtable.ts; imports there are now sorted normally.
    • Removed Prettier from dev dependencies and the Prettier-only lint-staged hook.
  • Other: ...

πŸ›  Bug Fixes

  • Fixed issue
    • Critical Security Vulnerability in React Server Components CVE-2025-55182.
    • Records caching will cache the original Airtable attachment URL, which might not alreadybe cached in the R2 storage.
  • Improved error handling
    • Image will no longer return 404. It returns the default picture instead.
  • Performance fix
  • Other: ...

βœ… Checklist

  1. Feature Updates:
  • Code follows project coding style.
  • Tested in a Next.js environment (next dev, next build, next start).
  • Relevant documentation is updated (especially any internal notes about image caching and Airtable usage).
  1. Bug Fixes:
  • Bug has been reproduced and verified.
  • Fix does not introduce new issues.
  • Added necessary tests.
  1. Code Refactor:
  • No breaking changes introduced in public APIs or commonly used utilities.
  • Performance improvement validated (image responses served from R2 as expected; no unexpected transcoding on the hot path).
  • Documentation updated if necessary
    • Internal docs describing how recordsCache + transformAttachment should be used.
    • Detailed caching-related documentation can be found on the Caching | Airtable TS documentation site.
  1. Dependency Updates:
  • Verified functionality after update.
  • Checked for security vulnerabilities using pnpm audit.

πŸ“œ Dependency Changes

Dependency Name Old Version New Version Reason
pnpm (packageManager) 10.22.0 10.25.0 Keep local tooling in sync with newer pnpm features/bugfixes
next 16.0.3 16.0.9 Address CVE-2025-55182
@next/third-parties 16.0.3 16.0.9 Match core Next.js version
react 19.2.0 19.2.2 Address CVE-2025-55182
react-dom 19.2.0 19.2.2 Address CVE-2025-55182
ts-airtable 0.2.3 0.3.1 Use new transformAttachment hook for attachment-level caching
lucide-react 0.554.0 0.560.0 Keep icon library up to date
eslint-config-next 16.0.3 16.0.9 Match updated Next.js version in linting config
@types/react 19.2.6 19.2.7 Keep React type definitions in sync
baseline-browser-mapping N/A 2.9.6 New dev dependency required by updated Next/Tailwind toolchain

πŸ’¬ Additional Notes

  • ESLint / formatting changes

    • eslint.config.mjs no longer ignores **.md, and lint-staged now runs ESLint on js/jsx/ts/tsx/json/md/mdx instead of using Prettier for Markdown.
    • Prettier has been removed from devDependencies and the extra lint-staged mapping for src/**/*.{md,json} has been deleted.
  • Type and logging updates

    • src/types/images.d.ts defines ImageFormat and ImageVariant to avoid stringly-typed formats and variants.
    • src/types/kv-logger.d.ts adds a new CacheKind variant: 'transformAttachmentError', used when transformAttachment fails.
    • createCloudflareApiKvCacheStore logs transformAttachmentError events via safeLog but always falls back to the original attachment url so calls remain resilient.
  • Docs

    • src/content/apply.md now points applicants to the /letters page instead of the agile research paper, which is more aligned with the current onboarding experience.

@ZL-Asica ZL-Asica self-assigned this Dec 11, 2025
@ZL-Asica ZL-Asica added bug general issues with the website enhancement general tag for new features to add labels Dec 11, 2025
@github-actions
Copy link

🎨 Lint Check

βœ… Lint: No linting issues found!

@ZL-Asica ZL-Asica force-pushed the fix/react-server-components-bug branch from c4813b6 to 834e223 Compare December 11, 2025 23:16
@ZL-Asica ZL-Asica marked this pull request as ready for review December 11, 2025 23:16
Copilot AI review requested due to automatic review settings December 11, 2025 23:16
@github-actions
Copy link

🎨 Lint Check

βœ… Lint: No linting issues found!

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR refactors the image caching architecture to handle image optimization at the attachment level on the server using ts-airtable's transformAttachment hook. It also addresses the critical CVE-2025-55182 security vulnerability by updating Next.js and React, and includes various dependency updates and code cleanup.

Key changes:

  • Server-side image caching via transformAttachment ensures images are warmed in R2 before being served
  • Simplified /api/images route that only reads from R2 and serves default images on cache miss
  • Updated dependencies to address CVE-2025-55182 and other security/compatibility issues

Reviewed changes

Copilot reviewed 11 out of 15 changed files in this pull request and generated no comments.

Show a summary per file
File Description
src/lib/image-cache.ts New server utility centralizing image caching logic (key building, transcoding, R2 operations)
src/utils/image.ts Simplified to just return attachment URL (now pre-transformed by cache store)
src/app/api/images/[...path]/route.ts Refactored to only serve from R2 with format negotiation and default image fallback
src/lib/airtable/cloudflare-kv-cache.ts Implements transformAttachment to warm R2 and rewrite URLs for image attachments
src/types/images.d.ts Added ImageFormat and ImageVariant type definitions
src/types/kv-logger.d.ts Added transformAttachmentError cache kind for logging
src/lib/r2/r2-gc.ts Updated interval check from hours to minutes with 5-minute buffer
package.json Updated Next.js, React, ts-airtable, and other dependencies; removed Prettier
eslint.config.mjs Removed **.md ignore and import sorting override
Component files Cleaned up eslint-disable comments removing obsolete rule references

πŸ’‘ Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@ZL-Asica ZL-Asica merged commit 1bbf549 into main Dec 11, 2025
8 checks passed
@ZL-Asica ZL-Asica deleted the fix/react-server-components-bug branch December 11, 2025 23:18
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug general issues with the website enhancement general tag for new features to add size/M

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants