Compare commits

...

1 Commits

Author SHA1 Message Date
nav
4d8c787dbc feat(protocol): add shared protocol error helpers 2026-04-08 20:33:25 +00:00
2 changed files with 94 additions and 0 deletions

93
src/errors.ts Normal file
View File

@@ -0,0 +1,93 @@
import type { BuiltinEnvelope, ErrorPayload, ProtocolErrorCode, TypedBuiltinEnvelope } from "./types.js";
export type ProtocolErrorCategory =
| "configuration"
| "protocol"
| "authentication"
| "pairing"
| "runtime";
export interface ProtocolErrorOptions {
message?: string;
details?: Record<string, unknown>;
cause?: unknown;
}
const protocolErrorCategories: Record<ProtocolErrorCode, ProtocolErrorCategory> = {
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<string, unknown>;
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";
}

View File

@@ -1,2 +1,3 @@
export * from "./types.js"; export * from "./types.js";
export * from "./codec.js"; export * from "./codec.js";
export * from "./errors.js";