UNPKG

every-plugin

Version:
203 lines (201 loc) 8.09 kB
import { ORPCError } from "@orpc/contract"; import { Cause, Data } from "effect"; //#region src/runtime/errors.ts var PluginRuntimeError = class extends Data.TaggedError("PluginRuntimeError") {}; var ModuleFederationError = class extends Data.TaggedError("ModuleFederationError") {}; var ValidationError = class extends Data.TaggedError("ValidationError") {}; const extractErrorMessage = (error) => { if (!error) return "Unknown error"; if (error instanceof Error) { if (error.message) return error.message; if (error.cause instanceof Error) return extractErrorMessage(error.cause); } if (error instanceof AggregateError && error.errors?.length) return error.errors.map((e) => extractErrorMessage(e)).join("; "); if (typeof error === "object" && "message" in error) return String(error.message); return String(error); }; const formatValidationIssue = (issue, index, maxDisplay) => { if (index >= maxDisplay) return ""; const path = Array.isArray(issue.path) && issue.path.length > 0 ? issue.path.join(".") : issue.path || "root"; const message = issue.message || "Validation failed"; return `│ ${index + 1}. ${path}: ${message}`; }; const formatDataPreview = (data, maxLength = 100) => { if (!data) return "undefined"; try { const str = JSON.stringify(data); if (str.length <= maxLength) return str; if (typeof data === "object" && data !== null) { if (Array.isArray(data)) return `Array(${data.length}) [...]`; const keys = Object.keys(data); return `{ ${keys.slice(0, 3).join(", ")}${keys.length > 3 ? ", ..." : ""} }`; } return `${str.slice(0, maxLength)}...`; } catch { return String(data).slice(0, maxLength); } }; const formatORPCValidationError = (error) => { const cause = error?.cause || error; if (!cause?.issues || !Array.isArray(cause.issues) || cause.issues.length === 0) return null; const lines = []; const errorType = error?.message || cause?.message || "Validation failed"; lines.push(`\n╭─ oRPC Validation Error ${"─".repeat(30)}`); lines.push(`│ ${errorType}`); lines.push(`│`); const maxDisplay = 10; const totalIssues = cause.issues.length; lines.push(`│ Issues (${totalIssues}):`); cause.issues.slice(0, maxDisplay).forEach((issue, idx) => { const formatted = formatValidationIssue(issue, idx, maxDisplay); if (formatted) lines.push(formatted); }); if (totalIssues > maxDisplay) lines.push(`│ ... and ${totalIssues - maxDisplay} more`); if (cause.data !== void 0) { lines.push(`│`); lines.push(`│ Data preview: ${formatDataPreview(cause.data, 80)}`); } lines.push(`╰${"─".repeat(50)}\n`); return lines; }; const formatORPCError = (error) => { if (!(error instanceof ORPCError)) return; const validationLines = formatORPCValidationError(error); if (validationLines) { console.error(validationLines.join("\n")); return; } const lines = []; const code = error.code || "UNKNOWN"; const status = error.status || 500; const message = error.message || "An error occurred"; lines.push(`\n╭─ oRPC Error ${"─".repeat(40)}`); lines.push(`│ ${message}`); lines.push(`│ Code: ${code} (${status})`); lines.push(`│`); if (error.data) { if (typeof error.data === "object" && error.data !== null) { if ("retryAfter" in error.data) lines.push(`│ Retry after: ${error.data.retryAfter} seconds`); if ("remainingRequests" in error.data) lines.push(`│ Remaining: ${error.data.remainingRequests} requests`); if ("host" in error.data) lines.push(`│ Host: ${error.data.host}`); if ("port" in error.data) lines.push(`│ Port: ${error.data.port}`); if ("suggestion" in error.data) lines.push(`│ → ${error.data.suggestion}`); if ("resource" in error.data) lines.push(`│ Resource: ${error.data.resource}`); if ("resourceId" in error.data) lines.push(`│ ID: ${error.data.resourceId}`); } } switch (code) { case "UNAUTHORIZED": lines.push(`│ → Check your API key or credentials`); break; case "TOO_MANY_REQUESTS": lines.push(`│ → Wait before retrying`); break; case "SERVICE_UNAVAILABLE": case "BAD_GATEWAY": case "GATEWAY_TIMEOUT": lines.push(`│ → The service may be temporarily unavailable`); break; case "TIMEOUT": lines.push(`│ → The operation took too long`); break; } lines.push(`╰${"─".repeat(50)}\n`); console.error(lines.join("\n")); }; const formatPluginError = (pluginId, operation, message) => { const lines = []; lines.push(`\n╭─ Plugin Error ${"─".repeat(40)}`); if (pluginId) lines.push(`│ Plugin: ${pluginId}`); if (operation) lines.push(`│ During: ${operation}`); lines.push(`│`); if (message.includes("ECONNREFUSED")) { lines.push(`│ ❌ Connection refused`); lines.push(`│ `); lines.push(`│ A required service is not running.`); lines.push(`│ → Run: docker compose up -d`); } else if (message.includes("ENOTFOUND")) { lines.push(`│ ❌ Host not found`); lines.push(`│ `); lines.push(`│ Check your connection URL or network settings.`); } else if (message.includes("ETIMEDOUT") || message.includes("timeout")) { lines.push(`│ ❌ Connection timeout`); lines.push(`│ `); lines.push(`│ The service took too long to respond.`); } else if (message.includes("EACCES") || message.includes("permission")) { lines.push(`│ ❌ Permission denied`); lines.push(`│ `); lines.push(`│ Check credentials or access permissions.`); } else if (message.includes("401") || message.includes("unauthorized")) { lines.push(`│ ❌ Authentication failed`); lines.push(`│ `); lines.push(`│ Check your API key or credentials.`); } else lines.push(`│ ❌ ${message}`); lines.push(`╰${"─".repeat(50)}\n`); console.error(lines.join("\n")); }; const isRetryableError = (message) => { return [ "ETIMEDOUT", "ECONNRESET", "timeout", "503", "429" ].some((p) => message.toLowerCase().includes(p.toLowerCase())); }; const isRetryableORPCCode = (code) => { switch (code) { case "TOO_MANY_REQUESTS": case "SERVICE_UNAVAILABLE": case "BAD_GATEWAY": case "GATEWAY_TIMEOUT": case "TIMEOUT": return true; default: return false; } }; const wrapORPCError = (orpcError, pluginId, procedureName, operation) => { const validationLines = formatORPCValidationError(orpcError); if (validationLines) console.error(validationLines.join("\n")); return new PluginRuntimeError({ pluginId, operation, procedureName, retryable: isRetryableORPCCode(orpcError.code), cause: orpcError }); }; /** * Extracts the underlying error from Effect's FiberFailure wrapper. * When Effect.runPromise rejects, errors are wrapped in FiberFailure. * This extracts the original error so oRPC can handle it properly. */ const extractFromFiberFailure = (error) => { if (!error || typeof error !== "object") return error; if ("cause" in error) { const cause = error.cause; if (cause && typeof cause === "object" && "_tag" in cause) try { const squashed = Cause.squash(cause); if (squashed instanceof ORPCError) return squashed; return squashed; } catch {} if (cause instanceof ORPCError) return cause; } return error; }; const toPluginRuntimeError = (error, pluginId, procedureName, operation, defaultRetryable = false) => { if (error instanceof ORPCError) return wrapORPCError(error, pluginId, procedureName, operation); if (error instanceof PluginRuntimeError) return error; const validationLines = formatORPCValidationError(error); if (validationLines) console.error(validationLines.join("\n")); else formatPluginError(pluginId, operation, extractErrorMessage(error)); return new PluginRuntimeError({ pluginId, operation, procedureName, retryable: defaultRetryable || isRetryableError(extractErrorMessage(error)), cause: error instanceof Error ? error : new Error(extractErrorMessage(error)) }); }; //#endregion export { ModuleFederationError, PluginRuntimeError, ValidationError, extractFromFiberFailure, formatORPCError, isRetryableORPCCode, toPluginRuntimeError, wrapORPCError }; //# sourceMappingURL=errors.mjs.map