Files
TeleUploader/src/shared/utils/validation.ts
T
asepharyana 24dfb1c6b1
Build & Deploy (Nix) / build-and-deploy (push) Successful in 56s
fix: fail-fast guard TELEGRAM_CHUNK_SIZE_BYTES <= 19MB (Telegram getFile limit 20MB)
Chunk parts > 19MB are stored to Telegram but getFile cannot resolve files over 20MB ('Bad Request: file is too big'), making every part undownloadable (prod bug 2026-08-01: 48MB chunk -> download 500).

- src/env.ts: reject TELEGRAM_CHUNK_SIZE_BYTES > 19922944 at startup (log error + throw), default changed 20MB -> 19MB
- src/shared/utils/validation.ts: TELEGRAM_CHUNK_SIZE_MAX_BYTES constant; asSafeChunkSize now enforces the max at runtime (covers S3 multipart parts too)
- test/env.test.ts: unit tests + subprocess fail-fast tests (48MB rejected, 19MB accepted)
- test/helpers/setup-env.ts: pin safe chunk size so a stale .env can't break the suite
- .env.example + CLAUDE.md: document the 20MB getFile limit
2026-08-01 13:06:42 +07:00

34 lines
1.5 KiB
TypeScript

/**
* Maximum allowed chunk/part size in bytes for Telegram storage.
*
* Telegram Bot API `getFile` can only resolve files up to 20 MB; anything
* larger fails with "Bad Request: file is too big". Chunked uploads store
* each part as a Telegram document and later resolve it via `getFile`, so a
* part must never reach that limit. 19 MB (19922944 bytes) leaves a safety
* margin and is the value used in production (/etc/teleuploader/env).
*/
export const TELEGRAM_CHUNK_SIZE_MAX_BYTES = 19 * 1024 * 1024;
/**
* Validates a chunk size value and returns it as a safe integer.
*
* @param chunkSizeBytes - The desired chunk size in bytes.
* @returns The same value if it is a positive safe integer at or below
* {@link TELEGRAM_CHUNK_SIZE_MAX_BYTES}.
* @throws {Error} If the chunk size is not a safe positive integer or exceeds
* the Telegram `getFile` limit (with margin).
*/
export const asSafeChunkSize = (chunkSizeBytes: number): number => {
if (!Number.isSafeInteger(chunkSizeBytes) || chunkSizeBytes <= 0) {
throw new Error('Invalid Telegram chunk size');
}
if (chunkSizeBytes > TELEGRAM_CHUNK_SIZE_MAX_BYTES) {
throw new Error(
`Telegram chunk size ${chunkSizeBytes} exceeds the maximum allowed part size ` +
`${TELEGRAM_CHUNK_SIZE_MAX_BYTES} bytes (${TELEGRAM_CHUNK_SIZE_MAX_BYTES / (1024 * 1024)} MB). ` +
'Telegram getFile cannot download files larger than 20 MB, so such parts would be undownloadable.',
);
}
return chunkSizeBytes;
};