evOo-local/packages/logging/src/serialize-error.ts
cynarAI 6c7eed7580 Initial clean evOo-local from f00577b
Fresh history cut from cynarAI/evoo antigravity-handoff/project-timeline
(Voice First + project timeline). Brand docs/titles as evOo; keep @rakazo/*
packages as tech debt. Excludes node_modules, caches, secrets, voice blobs.
2026-09-20 17:15:16 +02:00

40 lines
1.3 KiB
TypeScript

import { redactSensitiveText } from "./redaction.js";
import type { SerializedError } from "./types.js";
const MAX_CAUSE_DEPTH = 5;
export function serializeError(error: unknown, seen = new Set<unknown>()): SerializedError {
if (!(error instanceof Error)) {
return { name: "Error", message: stringifyUnknown(error) };
}
if (seen.has(error)) {
return { name: error.name, message: "[Circular]" };
}
seen.add(error);
const serialized: SerializedError = {
name: error.name || "Error",
message: redactSensitiveText(error.message),
};
if (typeof error.stack === "string" && error.stack.length > 0) {
serialized.stack = redactSensitiveText(error.stack);
}
if (error.cause !== undefined && seen.size < MAX_CAUSE_DEPTH) {
serialized.cause = serializeError(error.cause, seen);
}
return serialized;
}
function stringifyUnknown(value: unknown): string {
if (typeof value === "string") return redactSensitiveText(value);
if (typeof value === "number" || typeof value === "boolean" || typeof value === "bigint") {
return String(value);
}
if (value === null) return "null";
if (value === undefined) return "undefined";
try {
return redactSensitiveText(JSON.stringify(value) ?? String(value));
} catch {
return Object.prototype.toString.call(value);
}
}