import type * as Ably from 'ably'; import type { LiveMap, PathObject, Value } from 'ably/liveobjects'; import { ChannelNameAndOptions } from '../AblyReactHooks.js'; /** * Options for {@link useObject}. The standard channel-hook options: the channel * is resolved from the nearest `ChannelProvider` unless `channelName` is * provided, `ablyId` selects the client from a surrounding `AblyProvider`, and * `skip` short-circuits the hook. */ export type UseObjectOptions = ChannelNameAndOptions; /** * The surface common to every {@link PathObject} variant that {@link useObject} * relies on. Every node a selector can return satisfies this type. * * The node a selector returns can be any `PathObject` variant, so the hook's * result-side type parameter constrains and infers over this structural type * rather than over `PathObject`: `PathObject` is a conditional type that * TypeScript cannot infer `V` through for an arbitrary `V`, and the resolved * variants are not assignable to a common `PathObject` (two * `LiveMapPathObject`s with different shapes have incompatible `get` * signatures). Constraining and inferring the concrete variant directly is * what lets the selector's navigation chain determine the result type. The * selector's parameter needs no such treatment: it is always a map, and * `PathObject>` reduces eagerly for every `T`, so TypeScript can * infer `T` through it. */ export interface ObjectNode { /** The fully-qualified path string for this node. */ path(): string; /** A plain-data snapshot of the node, or `undefined` if the node does not exist. */ compact(): unknown; /** Registers a listener called on each change to the node or its subtree. */ subscribe(listener: () => void): Ably.Subscription; } /** * The plain-data snapshot type produced by a node's `compact()` method — the * type of {@link UseObjectResult.value} for the node type `N`. */ export type ObjectNodeValue = N extends { compact(): infer C; } ? Exclude : never; /** * Navigates from the channel's object to the node to subscribe to. Receives * the channel's live object as a PathObject and returns a descendant via * `get`/`at`; the chain's types flow through, so the hook result is typed * without manual annotation. The function must only navigate — the node it * returns is the one the hook subscribes to. To subscribe to the channel's * whole object, omit the selector. */ export type ObjectSelector = (object: Obj) => N; /** * Result of {@link useObject} for a subscribed node of type `N`. */ export interface UseObjectResult { /** * Reactive snapshot of the subscribed node (`PathObject.compact()`), cached * so its identity is stable between renders. `undefined` before the object * has synced, or if the node does not exist. */ value: ObjectNodeValue | undefined; /** * The live PathObject for the subscribed node. Use it to navigate (`get`/`at`) * and to write (`set`/`remove`/`increment`/`decrement`/`batch`). `undefined` * until the channel's object has resolved and synced — this is the * readiness signal: `object === undefined && error === null` is loading, * `error !== null` is failed, and a defined `object` is ready (with `value` * carrying the data once the node exists). */ object: N | undefined; /** * The error that prevented the object from resolving — e.g. the `LiveObjects` * plugin is missing, the channel lacks object modes, or the initial sync * failed. ably-js's own `ErrorInfo`, surfaced unmodified. `null` otherwise. */ error: Ably.ErrorInfo | null; /** Connection-level error, per the standard channel-hook convention. */ connectionError: Ably.ErrorInfo | null; /** Channel-level error, per the standard channel-hook convention. */ channelError: Ably.ErrorInfo | null; } /** * Subscribe to the channel's object and re-render on change. * * The channel is taken from the nearest `ChannelProvider` unless `channelName` * is given. `T` describes the shape of the channel's object — the same type * parameter `RealtimeObject.get()` takes — and defaults to an untyped map. * * Requires the `LiveObjects` plugin on the Realtime client and the * `OBJECT_SUBSCRIBE` channel mode (plus `OBJECT_PUBLISH` to write); otherwise * `error` carries ably-js's reason. Readiness is derived from the result (see * {@link UseObjectResult.object}), not a status enum. */ export declare function useObject = Record>(options?: UseObjectOptions): UseObjectResult>>; /** * Subscribe to a nested LiveObjects node, selected by navigating from the * channel's (untyped) object, and re-render on change. The node the selector * returns determines `N`, so `value` and `object` are typed from the * navigation chain, e.g. `useObject((obj) => obj.get('scores').get('alice'))`. * * Channel resolution, readiness, and plugin/modes requirements are as for the * no-selector overload. */ export declare function useObject(selector: ObjectSelector>>, N>, options?: UseObjectOptions): UseObjectResult; /** * Subscribe to a nested LiveObjects node, selected by navigating from the * channel's object with a typed shape, and re-render on change. Annotate the * selector's parameter with the shape of the channel's object * (`(obj: PathObject>) => ...`) — `T` is inferred from the * annotation, and is the same type parameter `RealtimeObject.get()` takes — * and the whole navigation chain, wrong keys included, is checked at compile * time. * * Channel resolution, readiness, and plugin/modes requirements are as for the * no-selector overload. */ export declare function useObject, N extends ObjectNode>(selector: ObjectSelector>, N>, options?: UseObjectOptions): UseObjectResult;