Migrate to the one React binding
The React surface moved: Register and every data hook now live in @super-line/react, plugin-auth/react shrank to the session owner (SuperLineAuthProvider + useAuth), plugin-chat gained a registered module-level binding with an auto-building ChatProvider, and useRequest became the one TanStack-style request hook. The migration is mechanical; this page is the whole of it.
1 · Move the Register declaration
Same body, new module:
-declare module '@super-line/plugin-auth/react' {
+declare module '@super-line/react' {
interface Register {
contract: typeof app
role: 'user'
}
}2 · Move the data-hook imports
useAuth and SuperLineAuthProvider stay where they are; everything else comes from @super-line/react:
-import { useCollection, useDoc, useEvent, useSubscription, useRequest, useEnv, useClient } from '@super-line/plugin-auth/react'
+import { useCollection, useDoc, useEvent, useSubscription, useRequest, useEnv, useMaybeClient } from '@super-line/react'
import { SuperLineAuthProvider, useAuth } from '@super-line/plugin-auth/react'useClient changed meaning
plugin-auth's old useClient was the null-returning accessor. In @super-line/react, useClient() throws while there is no client — the null-returning one is useMaybeClient(). Rename old useClient call sites to useMaybeClient.
3 · useRequest: isLoading → loading, and inputs auto-fetch
-const { call: join, isLoading } = useRequest('join')
-useEffect(() => { join({ room }).then(seed).catch(() => {}) }, [join, room])
+const { data: joined, loading } = useRequest('join', { room }) // auto-fetches; refetches when room changesExisting one-argument call sites keep their manual behavior — nothing auto-fires without an input argument. A no-input request opts into auto-fetching with an explicit undefined input; { enabled: false } holds fire. refetch() re-runs with the hook's input.
4 · Chat apps: delete the chatClient bridge
-const chat = useMemo(() => chatClient(client, { userId: me }), [client, me])
-useEffect(() => () => chat.close(), [chat])
-return <ChatProvider chat={chat}>…</ChatProvider>
+return <ChatProvider>…</ChatProvider>Import the chat hooks module-level from @super-line/plugin-chat/react instead of a local createChatHooks file. The module-level useChat() returns ChatClient | null (the factory's throwing form is unchanged) — panes that only mount inside the authed subtree can keep a four-line throwing wrapper if they prefer the old ergonomics.
5 · What you get for it
useDoctakes lazy ids (string | null | resolver) and exposesready,error, andhandle— a denied or absent open is finally visible, and editors sequence onreadyinstead of guessing fromnative.useCollectionexposesready,batch,handle, andsub, and takesquery: nullas the explicit idle state.- One-shot reads:
client.collection(name).query(q)resolves the ordered, limited snapshot and leaves no subscription behind. useLiveQuery(make, deps)is the exported low-levelLiveRowSet→ React glue you used to hand-write.useSuperLineClient(make, deps?)owns a client StrictMode-safely — and StrictMode is now supported across the whole binding, providers included.
The factory (createSuperLineHooks, createChatHooks) survives unchanged for multi-contract apps and tests.