BetaBetaRuns thunk and delegates claimable failures to the studio dialog.
With retryable: true, the dialog's "Try again" re-invokes the thunk;
the returned promise resolves with the first successful attempt.
Unclaimable failures reject the returned promise.
The thunk receives the attempt number (starting at 1), useful for logging or cache-busting. It may return a promise or an observable — an observable is drained to its last emitted value (single-shot request observables emit once and complete, so this is their value).
The observable MUST be finite. attempt waits for completion, so a
long-lived or multicast source (client.listen(), a Subject) would
never resolve and would leak its subscription for the life of the
returned promise. An observable that completes without emitting
rejects with rxjs's EmptyError. Pass request-style observables only.
Promises are eager, so the thunk must CREATE the request when called — retry works by invoking it again for a fresh request:
// ✓ each invocation issues a new request
attempt(() => client.fetch(query), {retryable: true})
// ✗ the request already happened; retry re-awaits the same
// settled rejection and the dialog just reappears
const promise = client.fetch(query)
attempt(() => promise, {retryable: true})
Optionaloptions: RequestErrorReportOptionsBetaPromise rejection handler — use directly in .catch(handle).
Claimable errors surface the studio dialog and leave the promise
pending (the request is in limbo until the user reloads);
unclaimable errors are re-thrown to the next .catch:
client
.create(doc)
.catch(handle)
.catch((err) => {
// caller-domain errors (validation, permissions, 404, ...)
})
Call-site API for delegating unrecoverable request errors to the studio's built-in error UI (dialogs, verified forced logout).
The studio never intercepts your requests — errors only reach this channel when you hand them over. Handle what you can locally (inline errors, toasts, fallbacks); delegate what you can't.
Two shapes, both feeding the same dialog:
Unclaimable errors (4xx other than 429, parse errors, ...) are re-thrown unchanged, so downstream
.catch/catchErrorhandlers still see them. 401s are claimed only when the API explicitly tags them as session expiry (SIO-401-AEX), in which case a forced logout follows; untagged resource-level 401s are re-thrown to the caller.