ui/keyed_async_slot.svelte.ts

Keyed sibling of AsyncSlot β€” fans the per-instance supersession machinery out across an open set of keys.

Each key gets its own lazily-created AsyncSlot, so concurrent run(key_a, ...) and run(key_b, ...) calls are independent: a second run() on key_a aborts only key_a's in-flight call, leaving key_b running. The keyed shape replaces the AsyncSlot + SvelteSet<id> pair that state classes previously carried for per-row in-flight tracking, with two genuine wins:

- Cross-key supersession is correct β€” clicking row B while row A is in flight no longer aborts A; each row has its own AbortController. - Per-key error surfacing β€” error(key) carries the failure for that key only, instead of the last-error-wins shape of a shared slot.

The backing SvelteMap keeps entries even after a run() resolves β€” components can read error(key) to render an inline per-row failure indicator. Call delete(key) to dismiss an entry, or reset() to clear everything (e.g. on page leave).

@example

class AdminInvitesState { readonly remove = new KeyedAsyncSlot<Uuid>(); async submit_delete(id: Uuid): Promise<void> { const ok = await this.remove.run(id, () => this.#rpc().delete({invite_id: id})); if (ok !== undefined) await this.fetch(); } } // In a template: // <button disabled={state.remove.loading(row.id)}> // {state.remove.loading(row.id) ? 'deleting…' : 'delete'} // </button> // {#if state.remove.error(row.id)}<p>{state.remove.error(row.id)}</p>{/if}

Declarations
#

2 declarations

view source

KeyedAsyncSlot
#

ui/keyed_async_slot.svelte.ts view source

Reactive container for many concurrent async operations keyed by K.

generics

K

T

default void

E

default string

constructor

type new <K, T = void, E = string>(options?: KeyedAsyncSlotOptions<T, E>): KeyedAsyncSlot<K, T, E>

options
type KeyedAsyncSlotOptions<T, E>
default {}

has

Reactive β€” true once run(key, ...) has been called and the entry hasn't been deleted.

type (key: K): boolean

key
type K
returns boolean

get

Direct access to the underlying AsyncSlot for key, or undefined if no run() has been issued for it yet. Reactive on map population and on the slot's $state.raw fields.

Prefer the sugar getters ({@link loading}, {@link error}) for templates; reach for get(key) when you need error_data, data, or to call abort() / set() / reset() on the underlying slot.

type (key: K): AsyncSlot<T, E> | undefined

key
type K
returns AsyncSlot<T, E> | undefined

loading

Reactive β€” false for keys that have never been used.

type (key: K): boolean

key
type K
returns boolean

error

Reactive β€” null when the key has no entry or hasn't failed.

type (key: K): E | null

key
type K
returns E | null

failed

Reactive β€” false for keys that have never been used.

type (key: K): boolean

key
type K
returns boolean

succeeded

Reactive β€” false for keys that have never been used.

type (key: K): boolean

key
type K
returns boolean

keys

Reactive iterator over every key with state.

type (): IterableIterator<K>

returns IterableIterator<K>

values

Reactive iterator over every slot.

type (): IterableIterator<AsyncSlot<T, E>>

returns IterableIterator<AsyncSlot<T, E>>

entries

Reactive iterator over [key, slot] pairs.

type (): IterableIterator<[K, AsyncSlot<T, E>]>

returns IterableIterator<[K, AsyncSlot<T, E>]>

run

Run an async operation for key. Lazily creates an AsyncSlot for the key on first use, inheriting the constructor's map_error / preserve_error_on_retry options.

Supersession is scoped to key: a second run(key, ...) aborts the first's signal AND drops its commit. Calls on different keys are fully independent (each has its own AbortController).

type (key: K, fn: (signal: AbortSignal) => Promise<T>, options?: RunOptions | undefined): Promise<T | undefined>

key
type K
fn
type (signal: AbortSignal) => Promise<T>
options?
type RunOptions | undefined
optional
returns Promise<T | undefined>

the resolved value on success; undefined on failure, abort, or supersession.

abort

Abort the in-flight run for key, if any. No-op when the key has no entry. The slot stays in the map at its prior resolved status β€” call {@link delete} to remove the entry entirely.

type (key: K, reason?: unknown): void

key
type K
reason?
type unknown
optional
returns void

abort_all

Abort every in-flight run. Resolved entries stay in the map β€” call {@link reset} to clear them too.

type (reason?: unknown): void

reason?
type unknown
optional
returns void

delete

Abort the in-flight run for key (if any) and remove the entry from the map. After delete(key), has(key) returns false and the sugar getters report the no-entry defaults β€” typically how a UI dismisses a per-row error indicator.

type (key: K): boolean

key
type K
returns boolean

true if the key had an entry.

reset

Abort every in-flight run and clear the map. The keyed slot looks like a fresh instance afterwards.

type (): void

returns void

KeyedAsyncSlotOptions
#

ui/keyed_async_slot.svelte.ts view source

KeyedAsyncSlotOptions<T, E>

Constructor options for KeyedAsyncSlot. Propagated to every child AsyncSlot at lazy creation time.

initial from {@link AsyncSlotOptions} is deliberately omitted β€” keyed slots have no per-key seed concept (the entries don't exist until run() creates them).

generics

T

E

default string

Depends on
#

Imported by
#