Files
bea-edit/src/lib/batch.ts
T
2026-10-28 09:25:15 +01:00

76 lines
2.2 KiB
TypeScript

export type BatchItemStatus = 'pending' | 'processing' | 'done' | 'error';
export type BatchItem = {
id: string;
file: File;
status: BatchItemStatus;
resultBytes?: Uint8Array;
resultName?: string;
errorMessage?: string | null;
};
export type BatchProcessResult = { bytes: Uint8Array; name: string };
export type BatchRunOptions = {
/**
* Error message written to a row when `process` throws for it. A function
* receives the thrown error so tools can surface a specific German message.
*/
errorMessage?: string | ((error: unknown, file: File) => string);
/**
* Optional predicate consulted before each item; when it returns `false`
* (for example because the row was removed mid-run), the item is skipped.
*/
shouldProcess?: (id: string) => boolean;
};
export const createBatchItem = (file: File): BatchItem => ({
id: crypto.randomUUID(),
file,
status: 'pending'
});
/**
* Processes the given items strictly one after another so only one PDF is in
* flight at a time. Never throws: a failing item is marked as an error row and
* the queue continues with the remaining files.
*/
export const runBatch = async (
items: BatchItem[],
process: (file: File) => Promise<BatchProcessResult>,
update: (id: string, patch: Partial<BatchItem>) => void,
options: BatchRunOptions = {}
): Promise<void> => {
const { errorMessage = 'Die Datei konnte nicht verarbeitet werden.', shouldProcess } = options;
for (const item of items) {
if (shouldProcess && !shouldProcess(item.id)) continue;
update(item.id, { status: 'processing', errorMessage: null });
try {
const result = await process(item.file);
update(item.id, {
status: 'done',
resultBytes: result.bytes,
resultName: result.name,
errorMessage: null
});
} catch (error) {
console.error(`Batch processing failed for ${item.file.name}:`, error);
update(item.id, {
status: 'error',
resultBytes: undefined,
resultName: undefined,
errorMessage:
typeof errorMessage === 'function' ? errorMessage(error, item.file) : errorMessage
});
}
}
};
export const formatBytes = (bytes: number) => {
if (bytes < 1024) return `${bytes} B`;
if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;
return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
};