1import * as Data from "effect/Data";
2import { UserFacingError } from "../UserFacingError.ts";
3
4/** A non-fatal note attached to a successful result. */
5export 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. */
17export 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. */
27export 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}