/** * Result — a lightweight, framework-agnostic result type used across * `@elly/shared`, `@elly/core`, and `@elly/bot`. * * Prefer this over throwing for expected/recoverable failures crossing * module or IPC boundaries. Reserve exceptions for genuinely exceptional * conditions (programmer error, invariant violation, infrastructure failure). */ export type Ok = { readonly ok: true; readonly value: T }; export type Err = { readonly ok: false; readonly error: E }; export type Result = Ok | Err; export function ok(value: T): Ok { return { ok: true, value }; } export function err(error: E): Err { return { ok: false, error }; } export function isOk(result: Result): result is Ok { return result.ok; } export function isErr(result: Result): result is Err { return !result.ok; } /** * Unwrap a Result or throw the error. Use sparingly — defeats the purpose of * Result in most call sites. */ export function unwrap(result: Result): T { if (result.ok) return result.value; throw result.error instanceof Error ? result.error : new Error(`Result.unwrap on Err: ${String(result.error)}`); } /** * Map the success value of a Result without affecting the error branch. */ export function map(result: Result, fn: (value: T) => U): Result { return result.ok ? ok(fn(result.value)) : result; } /** * Map the error value of a Result without affecting the success branch. */ export function mapErr(result: Result, fn: (error: E) => F): Result { return result.ok ? result : err(fn(result.error)); } /** * Wrap a throwing synchronous function in a Result. */ export function tryCatch(fn: () => T): Result { try { return ok(fn()); } catch (e) { return err(e instanceof Error ? e : new Error(String(e))); } } /** * Wrap a throwing async function in a Result. */ export async function tryCatchAsync(fn: () => Promise): Promise> { try { return ok(await fn()); } catch (e) { return err(e instanceof Error ? e : new Error(String(e))); } }