import { Result, ok, err } from '@shared/kernel/fp'; import { problemDetail } from '@shared/infrastructure/api-error'; import { withIdempotencyKey } from '@shared/infrastructure/api-client.provider'; /** * Run an API call and fold it into a `Result` — the one place the try/catch + * ProblemDetails-mapping lives, so every adapter method is just its own payload * mapping. The backend re-validates and returns a 422 ProblemDetails on * rejection, surfaced here as the error string. * * This is the **read** half: it mints no Idempotency-Key. Use it for GETs. * `runSubmit` below wraps it for mutations — never route a read through that * one, it mints a key for nothing. */ export async function runResult( fn: () => Promise, fallback: string, ): Promise> { try { return ok(await fn()); } catch (e) { return err(problemDetail(e, fallback)); } } /** * `runResult` for a **mutating** call: also mints the Idempotency-Key for this * logical submit — once per `runSubmit` call, not per HTTP attempt — so a * retry of this same submit dedupes on the backend (see `withIdempotencyKey`). * Reads must go through `runResult` instead, which mints nothing. */ export function runSubmit(fn: () => Promise, fallback: string): Promise> { return runResult(() => withIdempotencyKey(crypto.randomUUID(), fn), fallback); } // Single shared default for a failed submit; the @@id dedupes it at the // translation layer. export const SUBMIT_FAILED = $localize`:@@submit.failed:Het indienen is niet gelukt. Probeer het later opnieuw.`;