Skip to content

Documentation / @super-line/react / createSuperLineHooks

Function: createSuperLineHooks() ​

createSuperLineHooks<C, R>(): object

Defined in: index.ts:173

Bind typed React hooks to a contract + role. Create the client once, wrap your tree in the returned <Provider>, then use the hooks inside.

Type Parameters ​

C ​

C extends Contract

R ​

R extends string

Returns ​

Provider ​

Provider: (props) => ReactNode

Provides a client to the hooks below. null is legal and means "not connected yet" — the hooks go idle rather than throwing, which is what lets an auth-owned binding render a login screen above them.

Parameters ​

props ​
children? ​

ReactNode

client ​

SuperLineClient<C, R> | null

Returns ​

ReactNode

useClient ​

useClient: () => SuperLineClient<C, R>

Access the client from context (throws outside a <Provider>, or while it holds no client).

Returns ​

SuperLineClient<C, R>

useCollection ​

useCollection: <N>(name, query?) => object

Subscribe to a collection subset and track its rows reactively (typed by the contract). Returns the live, ordered + limited rows, the ready/error status of the subscription (so "still loading" and "genuinely empty" are distinguishable, and a denied subscribe is visible), the insert/update/delete/batch mutations, and the underlying handle/sub for anything the wrapped surface doesn't cover. query: null is the explicit idle state (no subscription, no live surface) — distinct from undefined, which subscribes to the whole collection. For joins and complex live queries, use TanStack DB via @super-line/tanstack-db instead — this hook is the thin, single-collection filtered-list surface. Re-subscribes when name or query changes.

Type Parameters ​

N ​

N extends string

Parameters ​

name ​

N

query? ​

CollectionQuery | null

Returns ​

batch ​

batch: (ops) => Promise<void>

Apply several ops as ONE atomic batch (all-or-nothing on the server).

Parameters ​
ops ​

({ row: RowOf<C, N>; type: "insert" | "update"; } | { id: string; type: "delete"; })[]

Returns ​

Promise<void>

delete ​

delete: (id) => Promise<void>

Parameters ​
id ​

string

Returns ​

Promise<void>

error? ​

optional error?: unknown

handle ​

handle: CollectionHandle<RowOf<C, N>> | undefined

The underlying CollectionHandle (undefined while idle). A window, not ownership.

insert ​

insert: (row) => Promise<void>

Parameters ​
row ​

RowOf<C, N>

Returns ​

Promise<void>

ready ​

ready: boolean

True once the initial snapshot has been applied. False while idle.

rows ​

rows: RowOf<C, N>[]

sub ​

sub: LiveRowSet<RowOf<C, N>> | undefined

The underlying LiveRowSet (undefined while idle). A window, not ownership — the hook closes it.

update ​

update: (row) => Promise<void>

Parameters ​
row ​

RowOf<C, N>

Returns ​

Promise<void>

useDoc ​

useDoc: <N>(name, id, deps?) => object

Open a CRDT document collection (ADR-0007) and track it reactively. The id may be:

  • a string — open that document;
  • null/undefined — the idle state (nothing opens; reads are empty, writes throw);
  • a resolver () => id | Promise<id> — for ids that arrive asynchronously (a registry lookup, a request). It re-runs when deps change (like an effect); an inline arrow is safe. Resolving null/undefined idles; throwing lands on error.

ready is the sequencing signal editors need: it flips true only after the catch-up snapshot has applied, so binding to native before ready is the bug this field exists to prevent. A denied or absent open surfaces on error (it used to be invisible). The handle is closed on unmount.

Type Parameters ​

N ​

N extends string

Parameters ​

name ​

N

id ​

string | (() => string | Promise<string | null | undefined> | null | undefined) | null | undefined

deps? ​

readonly unknown[]

Returns ​

data ​

data: DocOf<C, N> | undefined

delete ​

delete: (path) => void

Parameters ​
path ​

(string | number)[]

Returns ​

void

deleted ​

deleted: boolean

error ​

error: unknown

Open denial / absent doc / resolver failure. Cleared when a new open starts.

handle ​

handle: DocHandle<DocOf<C, N>> | undefined

The reactive DocHandle (undefined while idle/resolving). A window, not ownership — the hook closes it.

native ​

native: unknown

The engine's native document handle, or undefined before the doc is open. A value, not a getter, so it can be a dependency: it keeps its identity across merges and changes only when the underlying document is replaced, which is exactly when anything bound to it (a rich-text editor) must be rebuilt. Narrow it with the engine package's accessor — yDocOf for Yjs. Sequence the binding on ready, not on presence.

ready ​

ready: boolean

True once the catch-up snapshot has applied. False while idle, resolving, or loading.

set ​

set: (value) => void

Parameters ​
value ​

DocOf<C, N>

Returns ​

void

update ​

update: (partial) => void

Parameters ​
partial ​

Partial<DocOf<C, N>>

Returns ​

void

useEnv ​

useEnv: () => EnvOf<C, R> | null

The connection's server-vended, client-visible SuperLineClient.env (ADR-0012), tracked reactively: null until the first push (or for a role with no env), then the latest value, re-rendering on every update. Code-only — wire the creds into effects/calls; never render a raw secret.

Returns ​

EnvOf<C, R> | null

useEvent ​

useEvent: <E>(event, handler) => void

Subscribe to a server-pushed event for the component's lifetime. Idle (never bound) with no client.

Type Parameters ​

E ​

E extends string | number | symbol

Parameters ​

event ​

E

handler ​

(data) => void

Returns ​

void

useMaybeClient ​

useMaybeClient: () => SuperLineClient<C, R> | null

The client, or null — what every hook below reads, so a client-less provider idles instead of throwing.

Returns ​

SuperLineClient<C, R> | null

useRequest ​

useRequest: <M>(method, ...rest) => RequestState<Output<Requests<C, R>[M]>> & object

The one request hook, TanStack-style. With an input argument it AUTO-FETCHES — on mount, when the input changes (JSON-stable compare), and when the client swaps (new session ⇒ refresh) — unless enabled: false. WITHOUT an input argument nothing ever auto-fires: that is the manual/mutation mode, driven entirely through call(input). The arity is the mode switch, so a no-input request opts into auto-fetching by passing an explicit undefined input.

Type Parameters ​

M ​

M extends string | number | symbol

Parameters ​

method ​

M

rest ​

[] | [ClientInput<Requests<C, R>[M]>, object]

Returns ​

useSubscription ​

useSubscription: <T>(topic) => EventData<TopicsOf<ServerMessages<C, R>>[T]> | undefined

Subscribe to a topic and return its latest value (or undefined before the first message / with no client).

Type Parameters ​

T ​

T extends string | number | symbol

Parameters ​

topic ​

T

Returns ​

EventData<TopicsOf<ServerMessages<C, R>>[T]> | undefined

Example ​

tsx
const { Provider, useRequest, useEvent, useSubscription } = createSuperLineHooks<typeof api, 'user'>()

function Root() {
  const [client] = useState(() => createSuperLineClient(api, { url, role: 'user' }))
  return <Provider client={client}><Room /></Provider>
}

Released under the MIT License.