Skip to content

refactor: Centralize image and binary extension utilities#2363

Open
charlesvien wants to merge 4 commits into
mainfrom
05-25-centralize_image_extension_and_mime_utilities
Open

refactor: Centralize image and binary extension utilities#2363
charlesvien wants to merge 4 commits into
mainfrom
05-25-centralize_image_extension_and_mime_utilities

Conversation

@charlesvien
Copy link
Copy Markdown
Member

@charlesvien charlesvien commented May 25, 2026

Problem

Image extension sets and MIME mappings were duplicated across 9+ files, causing inconsistent behavior across paste, drag/drop, attachments, thumbnails and Claude API conversion.

Changes

  1. Add @posthog/shared/image as canonical source: IMAGE_MIME_TYPES, ALLOWED_IMAGE_MIME_TYPES, CLAUDE_IMAGE_EXTENSIONS, ClaudeImageMimeType, plus isImageFile / isRasterImageFile / isClaudeImageFile /
    isGifFile / getImageMimeType / parseImageDataUrl
  2. Add @posthog/shared/binary with BINARY_EXTENSIONS and isBinaryFile, image portion derived from the canonical image set
  3. Delete apps/code/src/shared/constants/image.ts and apps/code/src/shared/utils/imageDataUrl.ts; migrate 7 importers to @posthog/shared
  4. Wire @posthog/shared into mobile (package.json dep + Metro alias to TS source)
  5. Replace local COMMON_IMAGE_EXTENSIONS and ImageMimeType union in the Claude ACP adapter with shared exports
  6. Switch CodeEditorPanel to isRasterImageFile so SVGs keep opening in CodeMirror (broad isImageFile now includes svg/heic)

How did you test this?

Manually

Publish to changelog?

no

Copy link
Copy Markdown
Member Author

charlesvien commented May 25, 2026

This stack of pull requests is managed by Graphite. Learn more about stacking.

@charlesvien charlesvien changed the title Centralize image extension and MIME utilities refactor: Centralize image and binary extension utilities May 25, 2026
@charlesvien charlesvien force-pushed the 05-25-centralize_image_extension_and_mime_utilities branch from bc3bf9d to 5b0b845 Compare May 25, 2026 22:07
@charlesvien charlesvien changed the base branch from 05-20-dev_bar to graphite-base/2363 May 26, 2026 00:03
@charlesvien charlesvien force-pushed the 05-25-centralize_image_extension_and_mime_utilities branch from 5b0b845 to cd7faa3 Compare May 26, 2026 00:04
@charlesvien charlesvien force-pushed the graphite-base/2363 branch from e6f92b8 to e7cc5a9 Compare May 26, 2026 00:04
@charlesvien charlesvien changed the base branch from graphite-base/2363 to main May 26, 2026 00:04
@charlesvien charlesvien marked this pull request as ready for review May 26, 2026 00:45
@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps Bot commented May 26, 2026

T-Rex T-Rex Logs

What T-Rex did

  • Generated focused runtime checks for the shared image and binary helpers and the consumers that depend on them, covering extension parsing, image/raster/Claude classification, data URL parsing, binary detection, mobile MIME inference, and Claude ACP conversion, and confirming that SVG and HEIC data URLs are rejected while AVIF is allowed.
  • Created a focused vitest-based repro in packages/shared/src and ran it with vitest --reporter verbose, resulting in six passing assertions that exercise edge cases like query-string URIs, dotfiles in path, SVG-as-binary, isClaudeImageFile vs isImageFile, and parseImageDataUrl behavior for SVG/HEIC vs AVIF.
  • Saved verbose vitest output and a standalone Node repro script to artifacts, documenting the six-pass vitest run and the four-mismatch Node repro results with separate exit statuses.
  • Noted that no source code was modified for this work and that the temporary test file was removed after capture, leaving only the artifacts for verification.
Artifacts

Verbose targeted validation run

  • Shows the focused runtime validation for shared image/binary helpers and their consumers.

Standalone URI MIME validation output

  • Validates the MIME inference outcomes for mobile URIs, including rejection of SVG data URLs.

Standalone validation script

  • Contains the standalone validation script used during the targeted checks.

Verbose vitest output for the targeted repro suite

  • Records six passing assertions from the vitest run, including the exact command and environment used.

Standalone Node script demonstrating image MIME behavior on mobile URIs

  • Shows four mismatches observed in the Node repro and exit status 1.

Standalone repro script

  • JavaScript repro script exercising extensionOf/getImageMimeType/inferImageMime behavior.

T-Rex Ran code and verified through T-Rex

Reviews (1): Last reviewed commit: "harden image handling against HEIC/HEIF/..." | Re-trigger Greptile

base64: string;
}

export function extensionOf(filename: string): string {
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.

P1 Strip URI suffixes

extensionOf() slices everything after the last dot without removing ? or #. The mobile picker now calls getImageMimeType(uri) on raw picker URIs, so a real URI like ph://asset/IMG.png?width=1024 is parsed as extension png?width=1024. That returns application/octet-stream, and inferImageMime() falls back to image/jpeg, causing PNG/WebP attachments to be uploaded with the wrong MIME type.

Artifacts

Targeted repro suite covering URI query-string extension parsing

  • Keeps the command output available without making the summary code-heavy.

Standalone mobile URI MIME repro output

  • Keeps the command output available without making the summary code-heavy.

Standalone mobile URI MIME repro source

  • Contains supporting evidence from the run (text/javascript; charset=utf-8).

T-Rex Ran code and verified through T-Rex

base64: string;
}

export function extensionOf(filename: string): string {
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 Use basename first

extensionOf() only checks whether the dot is past index 0 in the full path. For a path like /path/.heic, the dot is after the slash, so this returns heic and classifies the hidden file as an image. That can send hidden dotfiles through image, binary, or MIME-specific paths even though the basename has no real extension.

Artifacts

Targeted repro suite covering path dotfile extension parsing

  • Keeps the command output available without making the summary code-heavy.

T-Rex Ran code and verified through T-Rex


export const DOCUMENT_BINARY_EXTENSIONS: ReadonlySet<string> = new Set(["pdf"]);

export const BINARY_EXTENSIONS: ReadonlySet<string> = new Set([
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 Keep SVG textual

BINARY_EXTENSIONS is built from every key in IMAGE_MIME_TYPES, which now includes svg. isBinaryFile('icon.svg') therefore returns true, so title generation skips reading the SVG XML and only emits [Attached: icon.svg]. SVG files are text resources elsewhere in this PR, so this shared binary set can suppress useful text content for SVG-only attachments.

Artifacts

Targeted repro suite covering SVG binary classification

  • Keeps the command output available without making the summary code-heavy.

T-Rex Ran code and verified through T-Rex

type: "base64",
data: chunk.data,
media_type: chunk.mimeType as ImageMimeType,
media_type: chunk.mimeType as ClaudeImageMimeType,
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.

P1 Validate Claude MIME

This cast does not validate the incoming ACP image MIME type. If an image chunk arrives with image/svg+xml, image/heic, image/avif, image/bmp, or application/octet-stream, the converter still forwards that value as media_type even though ClaudeImageMimeType only covers JPEG, PNG, GIF, and WebP. Those unsupported image blocks can then fail at the Claude API boundary instead of being rejected or converted consistently.

Artifacts

Targeted repro suite covering unsupported Claude image MIME forwarding

  • Keeps the command output available without making the summary code-heavy.

T-Rex Ran code and verified through T-Rex

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.

1 participant