Three-layer defect chain causing 'cannot identify image file <_io.BytesIO object>':
1. attachmentUploader: hardcoded 'application/octet-stream' on Tele CDN upload
regardless of actual file MIME type — CDN stored images under wrong type.
2. messageCapture: processAttachmentUpload call site never forwarded
attachment.contentType into the options bag, so the fix in (1) would
have received undefined and fallen back to octet-stream anyway.
3. llmModerationClient: blindly trusted att.type from the DB record
(Discord-provided MIME) when constructing data: URLs, but validated
neither the HTTP status of the CDN re-fetch nor the actual byte content.
Stale/expired CDN URLs returning HTML error pages were base64-encoded
and sent to the model as 'image/jpeg', causing PIL to reject the stream.
Fixes:
- uploadAttachmentToTele now accepts contentType param (defaults to
application/octet-stream for non-image files)
- processAttachmentUpload options bag gains optional contentType field
- messageCapture forwards attachment.contentType at the call site
- Added sniffImageMimeType() using magic-byte probes for JPEG, PNG, GIF,
WebP, AVIF/HEIF — runs on every downloaded attachment buffer before
base64 encoding; skips the attachment (logs headerHex for diagnosis)
if bytes don't match a known image format
- data: URL now uses the sniffed MIME type, not the DB record
- Changed all import statements across the project to include the .js extension for consistency and to comply with ES module standards.
- Updated imports in various files including bootstrap.ts, shutdown.ts, config.ts, and many others.
- Ensured that all related modules and types are correctly imported with the new extension.
- Introduced `loggerSerialization.ts` to handle error serialization and log metadata formatting.
- Added `serializeError` function to convert Error objects into a structured format.
- Implemented `serializeLogValue` to handle various data types including Errors, Dates, RegExps, and plain objects.
- Created `formatLogMetadata` to format log metadata using the serialization functions.
feat(pagination): implement cursor encoding and decoding
- Added `pagination.ts` to manage cursor-based pagination.
- Implemented `encodeCursor` to convert cursor data into a base64 string.
- Developed `decodeCursor` to parse base64 strings back into cursor data, with error handling for invalid inputs.
Separate text moderation and voice recording guild/channel state so each workflow can persist and operate independently.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
- Migrate validation.ts from class-transformer/class-validator to Zod
- Apply Biome auto-fixes (import sorting, nodejs protocol)
- Fix duplicate type identifier in validation.ts
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
- Replace all raw SQL queries in messageStore.ts with Drizzle ORM queries
- Remove DatabaseAdapter dependency from messageStore functions
- Update all function signatures to be async and remove db parameter
- Functions now use getDatabase() internally for database access
- Update all call sites in messageCapture.ts, attachmentUploader.ts, aiAnalyzer.ts, webserver.ts, and index.ts
- All functions remain backward compatible in behavior
- TypeScript typecheck passes with no errors
- All tests pass (11 passed)
- Skip attachment download/upload to Picser (was failing with 400 errors)
- Store Discord's original attachment URLs directly as uploaded_url
- Mark attachments as immediately uploaded with Discord URL
- Remove processAttachmentUpload call and unused attachmentUploader import
- Eliminates slow upload cycle and API failures
This resolves:
- Attachment upload 400 errors
- Performance slowdown from failed upload retries
- Unnecessary network overhead
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
- Added functions to retrieve message location, sticker metadata, and display content in messageCapture.ts.
- Updated captureMessage function to store thread information and sticker metadata in the database.
- Modified messageStore.ts to support querying messages and attachments by thread ID.
- Updated types.ts to include thread_id in AttachmentRecord.
- Altered database schema in muxer-queue.ts to add thread_id column to attachments.
- Introduced ChannelSummary interface and listWatchableChannels method in voiceController.ts to fetch watchable channels.
- Added API endpoint in webserver.ts to retrieve channels for a given guild.
- Add message store with database operations (insert, update, query)
- Implement attachment uploader with picser integration
- Add Discord event listeners for message create/update/delete
- Support attachment upload with retry logic and error handling
- Add comprehensive unit tests for message store and uploader