spb/cancerindex
Public
TypeScript 97.2%
SQL 1.5%
CSS 0.6%
JavaScript 0.5%
1/** Pure error classification for database failures (no server-only import so it is unit-testable). */23/** Thrown when the database itself is unreachable (connection refused, auth, pool exhausted…). */4export class DatabaseUnavailableError extends Error {5 readonly code: string | undefined;6 constructor(cause: unknown) {7 const e = cause as { message?: string; code?: string } | undefined;8 super(`Database unavailable${e?.code ? ` (${e.code})` : ''}: ${e?.message ?? String(cause)}`);9 this.name = 'DatabaseUnavailableError';10 this.code = e?.code;11 }12}1314// Node socket errors + postgres.js connection errors + PostgreSQL SQLSTATE classes 08 (connection15// exception), 28 (auth), 3D (bad database), 53 (insufficient resources) and 57P (operator intervention).16const CONNECTION_CODES = new Set(['ECONNREFUSED', 'ECONNRESET', 'ETIMEDOUT', 'ENOTFOUND', 'EHOSTUNREACH', 'EPIPE', 'EAI_AGAIN', 'CONNECT_TIMEOUT', 'CONNECTION_CLOSED', 'CONNECTION_ENDED', 'CONNECTION_DESTROYED']);17const CONNECTION_SQLSTATE = /^(08|28|3D|53|57P)/;18const CONNECTION_MESSAGE = /ECONNREFUSED|ECONNRESET|ETIMEDOUT|ENOTFOUND|connection (refused|terminated|closed|ended)|CONNECT_TIMEOUT|too many connections|password authentication failed/i;1920/** True when the error means "the database is unreachable" rather than "this query/table is wrong". */21export function isConnectionError(err: unknown, depth = 0): boolean {22 if (!err || typeof err !== 'object' || depth > 4) return false;23 const e = err as { code?: unknown; errno?: unknown; message?: unknown; cause?: unknown };24 const code = typeof e.code === 'string' ? e.code : typeof e.errno === 'string' ? e.errno : '';25 if (code && (CONNECTION_CODES.has(code) || CONNECTION_SQLSTATE.test(code))) return true;26 if (typeof e.message === 'string' && CONNECTION_MESSAGE.test(e.message)) return true;27 return e.cause != null && e.cause !== err ? isConnectionError(e.cause, depth + 1) : false;28}29