- Apply Biome organize-import/formatting fixes across changed S3 files
- Replace remaining string concatenations with template literals for lint
- Make home page inline handlers explicit via window.* and add button types
- Clean S3 auth lint issues with dot-property access and optional chaining
- Keep GetObject proxy and production/S3 SDK tests passing
Verification:
- bun run lint (0 errors, 1 CSS specificity warning)
- S3_SECRET_KEY=<env> bun test test/production-e2e.test.ts (29 pass)
- S3_SECRET_KEY=<env> bun test test/s3-sdk.test.ts (20 pass)
- bun test test/s3-auth.test.ts (5 pass)
- Add proxyS3Get config (PROXY_S3_GET env, default true) to env.ts
- Proxy handleGetObject and handleGetMultipartObject: fetch from Telegram
CDN and return 200 with streaming body instead of 302 redirect
- Real S3 clients (AWS SDK v3) expect 200+body on GetObject, not redirect
- Legacy 302 redirect path preserved when proxyS3Get=false
- Updated production-e2e: GetObject asserts 200 with body content
- Updated s3-sdk.test.ts: GetObject asserts 200 with body (removed try/catch)
- Cleaned up unused multipart imports in s3-sdk.test.ts
All 49 tests pass (29 production-e2e + 20 s3-sdk).
Tests use @aws-sdk/client-s3 against https://upload.asepharyana.my.id
with forcePathStyle=true. Covers all standard S3 operations:
ListBuckets, CreateBucket, HeadBucket, DeleteBucket, PutObject,
GetObject, HeadObject, ListObjectsV1/V2 (prefix, delimiter),
CopyObject, DeleteObject, DeleteObjects (batch), error handling.
Multipart is excluded from SDK tests — the SDK adds amz-sdk-* /
x-amz-user-agent to signed headers, which can differ between
signing time and the actual request through Cloudflare, causing
403 SignatureDoesNotMatch. Multipart is verified via manual
SigV4 signing in test/production-e2e.test.ts.
Fixes:
- RowList bug: postgres.js returns array directly, not {rows}. Fix in
buckets.ts, files-ext.ts, multipart.ts (3 files, 8 functions)
- S3 ListBuckets routing: GET / was intercepted by handleHome route
- Presigned URL detection: isS3Request() only checked Authorization header
- FK constraint on bucket delete: cascade-delete files & multipart rows first
- docker-compose.yml: pass S3_ACCESS_KEY / S3_SECRET_KEY to container
- Dockerfile: copy home.html to runner stage for handleHome
Tests:
- test/production-e2e.test.ts: 29 tests (11 Web API + 18 S3 SigV4)
All pass against https://upload.asepharyana.my.id
- Creates and cleans up real buckets/objects on production
- Updated formatting in web-api.ts for better alignment and readability.
- Enhanced XML builders in xml.ts for clearer structure and maintainability.
- Improved test cases in s3-auth.test.ts and s3-operations.test.ts for better clarity and consistency.
- Refactored mock data in web-api.test.ts for improved readability.
- Refactored Telegram bot pool iteration to handle 'wrong file_id' properly by verifying against all active bots
- Upgraded TelegramFileInfo interface to track owner bot_token
- Patched MaxListenersExceededWarning memory leak in zip.ts stream writes with events.once and async iteration
- Added new configuration options: trustProxy, uploadConcurrency, batchMaxItems, batchMaxSizeBytes, and maxRequestBodyBytes to AppConfig.
- Implemented utility functions for parsing environment variables and masking sensitive data.
- Updated rate limiting logic to use configurable window size and maximum requests per window.
- Introduced a middleware for rate limiting on specific routes.
- Refactored file handling routes to support streaming downloads instead of redirects.
- Improved error handling and response formatting in file routes.
- Added support for oversized request rejection based on Content-Length header.
- Updated Swagger documentation to reflect changes in API behavior and responses.
- Enhanced tests to cover new features and ensure proper functionality.
- Update test/bot.test.ts to use process.env.BOT_TOKEN || 'fallback'
- Update docs/superpowers/plans/2026-05-18-deploy-plan.md to use placeholders
- Completely eliminates hardcoded active API token from codebase
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
- Replace forceDocument boolean with fileType string in forwardToStorage
- Dynamically call matching sendPhoto, sendAudio, sendVideo, sendVoice, sendAnimation, sendSticker, or sendDocument Telegraf API method
- Correctly extract uploaded file details based on what Telegram returned
- Fixes IMAGE_PROCESS_FAILED 500 error when uploading ogg audio, video, sticker, or voice notes via HTTP
- Update upload.ts, bot.ts, and test suites to match the new dynamic signature
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
- Compile src/db/migrate.ts to dist/migrate.js during build
- Copy dist/migrate.js to Stage 2 (runner) inside Dockerfile
- Run bun dist/migrate.js on db:migrate command
- Modify schema.sql to use CREATE TABLE IF NOT EXISTS and ALTER TABLE to add file_hash to existing database instances on VPS
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>