Skip to content

Support HEIC EXIF timezone handling in the Telegram bot#403

Merged
techeng322 merged 1 commit into
mainfrom
techengme/myc-5014-support-heic-exif-timezone-handling-in-the-telegram-bot
Jul 11, 2026
Merged

Support HEIC EXIF timezone handling in the Telegram bot#403
techeng322 merged 1 commit into
mainfrom
techengme/myc-5014-support-heic-exif-timezone-handling-in-the-telegram-bot

Conversation

@techeng322

@techeng322 techeng322 commented Jul 11, 2026

Copy link
Copy Markdown
Collaborator

Summary

  • Parse Telegram image saleStart from EXIF using OffsetTimeOriginal or OffsetTime with reviveValues: false (no timezone guessing).
  • Sniff HEIC/HEIF MIME from magic bytes for extensionless Telegram documents and route them as images.
  • Patch exifr HEIC detection for Apple multi-brand files with large ftyp boxes.

Test plan

  • pnpm exec vitest run src/lib/telegram/chat (245 tests passed)
  • HEIC fixtures: shelf-christmas-decoration.heic2023-12-13T12:03:39Z
  • HEIC fixtures: apple-styled-photo.heic (111.HEIC) → 2026-07-05T16:02:17Z
  • Manual: send 111.HEIC as a Telegram document with caption and verify moment timeline uses capture time

Made with Cursor

Summary by CodeRabbit

  • New Features
    • Improved Telegram media recognition, including extensionless HEIC, HEIF, JPEG, PNG, GIF, WEBP, and MP4 files.
    • Media attachments can now be resolved using file contents when metadata is missing or generic.
    • Improved EXIF capture-date handling with timezone fallback support for HEIC images.
  • Bug Fixes
    • Improved compatibility with HEIC files that previously failed metadata parsing.
  • Tests
    • Added comprehensive coverage for MIME detection, attachment resolution, EXIF offsets, and HEIC metadata extraction.

Parse capture-time offsets from OffsetTimeOriginal or OffsetTime, sniff HEIC MIME from magic bytes for extensionless documents, and patch exifr detection for Apple multi-brand HEIC files so saleStart uses the true UTC instant.

Co-authored-by: Cursor <cursoragent@cursor.com>
@vercel

vercel Bot commented Jul 11, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
in-process-api Ready Ready Preview Jul 11, 2026 4:59pm

Request Review

@coderabbitai

coderabbitai Bot commented Jul 11, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

Adds HEIC/HEIF MIME detection from paths and file signatures, resolves extensionless Telegram attachments using downloaded bytes, patches HEIC EXIF parser detection, and supports EXIF timezone fallback from OffsetTime.

Changes

Telegram media resolution

