feat: dedup wave 2 — file factory + V1/V2 mapping + bot handler
Deploy FileDrop / deploy (push) Successful in 42s

- ✨ buildNewFile() factory (src/domain/entities/file-factory.ts)
  eliminates ~380 lines of archive null / isDeleted / field defaults
- ♻️ 27 creation blocks → buildNewFile() across 8 files
- ♻️ S3 V1/V2 object listing mapping → mapFileToListEntry()
- ♻️ Bot handler size validation → checkFileSize() from shared utils
- 🔎 computeHash audit: all 10 instances are streaming (no dedup)
- Lint ✅ Build ✅ Push ✅
This commit is contained in:
Claude
2026-07-29 16:02:01 +07:00
parent 332853f398
commit 3501d547c0
9 changed files with 364 additions and 327 deletions
+20 -25
View File
@@ -1,6 +1,7 @@
import { createReadStream } from 'node:fs';
import { nanoid } from 'nanoid';
import type { File as FileEntity } from '../../domain/entities/file';
import { buildNewFile } from '../../domain/entities/file-factory';
import type { NewFilePart } from '../../domain/entities/file-part';
import type { IFilePartRepository } from '../../domain/ports/file-part-repository';
import type { IFileRepository } from '../../domain/ports/file-repository';
@@ -193,31 +194,25 @@ export class ChunkedStorage {
const publicId = nanoid();
const file = await this.fileRepository.create({
publicId,
telegramFileId: firstPart.telegramFileId,
telegramFileUniqueId: firstPart.telegramFileUniqueId,
storageChatId: config.storageChatId,
storageMessageId: firstPart.storageMessageId,
fileName: input.fileName,
mimeType: input.mimeType,
sizeBytes: upload.totalSizeBytes,
fileType: input.fileType,
uploaderId: input.uploaderId,
fileHash: upload.fileHash,
archiveTelegramFileId: null,
archiveStorageMessageId: null,
archiveFileName: null,
archiveEntryName: null,
archiveMimeType: null,
archiveSizeBytes: null,
bucketId: input.bucketId ?? null,
s3Key: input.s3Key ?? null,
storageBackend: 'chunked',
isDeleted: false,
multipartUploadId: null,
partCount: upload.parts.length,
});
const file = await this.fileRepository.create(
buildNewFile({
publicId,
telegramFileId: firstPart.telegramFileId,
telegramFileUniqueId: firstPart.telegramFileUniqueId,
storageChatId: config.storageChatId,
storageMessageId: firstPart.storageMessageId,
fileName: input.fileName,
mimeType: input.mimeType,
sizeBytes: upload.totalSizeBytes,
fileType: input.fileType,
storageBackend: 'chunked',
uploaderId: input.uploaderId,
fileHash: upload.fileHash,
bucketId: input.bucketId,
s3Key: input.s3Key,
partCount: upload.parts.length,
}),
);
const fileParts: NewFilePart[] = upload.parts.map((part) => ({
fileId: file.id,
@@ -1,6 +1,7 @@
import { createReadStream } from 'node:fs';
import { nanoid } from 'nanoid';
import type { File as FileEntity, NewFile } from '../../domain/entities/file';
import { buildNewFile } from '../../domain/entities/file-factory';
import type { IFileRepository } from '../../domain/ports/file-repository';
import type { ITelegramService } from '../../domain/ports/telegram-service';
import { config } from '../../env';
@@ -92,7 +93,7 @@ export class UploadBatcher {
sizeBytes: number;
},
): NewFile {
return {
return buildNewFile({
publicId: nanoid(),
telegramFileId: archive.telegramFileId,
telegramFileUniqueId: archive.telegramFileUniqueId,
@@ -102,7 +103,7 @@ export class UploadBatcher {
mimeType: item.mimeType || 'application/octet-stream',
sizeBytes: item.prepared.sizeBytes,
fileType: item.fileType,
uploaderId: 0,
storageBackend: null,
fileHash: item.prepared.fileHash,
archiveTelegramFileId: archive.telegramFileId,
archiveStorageMessageId: archive.storageMessageId,
@@ -110,13 +111,7 @@ export class UploadBatcher {
archiveEntryName: entry.entryName,
archiveMimeType: 'application/zip',
archiveSizeBytes: archive.sizeBytes,
bucketId: null,
s3Key: null,
storageBackend: null,
isDeleted: null,
multipartUploadId: null,
partCount: null,
};
});
}
/**