metis-desk/apps/server/src/infrastructure/http/http-error-diagnostic.ts
David 37110d87ed feat: add optional registeredOn field to asset model and update related components
- Introduced a new optional field `registeredOn` to the asset input schema.
- Updated asset values and persistence layers to handle the new field.
- Enhanced tests to validate the behavior of the `registeredOn` field, including various date formats and null values.
- Modified UI components to display the registration date in asset details and forms.
- Added localization support for the new field in English and Spanish.
- Implemented helper functions for formatting the registration date.
- Created integration tests for reading and writing assets with the new field in the database.
2026-10-15 18:39:37 +02:00

49 lines
1.9 KiB
TypeScript

export type HttpErrorDiagnostic = Readonly<{
name: string;
code?: string;
errno?: number;
sqlState?: string;
frames: readonly string[];
}>;
/** Extrae datos técnicos sin serializar mensajes, SQL ni propiedades arbitrarias del error. */
export function httpErrorDiagnostics(failure: unknown): readonly HttpErrorDiagnostic[] {
const diagnostics: HttpErrorDiagnostic[] = [];
const visited = new Set<Error>();
let current = failure;
while (current instanceof Error && !visited.has(current) && diagnostics.length < 5) {
visited.add(current);
diagnostics.push(describeError(current));
current =
current.cause instanceof Error
? current.cause
: "parent" in current
? current.parent
: undefined;
}
return diagnostics.length ? diagnostics : [{ name: "NonErrorThrown", frames: [] }];
}
function describeError(failure: Error): HttpErrorDiagnostic {
const code = "code" in failure ? failure.code : undefined;
const errno = "errno" in failure ? failure.errno : undefined;
const sqlState = "sqlState" in failure ? failure.sqlState : undefined;
// El prefijo puede contener un mensaje multilínea: se elimina completo antes de leer los frames.
const prefix = failure.message ? `${failure.name}: ${failure.message}` : failure.name;
const stack = failure.stack?.startsWith(prefix) ? failure.stack.slice(prefix.length) : "";
return {
name: /^[A-Za-z][A-Za-z0-9]*Error$|^Error$/.test(failure.name) ? failure.name : "Error",
...(typeof code === "string" && /^(?:ER_[A-Z0-9_]+|E[A-Z0-9_]+)$/.test(code) ? { code } : {}),
...(typeof errno === "number" && Number.isSafeInteger(errno) ? { errno } : {}),
...(typeof sqlState === "string" && /^[0-9A-Z]{5}$/.test(sqlState) ? { sqlState } : {}),
frames: stack
.split("\n")
.filter((line) => /^\s+at .+:\d+:\d+\)?$/.test(line))
.slice(0, 20)
.map((line) => line.trim()),
};
}