API reference

yatta/binding

The shared reactive contract every framework binding is built on.

11 exported symbols and 8 members, read from src/types/binding.ts.

Construct

bind

function

Binds one call to a store.

`start` is separate because a binding is built during a render, and a render must not do work — that is what makes it safe to render many times, and what stops a Server Component from multiplying requests.

bind<TArgs, T>(store: CallStore, method: (args?: TArgs) => Promise<T>, args: TArgs | undefined, options?: BindOptions): BoundCall<T>
store
Where results live. Per request on a server, shared in a browser.
method
The route's method, taken from the app.
args
Its arguments. Part of the key, so different arguments never share.

callKey

function

The key one call is stored under: its route and its arguments.

callKey<TArgs>(method: unknown, args: TArgs | undefined): string

makeBinding

function

Shares one framework subscription across many subscribers.

Written this way because the alternative — one subscription per component — is a subscription per component on the same store, which is what a framework charges for.

makeBinding(track: (notify: () => void) => void | (() => void)): Binding
track
Starts the framework subscription and returns its teardown.

methodName

function

The route a method came from, used as the key's prefix.

The derived methods are named after their routes, so this is the route name. Two routes cannot collide under one key — which matters, because a key built from arguments alone would let one route serve another's cached value.

methodName(method: unknown): string

sameState

function

Whether two states are indistinguishable to a reader.

Compared field by field, because the store hands out a fresh object on every write: an identity check would report a change on every notification and defeat the whole point of the filter above.

sameState<T>(a: CallState<T>, b: CallState<T>): boolean

serverBinding

function

A binding that never notifies: correct on a server, where nothing updates.

serverBinding(): Binding

stableStringify

function

Serialises arguments so key order does not matter.

`{ id: "1", q: 2 }` and `{ q: 2, id: "1" }` are the same call. Keying them differently makes a component refetch whenever its parent reorders a literal. The non-plain cases are handled explicitly, because `Object.entries` sees them as empty and every one of them silently becomes `"{}"`: - A `Date` has no own enumerable properties, so two *different* dates produced the same key. Every date-range query then shared one cache entry and returned whichever date happened to be cached first. - A `RegExp` and a `Map` or `Set` have the same problem. - A circular structure recursed until the stack overflowed, which took down the render that built the arguments. `undefined` and `{}` are the same call, so an omitted argument does not fork the key.

stableStringify(value: unknown): string

watchCall

function

Subscribes to one call's changes.

The one thing every framework binding does. Returns the current state immediately, so a subscriber never renders one frame against an empty cache. Filtered to the key, and gated on the state actually having changed. Without either, the store's subscribe is global: one mutation anywhere woke every mounted component, each allocated a fresh state object, and each re-rendered. On a page with fifty calls that is fifty renders to change one, and the reason a small change could be felt as a janky one.

watchCall<T>(store: CallStore, key: string, onChange: (state: CallState<T>) => void): () => void

Types

Binding

interface

How a binding is told the store changed.

One operation: register a callback and get back an unsubscribe.

interface Binding

1 member

  • subscribe
    subscribe(notify: () => void): () => void

BindOptions

interface
interface BindOptions

3 members

  • enabledproperty
    enabled?: boolean

    Skip the load without tearing anything down, for an argument that is not

  • keyproperty
    key?: string

    Overrides the derived key. Used by the mutation paths.

  • signalproperty
    signal?: AbortSignal

    Cancels the request.

    Forwarded to `fetch` on the HTTP path, and readable from `ctx.signal` in a direct call. Without it, a component whose arguments change mid-flight cannot abandon the answers nobody is waiting for — the work still runs and still occupies a connection.

BoundCall

interface

A bound call.

Reads through to the store, so `state` is correct whether or not a notification has arrived yet.

interface BoundCall<T>

4 members

  • stateproperty
    state: CallState<T>
  • start
    start(): () => void

    Starts the load. Returns a teardown; does nothing if already started.

  • refetch
    refetch(): void

    Reloads, ignoring any cached value.

  • set
    set(updater: T | ((previous: T | undefined) => T)): void

    Writes a value without a request, for an optimistic update.

Tip
Most of the types above are inferred. You rarely import AuthConfig or JobPayload — declaring your schema once is enough for the rest to follow. See Typed keys.