import type { BuiltinEnvelope, ErrorPayload, ProtocolErrorCode, TypedBuiltinEnvelope } from "./types.js"; export type ProtocolErrorCategory = | "configuration" | "protocol" | "authentication" | "pairing" | "runtime"; export interface ProtocolErrorOptions { message?: string; details?: Record; cause?: unknown; } const protocolErrorCategories: Record = { MALFORMED_MESSAGE: "protocol", UNSUPPORTED_PROTOCOL_VERSION: "protocol", IDENTIFIER_NOT_ALLOWED: "protocol", PAIRING_REQUIRED: "pairing", PAIRING_EXPIRED: "pairing", ADMIN_NOTIFICATION_FAILED: "pairing", AUTH_FAILED: "authentication", NONCE_COLLISION: "authentication", RATE_LIMITED: "authentication", RE_PAIR_REQUIRED: "authentication", CLIENT_OFFLINE: "runtime", INTERNAL_ERROR: "runtime" }; export function getProtocolErrorCategory(code: ProtocolErrorCode): ProtocolErrorCategory { return protocolErrorCategories[code]; } export class YonexusProtocolError extends Error { readonly code: ProtocolErrorCode; readonly category: ProtocolErrorCategory; readonly details?: Record; override readonly cause?: unknown; constructor(code: ProtocolErrorCode, options: ProtocolErrorOptions = {}) { super(options.message ?? code); this.name = "YonexusProtocolError"; this.code = code; this.category = getProtocolErrorCategory(code); this.details = options.details; this.cause = options.cause; } toPayload(): ErrorPayload { return { code: this.code, message: this.message, details: this.details }; } toEnvelope(timestamp: number = Math.floor(Date.now() / 1000)): TypedBuiltinEnvelope<"error"> { return { type: "error", timestamp, payload: this.toPayload() }; } } export function createProtocolError( code: ProtocolErrorCode, options: ProtocolErrorOptions = {} ): YonexusProtocolError { return new YonexusProtocolError(code, options); } export function protocolErrorFromPayload( payload: ErrorPayload, cause?: unknown ): YonexusProtocolError { return new YonexusProtocolError(payload.code, { message: payload.message, details: payload.details, cause }); } export function isProtocolError(value: unknown): value is YonexusProtocolError { return value instanceof YonexusProtocolError; } export function isProtocolErrorEnvelope( envelope: BuiltinEnvelope ): envelope is TypedBuiltinEnvelope<"error"> { return envelope.type === "error"; }