/** * Errors thrown by the dispatch pipeline. * * Each implements `KernelErrorClassifiable` so `kernel-api/dispatch` can * convert them into typed `KernelErrorPayload` values automatically. */ import type { KernelErrorPayload, KernelErrorClassifiable } from '@astrale-os/kernel-api' import { KERNEL_ERROR_CODES } from '@astrale-os/kernel-api' /** A single Zod issue, normalized to the path/message the payload carries. */ type ValidationIssue = { path: (string | number)[]; message: string } /** Shape Zod issues into the `data.errors` array of a `KernelErrorPayload`. */ function toPayloadErrors(issues: ValidationIssue[]): Array<{ path: (string | number)[] code: 'INVALID' message: string }> { return issues.map((i) => ({ path: i.path, code: 'INVALID', message: i.message })) } export class MethodNotFoundError extends Error implements KernelErrorClassifiable { constructor(method: string) { super(`Method not found: ${method}`) this.name = 'MethodNotFoundError' } toKernelErrorPayload(): KernelErrorPayload { return { code: KERNEL_ERROR_CODES.METHOD_NOT_FOUND, message: this.message } } } export class SdkValidationError extends Error implements KernelErrorClassifiable { constructor( readonly issues: ValidationIssue[], message?: string, ) { super(message ?? 'Invalid params') this.name = 'SdkValidationError' } toKernelErrorPayload(): KernelErrorPayload { return { code: KERNEL_ERROR_CODES.VALIDATION_ERROR, message: this.message, data: { errors: toPayloadErrors(this.issues) }, } } } /** * Thrown when a handler's return value (or a stream chunk) fails validation * against its `outputSchema`. This is a server/handler fault — the author's * code produced data that violates its own declared contract — so it maps to * `INTERNAL_ERROR` (→ HTTP 500), NOT the `VALIDATION_ERROR` (422) used for * bad caller input. Mirrors the kernel's `ResultValidationError`. */ export class SdkResultValidationError extends Error implements KernelErrorClassifiable { constructor( readonly issues: ValidationIssue[], readonly ref?: string, ) { super(`Function${ref ? ` "${ref}"` : ''} returned an invalid result`) this.name = 'SdkResultValidationError' } toKernelErrorPayload(): KernelErrorPayload { return { code: KERNEL_ERROR_CODES.INTERNAL_ERROR, message: this.message, data: { errors: toPayloadErrors(this.issues) }, } } } /** * Thrown by a `RemoteHandler.authorize` hook to deny a call. * * Wraps any error the hook throws — handlers can throw a plain `Error` and * the dispatcher converts it. Already-typed `AuthorizationDeniedError` * instances are passed through unchanged so callers can attach hints. */ export class AuthorizationDeniedError extends Error implements KernelErrorClassifiable { constructor(message: string, cause?: unknown) { super(message, { cause }) this.name = 'AuthorizationDeniedError' } toKernelErrorPayload(): KernelErrorPayload { return { code: KERNEL_ERROR_CODES.PERMISSION_DENIED, message: this.message } } }