chore: fix lint errors — duplicate import, unused imports, formatting
Deploy FileDrop / deploy (push) Successful in 45s

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Claude
2026-07-28 20:09:42 +07:00
parent 002492626b
commit 667921b100
41 changed files with 241 additions and 238 deletions
+8 -2
View File
@@ -1,5 +1,11 @@
import { timingSafeEqual } from 'node:crypto';
import type { LoginInput, LoginResponse, LogoutResponse, UserInfoResponse, AuthSession } from '../dto/auth';
import type {
AuthSession,
LoginInput,
LoginResponse,
LogoutResponse,
UserInfoResponse,
} from '../dto/auth';
/** Subset of application configuration consumed by the authenticate use case. */
export interface AuthUseCaseConfig {
@@ -105,4 +111,4 @@ export function createMeUseCase(deps: AuthenticateUseCaseDeps) {
expiresAt: session.expiresAt?.toISOString() ?? null,
};
};
}
}
+1 -1
View File
@@ -173,4 +173,4 @@ export function createGetFileUseCase(deps: GetFileUseCaseDeps) {
return { type: 'redirect', file, redirectUrl, fileInfo };
};
}
}
+4 -16
View File
@@ -98,11 +98,7 @@ export function createGetBucketUseCase(deps: ManageBucketDeps) {
export function createCreateBucketUseCase(deps: ManageBucketDeps) {
return async (name: string): Promise<Bucket> => {
if (!BUCKET_NAME_REGEX.test(name)) {
throw new BucketError(
'InvalidBucketName',
'The specified bucket is not valid.',
400,
);
throw new BucketError('InvalidBucketName', 'The specified bucket is not valid.', 400);
}
const existing = await deps.bucketRepo.findByName(name);
@@ -134,20 +130,12 @@ export function createDeleteBucketUseCase(deps: ManageBucketDeps) {
return async (name: string): Promise<boolean> => {
const bucket = await deps.bucketRepo.findByName(name);
if (!bucket) {
throw new BucketError(
'NoSuchBucket',
'The specified bucket does not exist.',
404,
);
throw new BucketError('NoSuchBucket', 'The specified bucket does not exist.', 404);
}
const objectCount = await deps.fileRepo.countByBucket(bucket.id);
if (objectCount > 0) {
throw new BucketError(
'BucketNotEmpty',
'The bucket you tried to delete is not empty.',
409,
);
throw new BucketError('BucketNotEmpty', 'The bucket you tried to delete is not empty.', 409);
}
return deps.bucketRepo.delete(name);
@@ -165,4 +153,4 @@ export function createBucketExistsUseCase(deps: ManageBucketDeps) {
return async (name: string): Promise<boolean> => {
return deps.bucketRepo.exists(name);
};
}
}
@@ -116,10 +116,7 @@ export interface MultipartDeps {
* the upload initiation result, or `null` when the bucket is not found.
*/
export function createInitiateMultipartUploadUseCase(deps: MultipartDeps) {
return async (
bucketName: string,
key: string,
): Promise<InitiateMultipartResult | null> => {
return async (bucketName: string, key: string): Promise<InitiateMultipartResult | null> => {
const bucket = await deps.bucketRepo.findByName(bucketName);
if (!bucket) return null;
@@ -375,4 +372,4 @@ export function createListPartsUseCase(deps: MultipartDeps) {
createdAt: p.createdAt,
}));
};
}
}
+24 -7
View File
@@ -1,7 +1,7 @@
import { randomUUID } from 'node:crypto';
import { gzipSync } from 'node:zlib';
import { nanoid } from 'nanoid';
import type { File, NewFile } from '../../domain/entities/file';
import type { File } from '../../domain/entities/file';
import type { NewFilePart } from '../../domain/entities/file-part';
import type { MultipartPart } from '../../domain/entities/multipart';
import type { IBucketRepository } from '../../domain/ports/bucket-repository';
@@ -9,7 +9,7 @@ import type { IFilePartRepository } from '../../domain/ports/file-part-repositor
import type { IFileRepository, S3FileRecord } from '../../domain/ports/file-repository';
import type { IMultipartRepository } from '../../domain/ports/multipart-repository';
import type { ITelegramService, TelegramFileInfo } from '../../domain/ports/telegram-service';
import { ensureExtension, computeHash, formatCreatedAt } from '../../shared/utils/file';
import { computeHash, ensureExtension, formatCreatedAt } from '../../shared/utils/file';
// ─── Types ──────────────────────────────────────────────────────────
@@ -456,7 +456,12 @@ export function createPutObjectUseCase(deps: S3ObjectDeps) {
);
const partFileNamePrefix = `s3-${bucket.name}-${key.replace(/\//g, '_')}`;
const { telegramChunkSizeBytes, compressChunkedUploads, chunkCompressionMinSizeBytes, storageChatId } = deps.config;
const {
telegramChunkSizeBytes,
compressChunkedUploads,
chunkCompressionMinSizeBytes,
storageChatId,
} = deps.config;
if (body.byteLength > telegramChunkSizeBytes) {
// Chunked upload path
@@ -594,16 +599,28 @@ export function createCopyObjectUseCase(deps: S3ObjectDeps) {
if (!sourceFile) return null;
if (sourceFile.storageBackend === 'chunked') {
throw new ObjectError('NotImplemented', 'Copying chunked objects is not yet implemented.', 501);
throw new ObjectError(
'NotImplemented',
'Copying chunked objects is not yet implemented.',
501,
);
}
// Conditional copy: if-match / if-none-match checks
const sourceEtag = sourceFile.fileHash;
if (input.ifMatch && sourceEtag && input.ifMatch !== sourceEtag) {
throw new ObjectError('PreconditionFailed', 'The preconditions you specified did not hold.', 412);
throw new ObjectError(
'PreconditionFailed',
'The preconditions you specified did not hold.',
412,
);
}
if (input.ifNoneMatch && sourceEtag && input.ifNoneMatch === sourceEtag) {
throw new ObjectError('PreconditionFailed', 'The preconditions you specified did not hold.', 412);
throw new ObjectError(
'PreconditionFailed',
'The preconditions you specified did not hold.',
412,
);
}
const publicId = nanoid();
@@ -771,4 +788,4 @@ export function createFindObjectUseCase(deps: Pick<S3ObjectDeps, 'fileRepo'>) {
return async (bucketId: string, key: string): Promise<File | null> => {
return deps.fileRepo.findByBucketAndKey(bucketId, key);
};
}
}
+5 -4
View File
@@ -1,14 +1,14 @@
import { randomUUID } from 'node:crypto';
import { open } from 'node:fs/promises';
import { createReadStream } from 'node:fs';
import { open } from 'node:fs/promises';
import { gzipSync } from 'node:zlib';
import { nanoid } from 'nanoid';
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';
import type { ITelegramService } from '../../domain/ports/telegram-service';
import { checkFileSize, computeHash, ensureExtension, getFileType } from '../../shared/utils/file';
import type { UploadInput, UploadOutput } from '../dto/upload';
import { getFileType, checkFileSize, ensureExtension, computeHash, formatCreatedAt } from '../../shared/utils/file';
/** Compression algorithm string literal used in chunked storage. */
type ChunkCompressionAlgorithm = 'gzip' | null;
@@ -219,7 +219,8 @@ export function createUploadFileUseCase(deps: UploadFileUseCaseDeps) {
mimeType: existing.mimeType,
sizeBytes: existing.sizeBytes,
fileType: existing.fileType,
createdAt: existing.createdAt instanceof Date ? existing.createdAt : new Date(existing.createdAt),
createdAt:
existing.createdAt instanceof Date ? existing.createdAt : new Date(existing.createdAt),
downloadUrl: `${deps.config.baseUrl}/f/${existing.publicId}`,
};
}
@@ -357,4 +358,4 @@ export function createUploadFileUseCase(deps: UploadFileUseCaseDeps) {
downloadUrl: `${deps.config.baseUrl}/f/${createdFile.publicId}`,
};
};
}
}