decentrl.
API Reference

@decentrl/sdk-react

React hooks and providers for building Decentrl-powered UIs with useSyncExternalStore.

npm install @decentrl/sdk-react

Peer dependency: React 18+ or 19+.

Provider

DecentrlProvider

Wraps your app with a DecentrlClient instance.

import { DecentrlProvider } from '@decentrl/sdk-react'

<DecentrlProvider client={client}>
  <App />
</DecentrlProvider>

useDecentrlClient()

Access the raw client from context. Throws if used outside DecentrlProvider.

function useDecentrlClient<TEvents, TState>(): DecentrlClient<TEvents, TState>

Core Hooks

useDecentrl()

Returns the publish method and client instance.

function useDecentrl<TEvents, TState>(): {
  publish: DecentrlClient<TEvents, TState>['publish']
  client: DecentrlClient<TEvents, TState>
}
const { publish } = useDecentrl()

await publish('message', { text: 'hello', threadId: crypto.randomUUID() })

useDecentrlState(selector?)

Subscribes to client state with optional selector. Uses useSyncExternalStore for tear-free reads.

function useDecentrlState<TSelected>(
  selector?: (state: InferState<TState>) => TSelected,
): TSelected
const messages = useDecentrlState(s => s.messages)
const count = useDecentrlState(s => s.messages.length)

useDecentrlIdentity()

Manages identity state and operations.

function useDecentrlIdentity(): {
  identity: IdentityState | null
  isInitialized: boolean
  create: (opts: { alias: string; mediatorDid: string }) => Promise<IdentityState>
  load: (serialized: SerializedIdentity) => IdentityState
  serialize: () => SerializedIdentity
  reset: () => void
  contracts: ContractManager
}

useConnectionStatus()

function useConnectionStatus(): ConnectionStatus
// 'disconnected' | 'connecting' | 'authenticating' | 'connected'

useAutoSync(options?)

Starts automatic background sync. Cleans up on unmount.

function useAutoSync(options?: {
  intervalMs?: number         // default: 3000
  enabled?: boolean           // default: true
  onError?: (error: unknown) => void
  websocket?: boolean
  fallbackIntervalMs?: number
}): void

Event Hooks

useEventStream(callback, options?)

Subscribes to real-time events with optional type/tag filtering.

function useEventStream(
  callback: (envelope: EventEnvelope) => void,
  options?: { types?: string[]; tags?: string[] },
): void
useEventStream(
  (event) => console.log('New message:', event.data),
  { types: ['chat.message'] },
)

useEventQuery(options)

Queries historical events with pagination and state selection.

function useEventQuery<TSelected>(options: {
  tags?: string[]
  select: (state: InferState<TState>) => TSelected
  pageSize?: number                    // default: 20
  queryOptions?: Omit<QueryOptions, 'tags' | 'pagination'>
}): {
  data: TSelected
  isLoading: boolean
  error: Error | null
  hasMore: boolean
  fetchMore: () => void
}

Contract Hooks

useActiveContracts()

function useActiveContracts(): {
  contracts: StoredSignedContract[]
  refresh: () => void
  refreshAsync: () => Promise<void>
  isRefreshing: boolean
  isError: boolean
  error: Error | null
}

usePendingContracts(options?)

function usePendingContracts(
  options?: { enabled?: boolean },
): {
  data: PendingContractRequest[] | undefined
  isPending: boolean
  isError: boolean
  error: Error | null
  refetch: () => void
}

useContractByDid(did)

function useContractByDid(did: string): StoredSignedContract | undefined

Mutation Hooks

useCreateIdentity(options?)

function useCreateIdentity(options?): {
  mutate: (vars: { alias: string; mediatorDid: string }) => void
  mutateAsync: (vars) => Promise<IdentityState>
  isPending: boolean
  isSuccess: boolean
  isError: boolean
  error: Error | null
}

useRequestContract(options?)

function useRequestContract(options?): {
  mutate: (vars: { recipientDid: string; expiresIn?: number }) => void
  mutateAsync: (vars) => Promise<void>
  isPending: boolean
  // ...
}

useAcceptContract(options?)

function useAcceptContract(options?): {
  mutate: (vars: {
    pendingId: string
    encryptedPayload: string
    requestorEphemeralPublicKey: string
  }) => void
  mutateAsync: (vars) => Promise<void>
  isPending: boolean
  // ...
}

useSync(options?)

Manually trigger a sync.

function useSync(options?): {
  mutate: () => void
  mutateAsync: () => Promise<void>
  isPending: boolean
  // ...
}

Generic Primitives

These power all the hooks above and can be used for custom async operations:

useDecentrlQuery(queryFn, options?)

function useDecentrlQuery<TData, TError>(
  queryFn: () => Promise<TData>,
  options?: { enabled?: boolean },
): {
  data: TData | undefined
  isPending: boolean
  isFetching: boolean
  isSuccess: boolean
  isError: boolean
  error: TError | null
  refetch: () => void
}

useDecentrlMutation(mutationFn, options?)

function useDecentrlMutation<TVariables, TData, TError>(
  mutationFn: (variables: TVariables) => Promise<TData>,
  options?: {
    onSuccess?: (data: TData, variables: TVariables) => void
    onError?: (error: TError, variables: TVariables) => void
    onSettled?: (data: TData | undefined, error: TError | null, variables: TVariables) => void
  },
): {
  mutate: (variables: TVariables) => void
  mutateAsync: (variables: TVariables) => Promise<TData>
  isPending: boolean
  isSuccess: boolean
  isError: boolean
  isIdle: boolean
  data: TData | undefined
  error: TError | null
  reset: () => void
}