feat: add query functions for listing skipped/failed packages

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-03-24 16:19:42 +01:00
parent 094001f9f7
commit 71c3228e44
2 changed files with 66 additions and 0 deletions

View File

@@ -4,6 +4,7 @@ import type {
PackageDetail,
PackageFileItem,
IngestionAccountStatus,
SkippedPackageItem,
} from "./types";
export async function listPackages(options: {
@@ -336,3 +337,52 @@ export async function getIngestionStatus(): Promise<IngestionAccountStatus[]> {
return statuses;
}
export async function listSkippedPackages(options: {
page: number;
limit: number;
reason?: "SIZE_LIMIT" | "DOWNLOAD_FAILED" | "EXTRACT_FAILED" | "UPLOAD_FAILED";
}) {
const where: Record<string, unknown> = {};
if (options.reason) where.reason = options.reason;
const [items, total] = await Promise.all([
prisma.skippedPackage.findMany({
where,
orderBy: { createdAt: "desc" },
skip: (options.page - 1) * options.limit,
take: options.limit,
include: {
sourceChannel: { select: { id: true, title: true } },
},
}),
prisma.skippedPackage.count({ where }),
]);
const mapped: SkippedPackageItem[] = items.map((s) => ({
id: s.id,
fileName: s.fileName,
fileSize: s.fileSize.toString(),
reason: s.reason,
errorMessage: s.errorMessage,
sourceChannel: s.sourceChannel,
sourceMessageId: s.sourceMessageId.toString(),
isMultipart: s.isMultipart,
partCount: s.partCount,
createdAt: s.createdAt.toISOString(),
}));
return {
items: mapped,
pagination: {
page: options.page,
limit: options.limit,
total,
totalPages: Math.ceil(total / options.limit),
},
};
}
export async function countSkippedPackages(): Promise<number> {
return prisma.skippedPackage.count();
}

View File

@@ -42,6 +42,22 @@ export interface PackageFileItem {
crc32: string | null;
}
export interface SkippedPackageItem {
id: string;
fileName: string;
fileSize: string;
reason: "SIZE_LIMIT" | "DOWNLOAD_FAILED" | "EXTRACT_FAILED" | "UPLOAD_FAILED";
errorMessage: string | null;
sourceChannel: {
id: string;
title: string;
};
sourceMessageId: string;
isMultipart: boolean;
partCount: number;
createdAt: string;
}
export interface PaginatedResponse<T> {
items: T[];
pagination: {