Files
suaveplan/packages/persistence/database/surrealdb/src/errors/error.ts
2026-05-27 23:47:53 +01:00

86 lines
2.6 KiB
TypeScript

import {
defineCodes,
SuaveplanError,
type SuaveplanErrorOptions,
} from "@suaveplan/error";
/**
* Stable error code registry for the `@suaveplan/surrealdb` package.
* All codes are prefixed with `SURREAL.` to avoid collisions with other
* packages in the same process.
*/
export const SURREAL_CODES = defineCodes("SURREAL", [
"CONNECTION_FAILED",
"NOT_CONNECTED",
"QUERY_FAILED",
"AUTH_FAILED",
"TIMEOUT",
"VERSION_UNSUPPORTED",
"SCHEMA_LOAD_FAILED",
"INIT_FAILED",
"TRANSACTION_FAILED",
"RECORD_NOT_FOUND",
] as const);
export type SurrealCode = (typeof SURREAL_CODES)[keyof typeof SURREAL_CODES];
/**
* Structured error class for all SurrealDB adapter failures.
*
* Extends `SuaveplanError` and carries a stable `SurrealCode` discriminant
* so callers can match errors without string comparison.
*/
export class SurrealError extends SuaveplanError<SurrealCode> {
public constructor(
code: SurrealCode,
message: string,
options?: SuaveplanErrorOptions
) {
// Normalise empty/whitespace messages so downstream log surfaces
// (OTel attributes, console.error) always carry the stable code
// rather than rendering an empty `Error: ` line. The public
// constructor also widens the protected `SuaveplanError`
// constructor for in-process callers.
const normalised =
message.trim().length > 0 ? message : `SurrealError(${code})`;
super(code, normalised, options);
this.name = "SurrealError";
}
}
/**
* Map a raw driver error to the most appropriate `SurrealCode`.
*
* Returns `SURREAL.QUERY_FAILED` as a safe fallback for unrecognised inputs.
*/
export function mapSurrealCode(err: unknown): SurrealCode {
if (err instanceof SurrealError) return err.code;
const msg =
err instanceof Error
? err.message.toLowerCase()
: String(err).toLowerCase();
if (
msg.includes("connect") ||
msg.includes("connection") ||
msg.includes("econnrefused") ||
msg.includes("connectionrefused")
) {
return SURREAL_CODES.CONNECTION_FAILED;
}
if (msg.includes("auth") || msg.includes("wrong credentials")) {
return SURREAL_CODES.AUTH_FAILED;
}
if (msg.includes("timeout") || msg.includes("timed out")) {
return SURREAL_CODES.TIMEOUT;
}
if (msg.includes("not found") || msg.includes("does not exist")) {
return SURREAL_CODES.RECORD_NOT_FOUND;
}
if (msg.includes("transaction")) {
return SURREAL_CODES.TRANSACTION_FAILED;
}
return SURREAL_CODES.QUERY_FAILED;
}