Layer / File(s) Summary
EXIF offsets and HEIC parser handling
src/lib/telegram/chat/{extractExifCaptureDate,patchExifrHeicDetection,resolveExifOffsetMs,parseExifOffsetMs}.ts, src/lib/telegram/chat/__tests__/*Exif*
HEIC parser detection is patched, EXIF parsing requests both offset fields, and OffsetTime is used when OffsetTimeOriginal is unavailable.
Binary MIME detection and path fallback
src/lib/telegram/chat/{bufferStartsWith,readFtypBrands,detectMimeTypeFromBuffer,needsMimeSniff,resolveTelegramFileMimeType,getMimeTypeFromFilePath}.ts, src/lib/telegram/chat/__tests__/*Mime*, src/lib/telegram/chat/__tests__/{bufferStartsWith,readFtypBrands,needsMimeSniff}.test.ts
Adds signature and ISO BMFF brand detection for image and video formats, plus HEIC/HEIF extension mappings and MIME-sniffing decisions.
Telegram file and attachment resolution
src/lib/telegram/chat/{fetchTelegramFile,resolveTelegramMediaAttachment}.ts, src/lib/telegram/chat/handlers/onNewMention.ts, src/lib/telegram/chat/**/__tests__/*
Downloaded Telegram bytes now participate in MIME resolution, and mention handling processes attachments after asynchronous media-type resolution.

Estimated code review effort: 3 (Moderate) | ~30 minutes

Sequence Diagram(s)

sequenceDiagram
  participant onNewMention
  participant resolveTelegramMediaAttachment
  participant fetchTelegramFile
  participant resolveTelegramFileMimeType
  onNewMention->>resolveTelegramMediaAttachment: resolve message attachment
  resolveTelegramMediaAttachment->>fetchTelegramFile: fetch Telegram file
  fetchTelegramFile->>resolveTelegramFileMimeType: inspect path and buffer
  resolveTelegramFileMimeType-->>fetchTelegramFile: resolved MIME type
  fetchTelegramFile-->>resolveTelegramMediaAttachment: file metadata
  resolveTelegramMediaAttachment-->>onNewMention: normalized attachment
Loading
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title is concise and accurately summarizes the main HEIC EXIF timezone handling changes in the Telegram bot.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch techengme/myc-5014-support-heic-exif-timezone-handling-in-the-telegram-bot

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 ESLint

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

src/lib/telegram/chat/__tests__/bufferStartsWith.test.ts

Oops! Something went wrong! :(

ESLint: 9.39.4

TypeError: Converting circular structure to JSON
--> starting at object with constructor 'Object'
| property 'configs' -> object with constructor 'Object'
| property 'flat' -> object with constructor 'Object'
| ...
| property 'plugins' -> object with constructor 'Object'
--- property 'react' closes the circle
Referenced from: /.eslintrc.json
at JSON.stringify ()
at /node_modules/.pnpm/@eslint+eslintrc@3.3.5/node_modules/@eslint/eslintrc/dist/eslintrc.cjs:2255:45
at Array.map ()
at ConfigValidator.formatErrors (/node_modules/.pnpm/@eslint+eslintrc@3.3.5/node_modules/@eslint/eslintrc/dist/eslintrc.cjs:2246:23)
at ConfigValidator.validateConfigSchema (/node_modules/.pnpm/@eslint+eslintrc@3.3.5/node_modules/@eslint/eslintrc/dist/eslintrc.cjs:2277:84)
at ConfigArrayFactory._normalizeConfigData (/node_modules/.pnpm/@eslint+eslintrc@3.3.5/node_modules/@eslint/

... [truncated 446 characters] ...

c/dist/eslintrc.cjs:3261:25)
at ConfigArrayFactory._normalizeObjectConfigDataBody (/node_modules/.pnpm/@eslint+eslintrc@3.3.5/node_modules/@eslint/eslintrc/dist/eslintrc.cjs:3199:25)
(node:2) ESLintRCWarning: You are using an eslintrc configuration file, which is deprecated and support will be removed in v10.0.0. Please migrate to an eslint.config.js file. See https://eslint.org/docs/latest/use/configure/migration-guide for details. An eslintrc configuration file is used because you have the ESLINT_USE_FLAT_CONFIG environment variable set to false. If you want to use an eslint.config.js file, remove the environment variable. If you want to find the location of the eslintrc configuration file, use the --debug flag.
(Use node --trace-warnings ... to show where the warning was created)

src/lib/telegram/chat/__tests__/detectMimeTypeFromBuffer.test.ts

Oops! Something went wrong! :(

ESLint: 9.39.4

TypeError: Converting circular structure to JSON
--> starting at object with constructor 'Object'
| property 'configs' -> object with constructor 'Object'
| property 'flat' -> object with constructor 'Object'
| ...
| property 'plugins' -> object with constructor 'Object'
--- property 'react' closes the circle
Referenced from: /.eslintrc.json
at JSON.stringify ()
at /node_modules/.pnpm/@eslint+eslintrc@3.3.5/node_modules/@eslint/eslintrc/dist/eslintrc.cjs:2255:45
at Array.map ()
at ConfigValidator.formatErrors (/node_modules/.pnpm/@eslint+eslintrc@3.3.5/node_modules/@eslint/eslintrc/dist/eslintrc.cjs:2246:23)
at ConfigValidator.validateConfigSchema (/node_modules/.pnpm/@eslint+eslintrc@3.3.5/node_modules/@eslint/eslintrc/dist/eslintrc.cjs:2277:84)
at ConfigArrayFactory._normalizeConfigData (/node_modules/.pnpm/@eslint+eslintrc@3.3.5/node_modules/@eslint/

... [truncated 446 characters] ...

c/dist/eslintrc.cjs:3261:25)
at ConfigArrayFactory._normalizeObjectConfigDataBody (/node_modules/.pnpm/@eslint+eslintrc@3.3.5/node_modules/@eslint/eslintrc/dist/eslintrc.cjs:3199:25)
(node:2) ESLintRCWarning: You are using an eslintrc configuration file, which is deprecated and support will be removed in v10.0.0. Please migrate to an eslint.config.js file. See https://eslint.org/docs/latest/use/configure/migration-guide for details. An eslintrc configuration file is used because you have the ESLINT_USE_FLAT_CONFIG environment variable set to false. If you want to use an eslint.config.js file, remove the environment variable. If you want to find the location of the eslintrc configuration file, use the --debug flag.
(Use node --trace-warnings ... to show where the warning was created)

src/lib/telegram/chat/__tests__/extractExifCaptureDate.heic.test.ts

Oops! Something went wrong! :(

ESLint: 9.39.4

TypeError: Converting circular structure to JSON
--> starting at object with constructor 'Object'
| property 'configs' -> object with constructor 'Object'
| property 'flat' -> object with constructor 'Object'
| ...
| property 'plugins' -> object with constructor 'Object'
--- property 'react' closes the circle
Referenced from: /.eslintrc.json
at JSON.stringify ()
at /node_modules/.pnpm/@eslint+eslintrc@3.3.5/node_modules/@eslint/eslintrc/dist/eslintrc.cjs:2255:45
at Array.map ()
at ConfigValidator.formatErrors (/node_modules/.pnpm/@eslint+eslintrc@3.3.5/node_modules/@eslint/eslintrc/dist/eslintrc.cjs:2246:23)
at ConfigValidator.validateConfigSchema (/node_modules/.pnpm/@eslint+eslintrc@3.3.5/node_modules/@eslint/eslintrc/dist/eslintrc.cjs:2277:84)
at ConfigArrayFactory._normalizeConfigData (/node_modules/.pnpm/@eslint+eslintrc@3.3.5/node_modules/@eslint/

... [truncated 446 characters] ...

c/dist/eslintrc.cjs:3261:25)
at ConfigArrayFactory._normalizeObjectConfigDataBody (/node_modules/.pnpm/@eslint+eslintrc@3.3.5/node_modules/@eslint/eslintrc/dist/eslintrc.cjs:3199:25)
(node:2) ESLintRCWarning: You are using an eslintrc configuration file, which is deprecated and support will be removed in v10.0.0. Please migrate to an eslint.config.js file. See https://eslint.org/docs/latest/use/configure/migration-guide for details. An eslintrc configuration file is used because you have the ESLINT_USE_FLAT_CONFIG environment variable set to false. If you want to use an eslint.config.js file, remove the environment variable. If you want to find the location of the eslintrc configuration file, use the --debug flag.
(Use node --trace-warnings ... to show where the warning was created)

  • 23 others

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.

@techeng322 techeng322 merged commit 5a7b76e into main Jul 11, 2026
2 of 3 checks passed

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (5)
src/lib/telegram/chat/bufferStartsWith.ts (1)

1-2: 🩺 Stability & Availability | 🔵 Trivial | 💤 Low value

LGTM!

Optionally, add an explicit length guard so the function doesn't rely on Buffer returning undefined for out-of-bounds indices:

♻️ Optional robustness improvement
 const bufferStartsWith = (buffer: Buffer, magic: number[]): boolean =>
-  magic.every((byte, index) => buffer[index] === byte);
+  buffer.length >= magic.length &&
+  magic.every((byte, index) => buffer[index] === byte);
🤖 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 `@src/lib/telegram/chat/bufferStartsWith.ts` around lines 1 - 2, Optionally
update bufferStartsWith to first verify that buffer is at least as long as
magic, returning false when it is shorter, then preserve the existing
byte-by-byte comparison for valid lengths.
src/lib/telegram/chat/__tests__/detectMimeTypeFromBuffer.test.ts (1)

1-25: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Add tests for JPEG, PNG, GIF, WEBP, and video/mp4 detection.

Only HEIC and unknown-byte cases are tested. The remaining MIME branches in detectMimeTypeFromBuffer (JPEG, PNG, GIF, WEBP, ftyp-based video/mp4) have no coverage. These can be tested with small crafted buffers.

♻️ Suggested additional tests
  it('detects JPEG from magic bytes', () => {
    expect(detectMimeTypeFromBuffer(Buffer.from([0xff, 0xd8, 0xff, 0xe0, 0x00])))
      .toBe('image/jpeg');
  });

  it('detects PNG from magic bytes', () => {
    const png = Buffer.from([0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a]);
    expect(detectMimeTypeFromBuffer(png)).toBe('image/png');
  });

  it('detects GIF from magic bytes', () => {
    const gif = Buffer.from([0x47, 0x49, 0x46, 0x38, 0x39, 0x61, 0x00, 0x00]);
    expect(detectMimeTypeFromBuffer(gif)).toBe('image/gif');
  });

  it('detects WEBP from magic bytes', () => {
    const webp = Buffer.from([
      0x52, 0x49, 0x46, 0x46, 0x00, 0x00, 0x00, 0x00,
      0x57, 0x45, 0x42, 0x50,
    ]);
    expect(detectMimeTypeFromBuffer(webp)).toBe('image/webp');
  });

  it('detects video/mp4 from ftyp brands', () => {
    const mp4 = Buffer.from([
      0x00, 0x00, 0x00, 0x18, 0x66, 0x74, 0x79, 0x70,
      0x6d, 0x70, 0x34, 0x31, 0x00, 0x00, 0x00, 0x00,
      0x69, 0x73, 0x6f, 0x6d,
    ]);
    expect(detectMimeTypeFromBuffer(mp4)).toBe('video/mp4');
  });
🤖 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 `@src/lib/telegram/chat/__tests__/detectMimeTypeFromBuffer.test.ts` around
lines 1 - 25, Add coverage in the detectMimeTypeFromBuffer test suite for JPEG,
PNG, GIF, WEBP, and ftyp-based video/mp4 detection using minimal crafted buffers
matching each format’s magic bytes. Keep the existing HEIC and unknown-byte
tests unchanged, and assert the expected MIME type for each new case.
src/lib/telegram/chat/resolveTelegramFileMimeType.ts (1)

1-2: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Use the @/* alias for all new local TypeScript imports.

  • src/lib/telegram/chat/resolveTelegramFileMimeType.ts#L1-L2: replace both relative imports with their @/lib/telegram/chat/... aliases.
  • src/lib/telegram/chat/__tests__/needsMimeSniff.test.ts#L2-L2: replace ../needsMimeSniff with @/lib/telegram/chat/needsMimeSniff.
  • src/lib/telegram/chat/__tests__/resolveTelegramFileMimeType.test.ts#L4-L4: replace ../resolveTelegramFileMimeType with @/lib/telegram/chat/resolveTelegramFileMimeType.

As per path instructions, local TypeScript imports targeting src/* must use the @/* alias.

🤖 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 `@src/lib/telegram/chat/resolveTelegramFileMimeType.ts` around lines 1 - 2,
Replace the relative local TypeScript imports with the `@/`* alias: update both
imports in src/lib/telegram/chat/resolveTelegramFileMimeType.ts lines 1-2, the
needsMimeSniff import in src/lib/telegram/chat/__tests__/needsMimeSniff.test.ts
line 2, and the resolveTelegramFileMimeType import in
src/lib/telegram/chat/__tests__/resolveTelegramFileMimeType.test.ts line 4 to
reference their `@/lib/telegram/chat/`... paths.

Source: Path instructions

src/lib/telegram/chat/patchExifrHeicDetection.ts (2)

29-41: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

this.type reliance is fragile despite being correct today.

this inside the reassigned canHandle only resolves correctly because exifr's engine invokes it as FileParser.canHandle(file, marker). Capturing heicParser.type via closure instead of this.type would remove the dependency on how exifr internally calls the method.

♻️ Optional refactor
   const original = heicParser.canHandle.bind(heicParser);
+  const { type } = heicParser;
   heicParser.canHandle = function (file, firstTwoBytes) {
     if (firstTwoBytes !== 0) return false;
     if (file.getString(4, 4) !== 'ftyp') return false;

     const ftypLength = file.getUint32(0);
     if (ftypLength < 16 || ftypLength > 256) return false;

     for (let offset = 16; offset + 4 <= ftypLength; offset += 4) {
-      if (file.getString(offset, 4) === this.type) return true;
+      if (file.getString(offset, 4) === type) return true;
     }

     return original(file, firstTwoBytes);
   };
🤖 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 `@src/lib/telegram/chat/patchExifrHeicDetection.ts` around lines 29 - 41,
Update the reassigned heicParser.canHandle function to capture heicParser.type
in a closure before the function definition, then compare brand strings against
that captured value instead of this.type. Preserve the existing parsing checks
and fallback to original unchanged.

13-26: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick win

Patch silently no-ops if exifr's internal fileParsers shape changes.

exifr.fileParsers and canHandle's shape are undocumented internals (confirmed against Exifr.mjs, which calls FileParser.canHandle(file, marker) with marker = file.getUint16(0) — consistent with what this patch assumes). Because patchExifrHeicDetection just returns when heicParser is missing/reshaped, a future exifr bump could silently drop this fix with no runtime signal — only a fixture-test failure would catch it, and only if that test is run.

Consider logging a warning when the parser can't be found/patched, so a regression surfaces immediately rather than depending solely on CI catching it.

🔧 Suggested defensive logging
   if (!heicParser) return;
+  if (!heicParser) {
+    console.warn('[patchExifrHeicDetection] exifr heic parser not found; HEIC multi-brand detection patch not applied.');
+    return;
+  }
🤖 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 `@src/lib/telegram/chat/patchExifrHeicDetection.ts` around lines 13 - 26,
Update patchExifrHeicDetection so it emits a warning when exifr.fileParsers does
not provide the expected heicParser or compatible canHandle shape, rather than
silently returning. Keep the existing successful patch behavior unchanged and
use the module’s established logging mechanism to report that the HEIC detection
patch could not be applied.
🤖 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.

Inline comments:
In `@src/lib/telegram/chat/detectMimeTypeFromBuffer.ts`:
- Around line 1-2: Replace the relative internal imports with the `@/`* alias in
src/lib/telegram/chat/detectMimeTypeFromBuffer.ts lines 1-2, using
`@/lib/telegram/chat/bufferStartsWith` and `@/lib/telegram/chat/readFtypBrands`;
update src/lib/telegram/chat/__tests__/bufferStartsWith.test.ts line 2,
src/lib/telegram/chat/__tests__/readFtypBrands.test.ts line 4, and
src/lib/telegram/chat/__tests__/detectMimeTypeFromBuffer.test.ts line 4 to use
the corresponding `@/lib/telegram/chat` imports.

In `@src/lib/telegram/chat/readFtypBrands.ts`:
- Around line 9-13: Update the brand extraction logic in the visible
readFtypBrands flow to include the major brand from bytes 8–11 before collecting
compatible brands from offset 16. Preserve the existing compatible-brand
iteration and return the major brand first in the brands array so downstream
detectMimeTypeFromBuffer allowlist checks cover both brand types.

---

Nitpick comments:
In `@src/lib/telegram/chat/__tests__/detectMimeTypeFromBuffer.test.ts`:
- Around line 1-25: Add coverage in the detectMimeTypeFromBuffer test suite for
JPEG, PNG, GIF, WEBP, and ftyp-based video/mp4 detection using minimal crafted
buffers matching each format’s magic bytes. Keep the existing HEIC and
unknown-byte tests unchanged, and assert the expected MIME type for each new
case.

In `@src/lib/telegram/chat/bufferStartsWith.ts`:
- Around line 1-2: Optionally update bufferStartsWith to first verify that
buffer is at least as long as magic, returning false when it is shorter, then
preserve the existing byte-by-byte comparison for valid lengths.

In `@src/lib/telegram/chat/patchExifrHeicDetection.ts`:
- Around line 29-41: Update the reassigned heicParser.canHandle function to
capture heicParser.type in a closure before the function definition, then
compare brand strings against that captured value instead of this.type. Preserve
the existing parsing checks and fallback to original unchanged.
- Around line 13-26: Update patchExifrHeicDetection so it emits a warning when
exifr.fileParsers does not provide the expected heicParser or compatible
canHandle shape, rather than silently returning. Keep the existing successful
patch behavior unchanged and use the module’s established logging mechanism to
report that the HEIC detection patch could not be applied.

In `@src/lib/telegram/chat/resolveTelegramFileMimeType.ts`:
- Around line 1-2: Replace the relative local TypeScript imports with the `@/`*
alias: update both imports in
src/lib/telegram/chat/resolveTelegramFileMimeType.ts lines 1-2, the
needsMimeSniff import in src/lib/telegram/chat/__tests__/needsMimeSniff.test.ts
line 2, and the resolveTelegramFileMimeType import in
src/lib/telegram/chat/__tests__/resolveTelegramFileMimeType.test.ts line 4 to
reference their `@/lib/telegram/chat/`... paths.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: f790aab2-b0e6-4ee5-bfcd-2be3ee29470c

📥 Commits

Reviewing files that changed from the base of the PR and between 189ddf1 and bc04c41.

📒 Files selected for processing (28)
  • src/lib/telegram/chat/__tests__/bufferStartsWith.test.ts
  • src/lib/telegram/chat/__tests__/detectMimeTypeFromBuffer.test.ts
  • src/lib/telegram/chat/__tests__/extractExifCaptureDate.heic.test.ts
  • src/lib/telegram/chat/__tests__/extractExifCaptureDate.test.ts
  • src/lib/telegram/chat/__tests__/fetchTelegramFile.test.ts
  • src/lib/telegram/chat/__tests__/fixtures/apple-styled-photo.heic
  • src/lib/telegram/chat/__tests__/fixtures/shelf-christmas-decoration.heic
  • src/lib/telegram/chat/__tests__/getMimeTypeFromFilePath.test.ts
  • src/lib/telegram/chat/__tests__/needsMimeSniff.test.ts
  • src/lib/telegram/chat/__tests__/parseExifOffsetMs.test.ts
  • src/lib/telegram/chat/__tests__/readFtypBrands.test.ts
  • src/lib/telegram/chat/__tests__/resolveExifOffsetMs.test.ts
  • src/lib/telegram/chat/__tests__/resolveTelegramFileMimeType.test.ts
  • src/lib/telegram/chat/__tests__/resolveTelegramMediaAttachment.test.ts
  • src/lib/telegram/chat/bufferStartsWith.ts
  • src/lib/telegram/chat/detectMimeTypeFromBuffer.ts
  • src/lib/telegram/chat/extractExifCaptureDate.ts
  • src/lib/telegram/chat/fetchTelegramFile.ts
  • src/lib/telegram/chat/getMimeTypeFromFilePath.ts
  • src/lib/telegram/chat/handlers/__tests__/onNewMention.test.ts
  • src/lib/telegram/chat/handlers/onNewMention.ts
  • src/lib/telegram/chat/needsMimeSniff.ts
  • src/lib/telegram/chat/parseExifOffsetMs.ts
  • src/lib/telegram/chat/patchExifrHeicDetection.ts
  • src/lib/telegram/chat/readFtypBrands.ts
  • src/lib/telegram/chat/resolveExifOffsetMs.ts
  • src/lib/telegram/chat/resolveTelegramFileMimeType.ts
  • src/lib/telegram/chat/resolveTelegramMediaAttachment.ts
👮 Files not reviewed due to content moderation or server errors (2)
  • src/lib/telegram/chat/tests/fixtures/apple-styled-photo.heic
  • src/lib/telegram/chat/tests/fixtures/shelf-christmas-decoration.heic

Comment on lines +1 to +2
import bufferStartsWith from './bufferStartsWith';
import readFtypBrands from './readFtypBrands';

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick win

Use @/* path alias for internal imports per coding guidelines.

All internal imports use relative paths instead of the @/* alias. Per the project coding guidelines, imports pointing to ./src/* should use the @/* path alias.

  • src/lib/telegram/chat/detectMimeTypeFromBuffer.ts#L1-L2: replace ./bufferStartsWith and ./readFtypBrands with @/lib/telegram/chat/bufferStartsWith and @/lib/telegram/chat/readFtypBrands
  • src/lib/telegram/chat/__tests__/bufferStartsWith.test.ts#L2: replace ../bufferStartsWith with @/lib/telegram/chat/bufferStartsWith
  • src/lib/telegram/chat/__tests__/readFtypBrands.test.ts#L4: replace ../readFtypBrands with @/lib/telegram/chat/readFtypBrands
  • src/lib/telegram/chat/__tests__/detectMimeTypeFromBuffer.test.ts#L4: replace ../detectMimeTypeFromBuffer with @/lib/telegram/chat/detectMimeTypeFromBuffer

As per coding guidelines: **/*.{ts,tsx,js,jsx}: Use path alias @/* for imports pointing to ./src/*.

📍 Affects 4 files
  • src/lib/telegram/chat/detectMimeTypeFromBuffer.ts#L1-L2 (this comment)
  • src/lib/telegram/chat/__tests__/bufferStartsWith.test.ts#L2-L2
  • src/lib/telegram/chat/__tests__/readFtypBrands.test.ts#L4-L4
  • src/lib/telegram/chat/__tests__/detectMimeTypeFromBuffer.test.ts#L4-L4
🤖 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 `@src/lib/telegram/chat/detectMimeTypeFromBuffer.ts` around lines 1 - 2,
Replace the relative internal imports with the `@/`* alias in
src/lib/telegram/chat/detectMimeTypeFromBuffer.ts lines 1-2, using
`@/lib/telegram/chat/bufferStartsWith` and `@/lib/telegram/chat/readFtypBrands`;
update src/lib/telegram/chat/__tests__/bufferStartsWith.test.ts line 2,
src/lib/telegram/chat/__tests__/readFtypBrands.test.ts line 4, and
src/lib/telegram/chat/__tests__/detectMimeTypeFromBuffer.test.ts line 4 to use
the corresponding `@/lib/telegram/chat` imports.

Source: Coding guidelines

Comment on lines +9 to +13
const brands: string[] = [];
for (let offset = 16; offset + 4 <= ftypLength; offset += 4) {
brands.push(buffer.toString('ascii', offset, offset + 4));
}
return brands;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Include the major brand in the returned brands array.

The loop starts at offset 16 (compatible brands) but skips the major brand at bytes 8–11. Per the ISO BMFF spec, the major brand is a valid brand that should be checked against allowlists. If a file's major brand is heic but it's not listed among compatible brands, detectMimeTypeFromBuffer will fail to classify it.

🐛 Proposed fix: prepend major brand to brands array
   const brands: string[] = [];
+  // Include the major brand (bytes 8–11) per ISO BMFF spec
+  brands.push(buffer.toString('ascii', 8, 12));
   for (let offset = 16; offset + 4 <= ftypLength; offset += 4) {
     brands.push(buffer.toString('ascii', offset, offset + 4));
   }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const brands: string[] = [];
for (let offset = 16; offset + 4 <= ftypLength; offset += 4) {
brands.push(buffer.toString('ascii', offset, offset + 4));
}
return brands;
const brands: string[] = [];
// Include the major brand (bytes 8–11) per ISO BMFF spec
brands.push(buffer.toString('ascii', 8, 12));
for (let offset = 16; offset + 4 <= ftypLength; offset += 4) {
brands.push(buffer.toString('ascii', offset, offset + 4));
}
return brands;
🤖 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 `@src/lib/telegram/chat/readFtypBrands.ts` around lines 9 - 13, Update the
brand extraction logic in the visible readFtypBrands flow to include the major
brand from bytes 8–11 before collecting compatible brands from offset 16.
Preserve the existing compatible-brand iteration and return the major brand
first in the brands array so downstream detectMimeTypeFromBuffer allowlist
checks cover both brand types.

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