UNPKG

openclaw

Version:

Multi-channel AI gateway with extensible messaging integrations

139 lines (138 loc) 6.13 kB
import { o as sha256HexPrefixCore } from "./crypto-digest-C4hqTb_e.js"; //#region src/infra/diagnostic-error-metadata.ts const HTTP_STATUS_MIN = 100; const HTTP_STATUS_MAX = 599; const REQUEST_ID_HASH_PREFIX_LEN = 12; const PROVIDER_REQUEST_ID_KEYS = [ "upstreamRequestId", "providerRequestId", "requestId", "request_id" ]; const PROVIDER_REQUEST_ID_RE = /^[A-Za-z0-9._:-]{1,128}$/u; const PROVIDER_REQUEST_ID_TEXT_PATTERNS = [/\b(?:x-request-id|request-id|request_id|requestId|trace-id|trace_id)\b["'\s:=([]+([A-Za-z0-9._:-]{1,128})/i, /\((?:request_id|trace_id)\s*:\s*([A-Za-z0-9._:-]{1,128})\)/i]; function isObjectLike(value) { return (typeof value === "object" || typeof value === "function") && value !== null; } function readOwnDataProperty(value, key) { if (!isObjectLike(value)) return; try { const descriptor = Object.getOwnPropertyDescriptor(value, key); return descriptor && "value" in descriptor ? descriptor.value : void 0; } catch { return; } } function findDiagnosticErrorProperty(err, reader, seen = /* @__PURE__ */ new Set()) { const direct = reader(err); if (direct !== void 0) return direct; if (!isObjectLike(err) || seen.has(err)) return; seen.add(err); return findDiagnosticErrorProperty(readOwnDataProperty(err, "error"), reader, seen) ?? findDiagnosticErrorProperty(readOwnDataProperty(err, "cause"), reader, seen); } function isHttpStatusCode(value) { return typeof value === "number" && Number.isInteger(value) && value >= HTTP_STATUS_MIN && value <= HTTP_STATUS_MAX; } function normalizeProviderRequestId(value) { if (typeof value === "string") { const trimmed = value.trim(); return PROVIDER_REQUEST_ID_RE.test(trimmed) ? trimmed : void 0; } if (typeof value === "number" && Number.isFinite(value)) { const normalized = String(value); return PROVIDER_REQUEST_ID_RE.test(normalized) ? normalized : void 0; } if (typeof value === "bigint") { const normalized = String(value); return PROVIDER_REQUEST_ID_RE.test(normalized) ? normalized : void 0; } } function hashDiagnosticIdentifier(value) { return `sha256:${sha256HexPrefixCore(value, REQUEST_ID_HASH_PREFIX_LEN)}`; } function readDirectProviderRequestId(err) { for (const key of PROVIDER_REQUEST_ID_KEYS) { const normalized = normalizeProviderRequestId(readOwnDataProperty(err, key)); if (normalized) return normalized; } } function readDirectMessage(err) { if (typeof err === "string") return err; const message = readOwnDataProperty(err, "message"); return typeof message === "string" ? message : void 0; } function readDirectCode(err) { const code = readOwnDataProperty(err, "code"); return typeof code === "string" ? code : void 0; } function extractProviderRequestIdFromText(text) { if (!text) return; for (const pattern of PROVIDER_REQUEST_ID_TEXT_PATTERNS) { const normalized = normalizeProviderRequestId(text.match(pattern)?.[1]); if (normalized) return normalized; } } /** Returns a low-cardinality error category without trusting mutable `Error.name`. */ function diagnosticErrorCategory(err) { try { if (err instanceof TypeError) return "TypeError"; if (err instanceof RangeError) return "RangeError"; if (err instanceof ReferenceError) return "ReferenceError"; if (err instanceof SyntaxError) return "SyntaxError"; if (err instanceof URIError) return "URIError"; if (typeof AggregateError !== "undefined" && err instanceof AggregateError) return "AggregateError"; if (err instanceof Error) return "Error"; } catch { return "unknown"; } if (err === null) return "null"; return typeof err; } /** * Human-readable error message for diagnostics. Complements * {@link diagnosticErrorCategory} (low-cardinality class name) with the actual * message so error spans carry a real status message instead of a bare * category. Reads only an own data property so diagnostics never invoke a * user-defined getter. */ function diagnosticErrorMessage(err) { const trimmed = readDirectMessage(err)?.trim(); return trimmed ? trimmed : void 0; } /** Extracts a safe HTTP status code from own `status` or `statusCode` data properties. */ function diagnosticHttpStatusCode(err) { const status = readOwnDataProperty(err, "status"); if (isHttpStatusCode(status)) return String(status); const statusCode = readOwnDataProperty(err, "statusCode"); if (isHttpStatusCode(statusCode)) return String(statusCode); } /** Classifies transport-style failures without exposing raw error messages. */ function diagnosticErrorFailureKind(err) { switch (findDiagnosticErrorProperty(err, readDirectCode)?.trim().toUpperCase()) { case void 0: break; case "ABORT_ERR": case "ECONNABORTED": case "ERR_ABORTED": return "aborted"; case "ECONNRESET": return "connection_reset"; case "ERR_STREAM_PREMATURE_CLOSE": case "UND_ERR_SOCKET": return "connection_closed"; case "ETIMEDOUT": case "ERR_SOCKET_CONNECTION_TIMEOUT": return "timeout"; } const message = findDiagnosticErrorProperty(err, readDirectMessage); if (!message) return; if (/\b(?:terminated|sigkill|sigterm)\b/i.test(message)) return "terminated"; if (/\b(?:econnreset|connection reset)\b/i.test(message)) return "connection_reset"; if (/\b(?:socket hang up|premature close|connection closed|other side closed)\b/i.test(message)) return "connection_closed"; if (/\b(?:timed out|timeout|etimedout)\b/i.test(message)) return "timeout"; if (/\b(?:aborted|abort_err|operation was aborted)\b/i.test(message)) return "aborted"; } /** Extracts and hashes bounded provider request ids so diagnostics never expose raw ids. */ function diagnosticProviderRequestIdHash(err) { const fromProperty = findDiagnosticErrorProperty(err, readDirectProviderRequestId); if (fromProperty) return hashDiagnosticIdentifier(fromProperty); const fromMessage = findDiagnosticErrorProperty(err, (candidate) => extractProviderRequestIdFromText(readDirectMessage(candidate))); return fromMessage ? hashDiagnosticIdentifier(fromMessage) : void 0; } //#endregion export { diagnosticProviderRequestIdHash as a, diagnosticHttpStatusCode as i, diagnosticErrorFailureKind as n, diagnosticErrorMessage as r, diagnosticErrorCategory as t };