| ... | ... | @@ -1,17 +1,49 @@ |
| 1 | import * as Cause from "effect/Cause"; |
| 2 | |
| 3 | const MAX_ERROR_TRACE_NODES = 128; |
| 4 | |
| 1 | 5 | export function findErrorTraceId(error: unknown): string | null { |
| 2 | 6 | const seen = new Set<object>(); |
| 3 | | let current: unknown = error; |
| 7 | const pending: Array<unknown> = [error]; |
| 8 | let inspectedNodeCount = 0; |
| 4 | 9 | |
| 5 | | while (typeof current === "object" && current !== null && !seen.has(current)) { |
| 10 | while (pending.length > 0 && inspectedNodeCount < MAX_ERROR_TRACE_NODES) { |
| 11 | const current = pending.pop(); |
| 12 | inspectedNodeCount += 1; |
| 13 | if (typeof current !== "object" || current === null || seen.has(current)) { |
| 14 | continue; |
| 15 | } |
| 6 | 16 | seen.add(current); |
| 7 | 17 | const record = current as { |
| 8 | 18 | readonly cause?: unknown; |
| 19 | readonly errors?: unknown; |
| 9 | 20 | readonly traceId?: unknown; |
| 10 | 21 | }; |
| 11 | 22 | if (typeof record.traceId === "string" && record.traceId.trim().length > 0) { |
| 12 | 23 | return record.traceId; |
| 13 | 24 | } |
| 14 | | current = record.cause; |
| 25 | |
| 26 | if (Array.isArray(record.errors)) { |
| 27 | for (let index = record.errors.length - 1; index >= 0; index -= 1) { |
| 28 | pending.push(record.errors[index]); |
| 29 | } |
| 30 | } |
| 31 | if (Cause.isCause(current)) { |
| 32 | for (let index = current.reasons.length - 1; index >= 0; index -= 1) { |
| 33 | const reason = current.reasons[index]; |
| 34 | switch (reason?._tag) { |
| 35 | case "Fail": |
| 36 | pending.push(reason.error); |
| 37 | break; |
| 38 | case "Die": |
| 39 | pending.push(reason.defect); |
| 40 | break; |
| 41 | } |
| 42 | } |
| 43 | } |
| 44 | if ("cause" in record) { |
| 45 | pending.push(record.cause); |
| 46 | } |
| 15 | 47 | } |
| 16 | 48 | |
| 17 | 49 | return null; |