/**
 * Composable async-operation slot for Svelte 5 reactive state classes.
 *
 * A state class HOLDS one or more `AsyncSlot`s via composition — one slot
 * per distinct async operation (e.g. `list` + `create` + `revoke`). Each
 * slot tracks the status, payload, and error of its operation
 * independently, so state classes with multiple write paths don't accumulate
 * ad-hoc `creating` / `updating` fields beside a single shared
 * `loading` / `error` pair.
 *
 * Core surface:
 *
 * - **Explicit four-value `status`** — `AsyncStatus` from
 *   `@fuzdev/fuz_util/async.js`: `'initial' | 'pending' | 'success' |
 *   'failure'`. `loading: false, error: null` would be ambiguous
 *   between "never tried" and "succeeded once and now resting"; the
 *   four-value status removes the need for a per-class `submitted` /
 *   `hydrated` flag.
 * - **Owns `data: T | undefined`** — the success payload persists
 *   across retries (stale-while-revalidate). The sentinel is
 *   `undefined` (not `null`) so `null` stays available as a legitimate
 *   success value for nullable `T`s. Pass `T = void` for write-only
 *   actions whose response isn't worth keeping.
 * - **Supersession via internal `AbortController`** — a second `run()`
 *   aborts the first, and superseded results are silently discarded
 *   without writing to state. Removes the "in-flight call resolves
 *   after the locator advanced" race that locator-style state classes
 *   would otherwise need to compensate for.
 * - **`AbortSignal` threaded to the callback** — RPC clients that accept
 *   a signal (or `fetch`) get cancellation for free; callers can also
 *   pass an external `signal` via {@link RunOptions} to bind the slot's
 *   lifetime to a component / page.
 * - **`preserve_error_on_retry`** — opt-in to keeping the previous error
 *   visible while a retry is pending (default clears at the start of
 *   each `run()`).
 * - **Per-slot `map_error`** — set once in the constructor
 *   (`{map_error: to_rpc_error_message}`); every `run()` gets the right
 *   normalization without re-passing per call.
 * - **Public `run()`** — slots are composed, not subclassed, so call
 *   sites can invoke `state.list.run(...)` directly.
 *
 * @example
 * ```ts
 * class CellsState {
 *   readonly list = new AsyncSlot<{cells: ReadonlyArray<CellJson>}>();
 *   readonly create = new AsyncSlot<{cell: CellJson}>({map_error: to_rpc_error_message});
 *
 *   async fetch() {
 *     await this.list.run((signal) => this.#api.cell_list({}, {signal}));
 *   }
 *
 *   async submit_new(input: CellCreateInput) {
 *     const result = await this.create.run(() => this.#api.cell_create(input));
 *     if (result) await this.fetch();
 *   }
 * }
 * ```
 *
 * @module
 */
import type { AsyncStatus } from '@fuzdev/fuz_util/async.js';
export interface AsyncSlotOptions<T, E = string> {
    /**
     * Seed `data` and put the slot in `'success'` before any `run()`. Useful
     * when the page already has the resource in hand (SSR hydration, a
     * mutation response, hand-off from a parent slot).
     */
    initial?: T;
    /**
     * Convert a caught throw into the error value stored in
     * {@link AsyncSlot.error}. Default extracts `Error.message` (falling
     * back to `'Request failed'` for non-Error throws). Pass
     * `to_rpc_error_message` to unwrap JSON-RPC `data.reason` codes.
     */
    map_error?: (e: unknown) => E;
    /**
     * When `true`, the previous `error` / `error_data` survive the start
     * of a new `run()` until the next success (or another failure
     * overwrites them). Useful for retry UX that wants to keep the
     * failure message visible alongside an inline spinner. Default `false`
     * — `run()` clears the error at the start so the pending state reads
     * "no current error."
     */
    preserve_error_on_retry?: boolean;
}
export interface RunOptions {
    /**
     * External signal chained into the slot's internal controller. Aborts
     * the in-flight run when fired (alongside automatic supersession by
     * the next `run()` and manual {@link AsyncSlot.abort} calls).
     */
    signal?: AbortSignal;
}
/**
 * Reactive container for a single async operation.
 *
 * @typeParam T - The success payload type. Use `void` for write-only
 *   actions whose response isn't worth retaining.
 * @typeParam E - The shape of {@link AsyncSlot.error}. Defaults to
 *   `string` (set by the default `map_error`). Narrow to a structured
 *   type by providing a `map_error` that returns it.
 */
export declare class AsyncSlot<T = void, E = string> {
    #private;
    status: AsyncStatus;
    data: T | undefined;
    error: E | null;
    /** The raw caught value from the last failed `run()`, for programmatic inspection. */
    error_data: unknown;
    /** Convenience derived: `status === 'initial'`. */
    readonly initial: boolean;
    /** Convenience derived: `status === 'pending'`. */
    readonly loading: boolean;
    /** Convenience derived: `status === 'success'`. */
    readonly succeeded: boolean;
    /** Convenience derived: `status === 'failure'`. */
    readonly failed: boolean;
    constructor(options?: AsyncSlotOptions<T, E>);
    /**
     * Run an async operation. The callback receives an `AbortSignal` it
     * can forward to fetch / RPC clients that support cancellation; the
     * slot also discards superseded results internally even if the
     * callback ignores the signal.
     *
     * Supersession rule: a second `run()` aborts the first's signal AND
     * silently drops its commit if it resolves anyway. So
     * back-to-back-to-back `run()` calls leave only the last call's
     * result in `data`.
     *
     * Abort rule: a `run()` that throws because of its own signal (manual
     * `abort()`, external `options.signal`, OR supersession by another
     * `run()`) does NOT promote to `'failure'`. Manual / external aborts
     * revert status to the previous resolved state (`'initial'` if no
     * `run()` has ever succeeded, `'success'` otherwise). Supersession is
     * handled by the bail-on-mismatch check, leaving the second run's
     * `'pending'` standing.
     *
     * @returns the resolved value on success; `undefined` on failure,
     *   abort, or supersession
     */
    run(fn: (signal: AbortSignal) => Promise<T>, options?: RunOptions): Promise<T | undefined>;
    /**
     * Manually abort the in-flight run, if any. Reverts `status`
     * synchronously to the prior resolved state — `'initial'` if no
     * `run()` (or `set()`) has ever succeeded on this slot, `'success'`
     * otherwise. The aborted run's eventual resolution / rejection is
     * dropped without writing to state (the run's `Promise` resolves to
     * `undefined`).
     */
    abort(reason?: unknown): void;
    /**
     * Replace `data` directly and mark the slot `'success'`. For
     * post-mutation hydration where the calling RPC already returned the
     * canonical row (parallels `CellState.set_cell`).
     *
     * Aborts any in-flight `run()` first — without this, the in-flight
     * callback could resolve after `set()` and overwrite the explicit
     * value (the bail-on-mismatch check only fires when `#controller`
     * was rotated).
     *
     * @mutates `this`
     */
    set(data: T): void;
    /**
     * Reset to `'initial'`, clear `data` / `error` / `error_data`, and
     * abort any in-flight run. After `reset()` the slot looks like a
     * fresh instance with no `initial` option.
     *
     * @mutates `this`
     */
    reset(): void;
}
//# sourceMappingURL=async_slot.svelte.d.ts.map