mirror of
https://github.com/snapotter-hq/SnapOtter.git
synced 2026-08-03 07:46:42 +02:00
fix(tools): classify expected input and timeout errors, not bugs (#539)
crop/merge-pdf/csv bad input -> ToolInputError/InputValidationError (expected, 4xx); ffmpeg timeout -> operational SafeError. Internal v2-only guards stay plain Errors.
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
import type { FastifyInstance } from "fastify";
|
||||
import Papa from "papaparse";
|
||||
import { z } from "zod";
|
||||
import { InputValidationError } from "../../modality/contract.js";
|
||||
import { createToolRoute } from "../tool-factory.js";
|
||||
|
||||
const settingsSchema = z.object({
|
||||
@@ -31,7 +32,7 @@ export function registerCsvExcel(app: FastifyInstance) {
|
||||
await workbook.xlsx.load(input.buffer as unknown as ArrayBuffer);
|
||||
const ws = workbook.worksheets[settings.sheet - 1];
|
||||
if (!ws) {
|
||||
throw new Error(
|
||||
throw new InputValidationError(
|
||||
`Worksheet ${settings.sheet} not found (workbook has ${workbook.worksheets.length} sheets)`,
|
||||
);
|
||||
}
|
||||
@@ -59,7 +60,7 @@ export function registerCsvExcel(app: FastifyInstance) {
|
||||
skipEmptyLines: true,
|
||||
});
|
||||
if (parsed.errors.length > 0) {
|
||||
throw new Error(`CSV parse failed: ${parsed.errors[0].message}`);
|
||||
throw new InputValidationError(`CSV parse failed: ${parsed.errors[0].message}`);
|
||||
}
|
||||
const workbook = new ExcelJS.Workbook();
|
||||
const ws = workbook.addWorksheet("Sheet1");
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import type { FastifyInstance } from "fastify";
|
||||
import Papa from "papaparse";
|
||||
import { z } from "zod";
|
||||
import { InputValidationError } from "../../modality/contract.js";
|
||||
import { createToolRoute } from "../tool-factory.js";
|
||||
|
||||
const settingsSchema = z.object({
|
||||
@@ -26,13 +27,15 @@ export function registerCsvJson(app: FastifyInstance) {
|
||||
data = JSON.parse(input.buffer.toString("utf8"));
|
||||
} catch (err: unknown) {
|
||||
const msg = err instanceof Error ? err.message : String(err);
|
||||
throw new Error(`Not valid JSON: ${msg.split("\n")[0]}`);
|
||||
throw new InputValidationError(`Not valid JSON: ${msg.split("\n")[0]}`);
|
||||
}
|
||||
if (!Array.isArray(data)) {
|
||||
throw new Error("JSON input must be an array of objects to convert to CSV");
|
||||
throw new InputValidationError(
|
||||
"JSON input must be an array of objects to convert to CSV",
|
||||
);
|
||||
}
|
||||
if (data.some((r) => r === null || typeof r !== "object" || Array.isArray(r))) {
|
||||
throw new Error("JSON array elements must be objects to convert to CSV");
|
||||
throw new InputValidationError("JSON array elements must be objects to convert to CSV");
|
||||
}
|
||||
// Flatten nested objects/arrays to JSON strings (Papa would otherwise emit
|
||||
// "[object Object]"), and pass the union of all keys so columns appearing
|
||||
@@ -58,7 +61,7 @@ export function registerCsvJson(app: FastifyInstance) {
|
||||
skipEmptyLines: true,
|
||||
});
|
||||
if (parsed.errors.length > 0) {
|
||||
throw new Error(`CSV parse failed: ${parsed.errors[0].message}`);
|
||||
throw new InputValidationError(`CSV parse failed: ${parsed.errors[0].message}`);
|
||||
}
|
||||
const json = JSON.stringify(parsed.data, null, settings.pretty ? 2 : 0);
|
||||
return {
|
||||
|
||||
@@ -3,6 +3,7 @@ import { join } from "node:path";
|
||||
import { qpdfMerge } from "@snapotter/doc-engine";
|
||||
import type { FastifyInstance } from "fastify";
|
||||
import { z } from "zod";
|
||||
import { InputValidationError } from "../../modality/contract.js";
|
||||
import { createToolRoute } from "../tool-factory.js";
|
||||
|
||||
const settingsSchema = z.object({});
|
||||
@@ -17,7 +18,7 @@ export function registerMergePdf(app: FastifyInstance) {
|
||||
},
|
||||
processV2: async (ctx) => {
|
||||
if (ctx.inputs.length < 2) {
|
||||
throw new Error("Merging needs at least two PDFs");
|
||||
throw new InputValidationError("Merging needs at least two PDFs");
|
||||
}
|
||||
ctx.report(10, "Staging");
|
||||
const paths: string[] = [];
|
||||
|
||||
Reference in New Issue
Block a user