| 1 | import * as Data from "effect/Data"; |
| 2 | import { UserFacingError } from "../UserFacingError.ts"; |
| 3 | |
| 4 | /** A non-fatal note attached to a successful result. */ |
| 5 | export interface Diagnostic { |
| 6 | readonly severity: "debug" | "info" | "warning" | "error"; |
| 7 | readonly code: string; |
| 8 | readonly message: string; |
| 9 | } |
| 10 | |
| 11 | // Tag names are prefixed because the bare ones are already taken by the |
| 12 | // clouds we talk to — distilled's core ships `NotFound`, Route53 ships |
| 13 | // `InvalidInput` — and these errors travel in unions with cloud errors, |
| 14 | // where `catchTag` discriminates by tag alone. |
| 15 | |
| 16 | /** The caller sent something the route cannot act on. */ |
| 17 | export class AlchemistInvalidInput extends Data.TaggedError( |
| 18 | "AlchemistInvalidInput", |
| 19 | )<{ |
| 20 | readonly message: string; |
| 21 | readonly field?: string; |
| 22 | }> { |
| 23 | readonly [UserFacingError] = true; |
| 24 | } |
| 25 | |
| 26 | /** A named entity (profile, provider) does not resolve. */ |
| 27 | export class AlchemistNotFound extends Data.TaggedError("AlchemistNotFound")<{ |
| 28 | readonly kind: string; |
| 29 | readonly id: string; |
| 30 | }> { |
| 31 | readonly [UserFacingError] = true; |
| 32 | /** Human-readable line derived from the missing entity's kind and id. */ |
| 33 | override get message(): string { |
| 34 | return `No ${this.kind} named '${this.id}'.`; |
| 35 | } |
| 36 | } |