@poolse/react 2.25.0 → 2.26.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +52 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +20 -3
- package/dist/index.d.ts +20 -3
- package/dist/index.js +52 -1
- package/dist/index.js.map +1 -1
- package/package.json +10 -10
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/provider.tsx","../src/use-me.ts","../src/use-conversation.ts","../src/use-conversations.ts","../src/use-members.ts","../src/use-messages.ts","../src/use-reactions.ts","../src/use-thread.ts","../src/use-typing.ts","../src/use-presence.ts","../src/use-realtime-status.ts","../src/use-attachment-upload.ts","../src/use-attachment-url.ts","../src/use-user.ts","../src/grouping.ts","../src/use-call-room.ts","../src/internal/alone-watch.ts","../src/use-voice-room.ts","../src/use-calls.ts"],"names":["useEffect","useState","useCallback","useMemo","useRef","PAGE_SIZE","upsertById","safeUuid","userId","call","media"],"mappings":"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","file":"index.js","sourcesContent":["import { Poolse, type PoolseConfig } from '@poolse/sdk';\nimport { createContext, useContext, useEffect, useMemo, useRef, type ReactNode } from 'react';\n\ninterface PoolseContextValue {\n chat: Poolse;\n}\n\nconst PoolseContext = createContext<PoolseContextValue | null>(null);\n\nexport interface PoolseProviderProps {\n /**\n * SDK configuration. The provider builds the `Poolse` instance ONCE\n * per mount and reads `getToken` (and the other function-typed\n * options) from a ref on each call, so it's safe to pass a fresh\n * callback or a fresh object literal on every render.\n *\n * Re-mount the provider (give it a new `key`) when you genuinely\n * want a fresh client — typically after a sign-out, a tenant swap,\n * or an `apiUrl` change. Mutating `apiUrl` / `wsUrl` / `socketPath`\n * after mount is a no-op (the values are captured at construction\n * time); dev mode logs a warning when this happens.\n */\n config: PoolseConfig;\n children: ReactNode;\n}\n\n/**\n * Top-level provider. Wrap your tree once with this; every hook in\n * `@poolse/react` reads from the context.\n *\n * ```tsx\n * <PoolseProvider config={{apiUrl, getToken}}>\n * <App />\n * </PoolseProvider>\n * ```\n *\n * The `Poolse` instance is destroyed on unmount — closes the WebSocket\n * and drops every joined channel.\n */\nexport function PoolseProvider({ config, children }: PoolseProviderProps) {\n // Hold the latest config in a ref so the SDK reads current callbacks\n // without us rebuilding the client. Without this, the standard call\n // site `<Provider config={{apiUrl, getToken}}>` re-creates `Poolse`\n // on every parent render — closing the socket mid-flight and\n // re-firing every REST call. Refs let us keep ONE SDK instance per\n // mount while still honoring a freshly-bound `getToken` closed over\n // new auth state.\n const configRef = useRef(config);\n configRef.current = config;\n\n // Captured at mount for the dev-mode change warning below.\n const initialConnectionRef = useRef<{\n apiUrl: string | undefined;\n wsUrl: string | undefined;\n socketPath: string | undefined;\n } | null>(null);\n\n const chat = useMemo(() => {\n const initial = configRef.current;\n initialConnectionRef.current = {\n apiUrl: initial.apiUrl,\n wsUrl: initial.wsUrl,\n socketPath: initial.socketPath,\n };\n return new Poolse({\n // apiUrl is optional in PoolseConfig — only forward when set\n // so the SDK can fall back to its hosted-endpoint default.\n ...(initial.apiUrl !== undefined ? { apiUrl: initial.apiUrl } : {}),\n // Always read the latest callbacks from the ref — they're free\n // to change between renders.\n getToken: () => configRef.current.getToken(),\n ...(initial.fetch\n ? { fetch: ((...args) => configRef.current.fetch!(...args)) as typeof globalThis.fetch }\n : {}),\n ...(initial.maxRetries !== undefined ? { maxRetries: initial.maxRetries } : {}),\n ...(initial.baseBackoffMs !== undefined ? { baseBackoffMs: initial.baseBackoffMs } : {}),\n ...(initial.maxBackoffMs !== undefined ? { maxBackoffMs: initial.maxBackoffMs } : {}),\n ...(initial.generateIdempotencyKey\n ? { generateIdempotencyKey: () => configRef.current.generateIdempotencyKey!() }\n : {}),\n ...(initial.wsUrl !== undefined ? { wsUrl: initial.wsUrl } : {}),\n ...(initial.socketPath !== undefined ? { socketPath: initial.socketPath } : {}),\n ...(initial.onSocketError\n ? { onSocketError: (err) => configRef.current.onSocketError!(err) }\n : {}),\n // Customer's user metadata resolver — name + avatar lookup.\n // Read through the ref so the customer can swap the closure\n // (e.g. switch tenant context) without re-mounting.\n ...(initial.userResolver\n ? { userResolver: (id: string) => configRef.current.userResolver!(id) }\n : {}),\n });\n // Mount-once: the `Poolse` instance owns a WebSocket and channel\n // subscriptions, so it MUST be stable for the life of the mount.\n // Changing `apiUrl` / `wsUrl` / `socketPath` requires a remount.\n }, []);\n\n // Surface mistakes early in dev: connection-shaped fields are\n // captured at construction time, so changing them after mount has\n // no effect (callbacks like `getToken` ARE re-read from the ref).\n if (process.env.NODE_ENV !== 'production') {\n // eslint-disable-next-line react-hooks/rules-of-hooks\n useEffect(() => {\n const initial = initialConnectionRef.current;\n if (!initial) return;\n if (\n initial.apiUrl !== config.apiUrl ||\n initial.wsUrl !== config.wsUrl ||\n initial.socketPath !== config.socketPath\n ) {\n console.warn(\n '[poolse] connection-shaped config (apiUrl / wsUrl / socketPath) ' +\n 'changed after <PoolseProvider> mounted. These are captured at ' +\n 'construction time — remount the provider with a new `key` to ' +\n 'switch environments.',\n );\n }\n }, [config.apiUrl, config.wsUrl, config.socketPath]);\n }\n\n useEffect(() => {\n return () => {\n chat.destroy();\n };\n }, [chat]);\n\n const value = useMemo(() => ({ chat }), [chat]);\n\n return <PoolseContext.Provider value={value}>{children}</PoolseContext.Provider>;\n}\n\n/**\n * Access the underlying `Poolse` instance. Most app code should prefer\n * higher-level hooks (`useMessages`, `useTyping`, etc.) but the raw\n * client is here for escape-hatch usage (custom REST calls, direct\n * realtime control).\n */\nexport function usePoolse(): Poolse {\n const value = useContext(PoolseContext);\n\n if (!value) {\n throw new Error(\n 'usePoolse(): no <PoolseProvider> in the tree. Wrap your component ' +\n 'with `<PoolseProvider config={{apiUrl, getToken}}>` first.',\n );\n }\n\n return value.chat;\n}\n","import type { Me } from '@poolse/sdk';\nimport { useEffect, useState } from 'react';\nimport { usePoolse } from './provider.js';\n\ninterface UseMeState {\n me: Me | null;\n loading: boolean;\n error: Error | null;\n}\n\n/**\n * The currently-signed-in End User (`/v1/me`). Fetches once on mount\n * and never re-fetches automatically — user identity is stable for\n * the JWT's lifetime.\n *\n * Most apps won't need this; the JWT subject is enough. Useful when\n * the UI needs the display name / external_id without re-asking the\n * Customer's backend.\n */\nexport function useMe(): UseMeState {\n const chat = usePoolse();\n const [state, setState] = useState<UseMeState>({\n me: null,\n loading: true,\n error: null,\n });\n\n useEffect(() => {\n let cancelled = false;\n const controller = new AbortController();\n\n chat.me\n .show(controller.signal)\n .then((me) => {\n if (!cancelled) setState({ me, loading: false, error: null });\n })\n .catch((err: unknown) => {\n if (!cancelled) {\n setState({\n me: null,\n loading: false,\n error: err instanceof Error ? err : new Error(String(err)),\n });\n }\n });\n\n return () => {\n cancelled = true;\n controller.abort();\n };\n }, [chat]);\n\n return state;\n}\n","import type { Conversation, Uuid } from '@poolse/sdk';\nimport { useCallback, useEffect, useState } from 'react';\nimport { usePoolse } from './provider.js';\n\ninterface UseConversationState {\n /** The fetched conversation, or `null` while loading or on error. */\n conversation: Conversation | null;\n loading: boolean;\n error: Error | null;\n /** Re-run the GET. Use after a `chat.conversations.one(id).update(...)` to refresh state. */\n refetch: () => Promise<void>;\n}\n\n/**\n * Fetch a single conversation by id. Re-fetches when `id` changes\n * (e.g. routing to a different conversation in the same component).\n *\n * Doesn't subscribe to realtime updates yet — the backend doesn't\n * broadcast `conversation:updated` to user channels. Use `refetch()`\n * after a mutation if you need fresh state in the same render cycle.\n *\n * ```ts\n * const { conversation, loading } = useConversation(convId);\n * if (loading) return <Spinner />;\n * if (!conversation) return <NotFound />;\n * return <h1>{conversation.name ?? 'Untitled'}</h1>;\n * ```\n */\nexport function useConversation(id: Uuid | null): UseConversationState {\n const chat = usePoolse();\n const [conversation, setConversation] = useState<Conversation | null>(null);\n const [loading, setLoading] = useState(id !== null);\n const [error, setError] = useState<Error | null>(null);\n\n // The fetcher is wrapped in useCallback so it's stable across\n // renders for the same id — lets callers depend on it in their\n // own effects (e.g. polling) without re-firing on every render.\n const fetcher = useCallback(\n async (signal?: AbortSignal): Promise<void> => {\n if (id === null) return;\n setLoading(true);\n setError(null);\n try {\n const conv = await chat.conversations.one(id).show(signal);\n setConversation(conv);\n } catch (err) {\n // Ignore AbortError — the caller hit unmount or a new id.\n if ((err as DOMException)?.name === 'AbortError') return;\n setError(err instanceof Error ? err : new Error(String(err)));\n } finally {\n setLoading(false);\n }\n },\n [chat, id],\n );\n\n useEffect(() => {\n if (id === null) {\n setConversation(null);\n setLoading(false);\n setError(null);\n return;\n }\n const controller = new AbortController();\n void fetcher(controller.signal);\n return () => controller.abort();\n }, [fetcher, id]);\n\n const refetch = useCallback(() => fetcher(), [fetcher]);\n\n return { conversation, loading, error, refetch };\n}\n","import type { Conversation, ConversationCreateRequest, Uuid } from '@poolse/sdk';\nimport { useCallback, useEffect, useMemo, useState } from 'react';\nimport { usePoolse } from './provider.js';\nimport { useMe } from './use-me.js';\n\ninterface UseConversationsState {\n conversations: Conversation[];\n loading: boolean;\n error: Error | null;\n refetch: () => Promise<void>;\n create: (attrs: ConversationCreateRequest) => Promise<Conversation>;\n /**\n * Per-conversation unread count, keyed by conversation id. Sourced\n * from `Conversation.unread_count` on the initial fetch and kept\n * fresh as the caller marks conversations read (via `markRead`).\n *\n * Note: cross-conversation incrementing on a new inbound message\n * requires subscribing to every conversation channel, which the SDK\n * doesn't do by default. Counts in this map are accurate for the\n * conversation the caller has open + correct at fetch time for the\n * rest; refetch on a fresh tab focus for true reconciliation.\n */\n unreadCounts: Record<Uuid, number>;\n /** Force a conversation's unread to 0 — invoked by `markReadUpTo`. */\n markConversationRead: (conversationId: Uuid) => void;\n}\n\n/**\n * List of conversations the current End User can see.\n *\n * On mount: REST-fetches the list and subscribes to the user's\n * `user:<id>` channel for `conversation:created` events — fired by\n * the server both when this user creates a conversation AND when\n * someone else adds them to one. New rows are prepended to local\n * state with id-based dedup so an optimistic `create()` followed by\n * the realtime echo doesn't insert twice.\n *\n * `refetch()` is still here for explicit re-syncs (e.g. after a\n * mutation that the SDK doesn't yet observe — name changes,\n * settings updates). `create()` returns the canonical server row.\n */\nexport function useConversations(): UseConversationsState {\n const chat = usePoolse();\n const { me } = useMe();\n const [conversations, setConversations] = useState<Conversation[]>([]);\n const [loading, setLoading] = useState(true);\n const [error, setError] = useState<Error | null>(null);\n\n const refetch = useCallback(async () => {\n setLoading(true);\n try {\n const list = await chat.conversations.list();\n setConversations(list.data);\n setError(null);\n } catch (err) {\n setError(err instanceof Error ? err : new Error(String(err)));\n } finally {\n setLoading(false);\n }\n }, [chat]);\n\n const create = useCallback(\n async (attrs: ConversationCreateRequest) => {\n const conv = await chat.conversations.create(attrs);\n // Optimistically prepend; if the realtime echo arrives later\n // for the same conv (because the server also broadcast it to\n // us as the creator), the id-based dedup in `prepend` keeps\n // it from inserting twice.\n setConversations((prev) => prepend(prev, conv));\n return conv;\n },\n [chat],\n );\n\n useEffect(() => {\n void refetch();\n }, [refetch]);\n\n // Realtime: subscribe to `user:<me.id>` for both `conversation:created`\n // (new membership) and `conversation:updated` (a member of an existing\n // conversation sent a message). Re-subscribes if `me.id` changes.\n useEffect(() => {\n if (!me) return;\n const userChan = chat.realtime.user(me.id);\n const offCreated = userChan.onConversationCreated((conv) => {\n setConversations((prev) => prepend(prev, conv));\n });\n const offUpdated = userChan.onConversationUpdated(({ conversation, by_user_id }) => {\n const fromMe = by_user_id === me.id;\n setConversations((prev) => mergeUpdated(prev, conversation, fromMe));\n });\n return () => {\n offCreated();\n offUpdated();\n };\n }, [chat, me]);\n\n // Force-zero an unread count without mutating the conversation row.\n // Wired by ConversationView's auto-mark-read on scroll so the sidebar\n // badge clears the moment the caller's IntersectionObserver fires\n // — before the server roundtrip + realtime echo for `member:read`.\n const markConversationRead = useCallback((conversationId: Uuid) => {\n setConversations((prev) =>\n prev.map((c) => (c.id === conversationId ? { ...c, unread_count: 0 } : c)),\n );\n }, []);\n\n const unreadCounts = useMemo<Record<Uuid, number>>(() => {\n const out: Record<Uuid, number> = {};\n for (const c of conversations) {\n if (typeof c.unread_count === 'number' && c.unread_count > 0) {\n out[c.id] = c.unread_count;\n }\n }\n return out;\n }, [conversations]);\n\n return { conversations, loading, error, refetch, create, unreadCounts, markConversationRead };\n}\n\n/**\n * Prepend `conv` if its id isn't already in `prev`; otherwise replace\n * the existing row (covers the race where the realtime echo arrives\n * for a conversation our local `create()` already inserted).\n */\nfunction prepend(prev: Conversation[], conv: Conversation): Conversation[] {\n const idx = prev.findIndex((c) => c.id === conv.id);\n if (idx === -1) return [conv, ...prev];\n const next = prev.slice();\n next[idx] = conv;\n return next;\n}\n\n/**\n * Apply a `conversation:updated` realtime payload: merge the fresh\n * surface fields (preview, timestamp, sequence, unread_count) into\n * the existing row and float it to the top.\n *\n * Preferred source for `unread_count` is the wire payload —\n * @poolse/server now computes per-member counts excluding tombstoned\n * messages and injects them into each member's broadcast, so the\n * value is authoritative for both new-message and delete events.\n * Older servers don't include it; we fall back to the legacy\n * \"increment when not from me\" heuristic so the badge still moves\n * for unconsumed sends.\n *\n * If the conversation isn't in our local list yet (rare — joined\n * via a different tab, or we just signed in), prepend the wire row\n * as-is.\n */\nfunction mergeUpdated(prev: Conversation[], next: Conversation, fromMe: boolean): Conversation[] {\n const idx = prev.findIndex((c) => c.id === next.id);\n if (idx === -1) return [next, ...prev];\n const existing = prev[idx]!;\n const wireUnread = typeof next.unread_count === 'number' ? next.unread_count : null;\n const unread_count =\n wireUnread !== null ? wireUnread : fromMe ? 0 : (existing.unread_count ?? 0) + 1;\n const merged: Conversation = {\n ...existing,\n last_message_at: next.last_message_at,\n last_message_preview: next.last_message_preview,\n last_sequence: next.last_sequence,\n unread_count,\n };\n const rest = prev.slice(0, idx).concat(prev.slice(idx + 1));\n return [merged, ...rest];\n}\n","import type { AddMemberOptions, MemberReadEvent, MemberRole, Membership, Uuid } from '@poolse/sdk';\nimport { useCallback, useEffect, useRef, useState } from 'react';\nimport { usePoolse } from './provider.js';\n\ninterface UseMembersState {\n members: Membership[];\n loading: boolean;\n error: Error | null;\n refetch: () => Promise<void>;\n /**\n * Add one or more users by `external_id`. Unknown ids are\n * auto-provisioned on the server. Returned memberships are\n * appended to local state on success.\n */\n addMembers: (externalIds: string[], opts?: { role?: MemberRole }) => Promise<Membership[]>;\n /**\n * Remove a member by `external_id`. The SDK translates to the\n * internal user_id under the hood. Optimistically removes from\n * state; rolls back on server error.\n */\n removeMember: (externalId: string) => Promise<void>;\n}\n\n/**\n * Live-ish membership list for a conversation. Initial REST fetch on\n * mount; mutation helpers update local state in place.\n *\n * Realtime: subscribes to `member:read` on the conversation channel\n * and advances the matching membership's `last_read_message_id` /\n * `last_read_at` so the sender's read-receipt glyph flips from \"sent\"\n * to \"read\" without a refetch. `member:joined` / `member:left` aren't\n * broadcast yet — for cross-client adds/removes, call `refetch()`.\n */\nexport function useMembers(conversationId: Uuid): UseMembersState {\n const chat = usePoolse();\n const [members, setMembers] = useState<Membership[]>([]);\n const [loading, setLoading] = useState(true);\n const [error, setError] = useState<Error | null>(null);\n\n // Shadow ref tracking the latest committed members. Lets the\n // optimistic rollback path capture a snapshot synchronously\n // without racing the React updater queue against an `await`.\n const membersRef = useRef<Membership[]>([]);\n membersRef.current = members;\n\n // Buffer for `member:read` events that arrive BEFORE the initial\n // fetch lands. The realtime subscription runs almost immediately on\n // mount; the HTTP fetch takes a roundtrip. If another user reads in\n // that window, the broadcast fires while local state is still empty\n // and the `prev.map` no-ops — leaving the read invisible forever.\n // We buffer here and replay inside the fetcher after `setMembers`\n // commits the snapshot.\n const pendingReadsRef = useRef<MemberReadEvent[]>([]);\n const hasFetchedRef = useRef(false);\n\n const applyRead = (list: Membership[], evt: MemberReadEvent): Membership[] =>\n list.map((m) =>\n m.user_id === evt.user_id\n ? {\n ...m,\n last_read_message_id: evt.last_read_message_id,\n last_read_at: evt.last_read_at,\n }\n : m,\n );\n\n const fetcher = useCallback(\n async (signal?: AbortSignal): Promise<void> => {\n // Empty id = \"skip fetch\" — used by callers that conditionally\n // want member data (e.g. ConversationView's `mentions={false}\n // readReceipts={false}` configuration). Better than asking\n // every caller to wrap in `enabled ? useMembers(id) : null`.\n if (!conversationId) {\n setLoading(false);\n setMembers([]);\n setError(null);\n return;\n }\n setLoading(true);\n setError(null);\n try {\n const { data } = await chat.conversations.one(conversationId).listMembers(signal);\n // Drain any buffered `member:read` events that fired before the\n // fetch landed. Without this, reads that arrive in the\n // subscribe→response gap would be lost.\n let next = data;\n if (pendingReadsRef.current.length > 0) {\n for (const evt of pendingReadsRef.current) next = applyRead(next, evt);\n pendingReadsRef.current = [];\n }\n setMembers(next);\n hasFetchedRef.current = true;\n } catch (err) {\n if ((err as DOMException)?.name === 'AbortError') return;\n setError(err instanceof Error ? err : new Error(String(err)));\n } finally {\n setLoading(false);\n }\n },\n [chat, conversationId],\n );\n\n useEffect(() => {\n // Reset per-conversation state so a swap of `conversationId`\n // doesn't carry stale buffered reads from a previous channel.\n hasFetchedRef.current = false;\n pendingReadsRef.current = [];\n const controller = new AbortController();\n void fetcher(controller.signal);\n return () => controller.abort();\n }, [fetcher]);\n\n // Real-time read-cursor sync. When ANY member reads, advance their\n // membership row locally — the sender's UI uses\n // max(memberships.last_read_message_id.sequence) to decide whether\n // to show the \"read\" glyph, so this single state edit drives the\n // whole receipt UI.\n useEffect(() => {\n if (!conversationId) return;\n const channel = chat.realtime.conversation(conversationId);\n const off = channel.onMemberRead((evt) => {\n // Buffer if the initial fetch hasn't landed — the fetcher's\n // try-block drains the buffer once it has membership rows to\n // apply the read to. See the matching ref pair above.\n if (!hasFetchedRef.current) {\n pendingReadsRef.current.push(evt);\n return;\n }\n setMembers((prev) => applyRead(prev, evt));\n });\n return () => off();\n }, [chat, conversationId]);\n\n const refetch = useCallback(() => fetcher(), [fetcher]);\n\n const addMembers = useCallback(\n async (externalIds: string[], opts: { role?: MemberRole } = {}) => {\n const addOpts: AddMemberOptions = opts.role !== undefined ? { role: opts.role } : {};\n const { data } = await chat.conversations\n .one(conversationId)\n .addMembers(externalIds, addOpts);\n // Dedup by id in case the server returns a row that was already\n // a member (idempotent re-add).\n setMembers((prev) => {\n const byId = new Map(prev.map((m) => [m.id, m]));\n for (const m of data) byId.set(m.id, m);\n return Array.from(byId.values());\n });\n return data;\n },\n [chat, conversationId],\n );\n\n const removeMember = useCallback(\n async (externalId: string) => {\n const snapshot = membersRef.current;\n // Translate external_id → internal user_id via the loaded member\n // list. The DELETE endpoint takes user_id in the path, but the\n // consumer never has to know that.\n const target = snapshot.find((m) => m.external_id === externalId);\n if (!target) return; // not a member; idempotent no-op\n\n const targetUserId: Uuid = target.user_id;\n setMembers((prev) => prev.filter((m) => m.external_id !== externalId));\n try {\n await chat.conversations.one(conversationId).removeMember(targetUserId);\n } catch (err) {\n setMembers(snapshot);\n throw err;\n }\n },\n [chat, conversationId],\n );\n\n return { members, loading, error, refetch, addMembers, removeMember };\n}\n","import type { Message, MessageCreateRequest, Uuid } from '@poolse/sdk';\nimport { safeUuid } from '@poolse/sdk';\nimport { useCallback, useEffect, useRef, useState } from 'react';\nimport { usePoolse } from './provider.js';\nimport { useMe } from './use-me.js';\n\ninterface UseMessagesState {\n /** Newest-last array. The wire returns newest-first; we reverse so list rendering matches reading order. */\n messages: Message[];\n loading: boolean;\n error: Error | null;\n hasMore: boolean;\n /** Load an older page (lower sequence numbers). Idempotent if no older messages exist. */\n loadMore: () => Promise<void>;\n /** Optimistically append + POST. Replaces the optimistic row with the server response on success. */\n send: (attrs: MessageCreateRequest) => Promise<Message>;\n /**\n * Edit a message you previously sent. Optimistically updates the\n * local row, rolls back on server error. Server enforces\n * sender-only authorization — calling this for a message you didn't\n * send will throw an ApiError.\n */\n edit: (messageId: Uuid, body: string) => Promise<Message>;\n /**\n * Soft-delete a message you sent (or that you have admin authority\n * over). Optimistically applies the tombstone (`deleted_at` + null\n * body) locally, rolls back on error.\n */\n delete: (messageId: Uuid) => Promise<void>;\n /**\n * Advance the caller's read cursor to `messageId`. Server emits\n * read-receipt updates to other members; the conversation's\n * unread count drops to zero. No local state mutation — this is\n * \"tell the server we read up to here\".\n */\n markReadUpTo: (messageId: Uuid) => Promise<void>;\n /**\n * Re-fetch the newest page (PAGE_SIZE) and replace the cached\n * messages. Useful when the app returns from background or the\n * realtime socket reconnects after a drop — any messages we missed\n * while disconnected are pulled in via REST. Pagination resets:\n * `hasMore` becomes true again so `loadMore()` will walk back from\n * the new tail.\n */\n refetch: () => Promise<void>;\n}\n\nconst PAGE_SIZE = 50;\n\n/**\n * Live message list for `conversationId`. Combines:\n *\n * * Initial REST fetch (newest 50) on mount.\n * * WebSocket subscription for `message:new`, `message:updated`,\n * `message:deleted` — applied in-place to the cached array.\n * * Optimistic-send via `send()` — the message appears immediately\n * under the SAME id the server will assign (we pre-generate it\n * client-side and pass it through), so the realtime echo and the\n * REST response both arrive carrying that id and get deduped by\n * `findIndex(m => m.id === msg.id)`. No heuristic match, no race.\n *\n * Re-mounting with the same `conversationId` reuses the underlying\n * channel — no extra socket traffic.\n */\nexport function useMessages(conversationId: string): UseMessagesState {\n const chat = usePoolse();\n const { me } = useMe();\n const [messages, setMessages] = useState<Message[]>([]);\n const [loading, setLoading] = useState(true);\n const [error, setError] = useState<Error | null>(null);\n const [hasMore, setHasMore] = useState(true);\n\n // Cursor for `loadMore` — the lowest sequence currently in state.\n const oldestSequenceRef = useRef<number | null>(null);\n // Mutable refetch implementation. Set per-effect (it captures the\n // current conversation's `messages` resource handle). Exposed\n // through the stable `refetch` callback below so consumers can wire\n // it to e.g. `AppState` 'active' without re-binding on every render.\n const refetchRef = useRef<(() => Promise<void>) | null>(null);\n\n // Hold `me.id` in a ref so `send()` stays stable across renders\n // (otherwise its identity changes every time `me` reloads, which\n // would re-create handlers in calling components).\n const meIdRef = useRef<string | null>(me?.id ?? null);\n meIdRef.current = me?.id ?? null;\n const meExternalIdRef = useRef<string | null>(me?.external_id ?? null);\n meExternalIdRef.current = me?.external_id ?? null;\n\n useEffect(() => {\n let cancelled = false;\n setLoading(true);\n setMessages([]);\n setError(null);\n setHasMore(true);\n oldestSequenceRef.current = null;\n\n const handle = chat.conversations.one(conversationId).messages;\n\n handle\n .list({ limit: PAGE_SIZE })\n .then((page) => {\n if (cancelled) return;\n // Wire is newest-first; flip for natural reading order.\n const ordered = [...page.data].reverse();\n setMessages(ordered);\n setHasMore(page.data.length === PAGE_SIZE);\n oldestSequenceRef.current = ordered[0]?.sequence ?? null;\n setLoading(false);\n })\n .catch((err: unknown) => {\n if (cancelled) return;\n setError(err instanceof Error ? err : new Error(String(err)));\n setLoading(false);\n });\n\n refetchRef.current = async () => {\n const page = await handle.list({ limit: PAGE_SIZE });\n const ordered = [...page.data].reverse();\n setMessages(ordered);\n setHasMore(page.data.length === PAGE_SIZE);\n oldestSequenceRef.current = ordered[0]?.sequence ?? null;\n };\n\n // Realtime listeners.\n const conv = chat.realtime.conversation(conversationId);\n\n const offNew = conv.onMessage((msg) => {\n // Thread replies don't live in the main feed — they belong to\n // the side-pane that `useThread` populates. So when a reply\n // arrives over realtime, route it to the root's reply_count\n // ONLY, and skip the main-list upsert. The server now mirrors\n // this rule on the REST list (`WHERE thread_root_id IS NULL`),\n // so post-refresh state matches realtime behavior.\n if (msg.thread_root_id) {\n setMessages((prev) =>\n prev.map((m) =>\n m.id === msg.thread_root_id ? { ...m, reply_count: (m.reply_count ?? 0) + 1 } : m,\n ),\n );\n return;\n }\n // Top-level message: standard by-id upsert. Covers three cases:\n // 1) Brand-new message from another user → append.\n // 2) Echo of our own optimistic send (id we generated below) →\n // replace the temp row in place (preserves position).\n // 3) Re-delivery on channel rejoin → idempotent replace.\n setMessages((prev) => upsertById(prev, msg));\n });\n\n const offUpdated = conv.onMessageUpdated((msg) => {\n setMessages((prev) => prev.map((m) => (m.id === msg.id ? msg : m)));\n });\n\n const offDeleted = conv.onMessageDeleted((evt) => {\n setMessages((prev) => {\n // Capture the pre-delete row so we can find the thread root if\n // this message was a reply — the delete payload doesn't carry\n // `thread_root_id`, so we have to look it up locally.\n const target = prev.find((m) => m.id === evt.id);\n const updated = prev.map((m) =>\n m.id === evt.id ? { ...m, deleted_at: evt.deleted_at, body: null } : m,\n );\n if (target?.thread_root_id) {\n return updated.map((m) =>\n m.id === target.thread_root_id\n ? { ...m, reply_count: Math.max(0, (m.reply_count ?? 0) - 1) }\n : m,\n );\n }\n return updated;\n });\n });\n\n return () => {\n cancelled = true;\n offNew();\n offUpdated();\n offDeleted();\n // Don't leave the channel — another component may still be reading\n // this conversation. The Poolse.destroy() at provider-unmount\n // tears everything down.\n };\n }, [chat, conversationId]);\n\n const loadMore = useCallback(async () => {\n if (!hasMore || loading) return;\n const before = oldestSequenceRef.current;\n if (!before) return;\n\n const opts: { limit: number; before?: number } = { limit: PAGE_SIZE };\n if (before !== null) opts.before = before;\n\n const page = await chat.conversations.one(conversationId).messages.list(opts);\n if (page.data.length === 0) {\n setHasMore(false);\n return;\n }\n const older = [...page.data].reverse();\n setMessages((prev) => [...older, ...prev]);\n setHasMore(page.data.length === PAGE_SIZE);\n oldestSequenceRef.current = older[0]?.sequence ?? oldestSequenceRef.current;\n }, [chat, conversationId, hasMore, loading]);\n\n const send = useCallback(\n async (attrs: MessageCreateRequest) => {\n // Generate the message id client-side and pass it through, so\n // the optimistic row, the REST response, and the realtime echo\n // ALL share one id — id-based upsert handles every race.\n const id = attrs.id ?? safeUuid();\n const tempMsg: Message = {\n id,\n tenant_id: '',\n conversation_id: conversationId,\n // Stamp the current user's id so the optimistic row renders\n // on the right (self) side from the moment it appears. Null\n // here would briefly flash the row on the \"other\" side until\n // the realtime echo replaced it with the canonical row.\n sender_id: meIdRef.current,\n sender_external_id: meExternalIdRef.current,\n type: attrs.type ?? 'text',\n body: attrs.body ?? null,\n reply_to_id: attrs.reply_to_id ?? null,\n thread_root_id: null,\n // Optimistic quote: keep the id locally so the bubble can flag\n // itself as a quote-reply immediately. `quoted_message` (the\n // preview card body/sender) only lands when the server echo\n // arrives — the UI can render a placeholder (\"Quoted message\")\n // in the gap or wait silently; current bubble does the latter.\n quoted_message_id: attrs.quoted_message_id ?? null,\n mentions: attrs.mentions ?? [],\n reactions: {},\n edited_at: null,\n deleted_at: null,\n // MAX_SAFE_INTEGER sorts the temp row to the very end (newest\n // position) until the server returns the real `sequence`.\n sequence: Number.MAX_SAFE_INTEGER,\n inserted_at: new Date().toISOString(),\n updated_at: new Date().toISOString(),\n };\n\n setMessages((prev) => [...prev, tempMsg]);\n\n try {\n const sent = await chat.conversations.one(conversationId).messages.send({ ...attrs, id });\n // Both REST and realtime carry the same id; whichever lands\n // first wins, and the second is an idempotent replace.\n setMessages((prev) => upsertById(prev, sent));\n return sent;\n } catch (err) {\n setMessages((prev) => prev.filter((m) => m.id !== id));\n throw err;\n }\n },\n [chat, conversationId],\n );\n\n const edit = useCallback(\n async (messageId: Uuid, body: string): Promise<Message> => {\n // Optimistic: capture the previous body so we can roll back if the\n // PATCH fails. `edited_at` is set to \"now\" client-side; the server\n // will overwrite with its authoritative timestamp on the realtime\n // echo + REST response.\n let previous: Message | undefined;\n setMessages((prev) =>\n prev.map((m) => {\n if (m.id !== messageId) return m;\n previous = m;\n return { ...m, body, edited_at: new Date().toISOString() };\n }),\n );\n\n try {\n const updated = await chat.messages.one(messageId).update({ body });\n // Replace with the canonical row (right edited_at, etc).\n setMessages((prev) => prev.map((m) => (m.id === messageId ? updated : m)));\n return updated;\n } catch (err) {\n if (previous) {\n const restore = previous;\n setMessages((prev) => prev.map((m) => (m.id === messageId ? restore : m)));\n }\n throw err;\n }\n },\n [chat],\n );\n\n const deleteMessage = useCallback(\n async (messageId: Uuid): Promise<void> => {\n // Optimistic tombstone — same shape the realtime delete handler\n // applies, so the UI is consistent regardless of which path\n // (REST response or WS push) lands first.\n let previous: Message | undefined;\n setMessages((prev) =>\n prev.map((m) => {\n if (m.id !== messageId) return m;\n previous = m;\n return { ...m, body: null, deleted_at: new Date().toISOString() };\n }),\n );\n\n try {\n await chat.messages.one(messageId).delete();\n } catch (err) {\n if (previous) {\n const restore = previous;\n setMessages((prev) => prev.map((m) => (m.id === messageId ? restore : m)));\n }\n throw err;\n }\n },\n [chat],\n );\n\n const markReadUpTo = useCallback(\n async (messageId: Uuid): Promise<void> => {\n // Fire-and-forget — server updates the caller's last_read_message_id\n // and broadcasts the resulting membership update to other clients\n // (which is what drives read-receipt glyphs in their UIs).\n await chat.conversations.one(conversationId).messages.markRead(messageId);\n },\n [chat, conversationId],\n );\n\n const refetch = useCallback(async (): Promise<void> => {\n const fn = refetchRef.current;\n if (!fn) return;\n await fn();\n }, []);\n\n return {\n messages,\n loading,\n error,\n hasMore,\n loadMore,\n send,\n edit,\n delete: deleteMessage,\n markReadUpTo,\n refetch,\n };\n}\n\nfunction upsertById(prev: Message[], msg: Message): Message[] {\n const idx = prev.findIndex((m) => m.id === msg.id);\n if (idx === -1) return [...prev, msg];\n const next = prev.slice();\n next[idx] = msg;\n return next;\n}\n","import type { Uuid } from '@poolse/sdk';\nimport { useCallback, useEffect, useRef, useState } from 'react';\nimport { usePoolse } from './provider.js';\n\n/**\n * Map of emoji → list of user_ids who reacted with it. Matches the\n * shape of `Message.reactions` so initial seeding from a message you\n * already have in state is a direct assignment.\n */\nexport type ReactionMap = Record<string, Uuid[]>;\n\ninterface UseReactionsState {\n reactions: ReactionMap;\n /** Add the caller's reaction (idempotent server-side). */\n addReaction: (emoji: string) => Promise<void>;\n /** Remove the caller's reaction. No-op if not present. */\n removeReaction: (emoji: string) => Promise<void>;\n}\n\ninterface UseReactionsOptions {\n /**\n * Required for the in-channel subscription — the realtime layer\n * routes reaction events through the conversation channel, not a\n * per-message channel. Pass the conversation id you already know.\n */\n conversationId: Uuid;\n /**\n * Seed the local reaction map from a message you already have\n * (e.g. from `useMessages`). Without this the hook starts empty\n * and only sees deltas from the realtime stream.\n */\n initialReactions?: ReactionMap;\n /**\n * Current user's id. When provided, optimistic mutate updates the\n * local map immediately for that user; when omitted, we wait for\n * the server's `reaction:added` echo to update state.\n */\n currentUserId?: Uuid | null;\n}\n\n/**\n * Live reaction map for a single message. Subscribes to\n * `reaction:added` / `reaction:removed` realtime events filtered to\n * `messageId`, and provides mutation helpers.\n *\n * ```ts\n * const { reactions, addReaction } = useReactions(msg.id, {\n * conversationId: msg.conversation_id,\n * initialReactions: msg.reactions,\n * currentUserId: me?.id,\n * });\n * <button onClick={() => addReaction('🎉')}>🎉 {reactions['🎉']?.length ?? 0}</button>\n * ```\n */\nexport function useReactions(messageId: Uuid, opts: UseReactionsOptions): UseReactionsState {\n const chat = usePoolse();\n const [reactions, setReactions] = useState<ReactionMap>(opts.initialReactions ?? {});\n\n // Keep currentUserId in a ref so the realtime callbacks (set up in\n // the mount effect) always see the latest value without having to\n // re-subscribe when it changes.\n const currentUserIdRef = useRef<Uuid | null>(opts.currentUserId ?? null);\n currentUserIdRef.current = opts.currentUserId ?? null;\n\n // Shadow ref of the latest committed reactions map — used by\n // `removeReaction` for synchronous snapshot capture so the\n // optimistic rollback isn't racing the React updater queue.\n const reactionsRef = useRef<ReactionMap>(reactions);\n reactionsRef.current = reactions;\n\n useEffect(() => {\n const conv = chat.realtime.conversation(opts.conversationId);\n\n const offAdded = conv.onReactionAdded((evt) => {\n if (evt.message_id !== messageId) return;\n setReactions((prev) => addUser(prev, evt.emoji, evt.user_id));\n });\n\n const offRemoved = conv.onReactionRemoved((evt) => {\n if (evt.message_id !== messageId) return;\n setReactions((prev) => removeUser(prev, evt.emoji, evt.user_id));\n });\n\n return () => {\n offAdded();\n offRemoved();\n };\n }, [chat, opts.conversationId, messageId]);\n\n const addReaction = useCallback(\n async (emoji: string) => {\n const uid = currentUserIdRef.current;\n // Optimistic add when we know who we are; otherwise wait for echo.\n if (uid) setReactions((prev) => addUser(prev, emoji, uid));\n try {\n await chat.messages.one(messageId).addReaction(emoji);\n } catch (err) {\n if (uid) setReactions((prev) => removeUser(prev, emoji, uid));\n throw err;\n }\n },\n [chat, messageId],\n );\n\n const removeReaction = useCallback(\n async (emoji: string) => {\n const uid = currentUserIdRef.current;\n const snapshot = reactionsRef.current;\n if (uid) setReactions((prev) => removeUser(prev, emoji, uid));\n try {\n await chat.messages.one(messageId).removeReaction(emoji);\n } catch (err) {\n if (uid) setReactions(snapshot);\n throw err;\n }\n },\n [chat, messageId],\n );\n\n return { reactions, addReaction, removeReaction };\n}\n\nfunction addUser(prev: ReactionMap, emoji: string, userId: Uuid): ReactionMap {\n const existing = prev[emoji] ?? [];\n if (existing.includes(userId)) return prev;\n return { ...prev, [emoji]: [...existing, userId] };\n}\n\nfunction removeUser(prev: ReactionMap, emoji: string, userId: Uuid): ReactionMap {\n const existing = prev[emoji];\n if (!existing || !existing.includes(userId)) return prev;\n const next = existing.filter((id) => id !== userId);\n if (next.length === 0) {\n const { [emoji]: _, ...rest } = prev;\n return rest;\n }\n return { ...prev, [emoji]: next };\n}\n","import type { Message, MessageCreateRequest, Uuid } from '@poolse/sdk';\nimport { safeUuid } from '@poolse/sdk';\nimport { useCallback, useEffect, useRef, useState } from 'react';\nimport { usePoolse } from './provider.js';\n\ninterface UseThreadState {\n /** Replies, oldest-first (the wire returns oldest-first; we don't flip). */\n replies: Message[];\n loading: boolean;\n error: Error | null;\n /** More older-than-current-page replies available on the server. */\n hasMore: boolean;\n /** Load the next page after the current newest reply. Idempotent if no more. */\n loadMore: () => Promise<void>;\n /**\n * Send a reply into this thread. Fills `reply_to_id` with the root\n * message id automatically; pass `body` (and any other\n * `MessageCreateRequest` fields) as you would to `useMessages.send`.\n */\n sendReply: (attrs: Omit<MessageCreateRequest, 'reply_to_id'>) => Promise<Message>;\n /**\n * Edit a reply (or the root message). Optimistic with rollback —\n * mirrors `useMessages.edit`. Server enforces sender-only authz.\n */\n edit: (messageId: Uuid, body: string) => Promise<Message>;\n /**\n * Soft-delete a reply (or the root message). Optimistic tombstone\n * (`deleted_at` + null body) — mirrors `useMessages.delete`.\n */\n delete: (messageId: Uuid) => Promise<void>;\n}\n\n// Threads load top-down all-at-once: most discussions stay well under\n// 500 replies, the side-pane has no infinite-scroll affordance, and\n// avoiding pagination keeps the UX simple. `loadMore` remains as an\n// escape hatch in case a thread does exceed this on the rare day.\nconst PAGE_SIZE = 500;\n\n/**\n * Thread view rooted at `rootMessageId`. Loads replies oldest-first\n * with cursor pagination (`after: sequence`), subscribes to the\n * conversation channel's `message:new` event filtered by\n * `thread_root_id === rootMessageId`, and provides a `sendReply`\n * that wires `reply_to_id` for you.\n *\n * Like `useMessages`, the optimistic send uses the same id the\n * server will assign (auto-generated by the SDK), so the realtime\n * echo just upserts in place — no double-render.\n */\nexport function useThread(conversationId: Uuid, rootMessageId: Uuid): UseThreadState {\n const chat = usePoolse();\n const [replies, setReplies] = useState<Message[]>([]);\n const [loading, setLoading] = useState(true);\n const [error, setError] = useState<Error | null>(null);\n const [hasMore, setHasMore] = useState(true);\n\n // Cursor for `loadMore` — the highest sequence currently in state.\n const newestSequenceRef = useRef<number | null>(null);\n\n useEffect(() => {\n let cancelled = false;\n setLoading(true);\n setReplies([]);\n setError(null);\n setHasMore(true);\n newestSequenceRef.current = null;\n\n chat.messages\n .one(rootMessageId)\n .replies({ limit: PAGE_SIZE })\n .then((page) => {\n if (cancelled) return;\n setReplies(page.data);\n setHasMore(page.data.length === PAGE_SIZE);\n newestSequenceRef.current = page.data[page.data.length - 1]?.sequence ?? null;\n setLoading(false);\n })\n .catch((err: unknown) => {\n if (cancelled) return;\n setError(err instanceof Error ? err : new Error(String(err)));\n setLoading(false);\n });\n\n // Realtime: filter conversation messages for thread membership.\n const conv = chat.realtime.conversation(conversationId);\n const offNew = conv.onMessage((msg) => {\n if (msg.thread_root_id !== rootMessageId) return;\n setReplies((prev) => upsertById(prev, msg));\n });\n const offUpdated = conv.onMessageUpdated((msg) => {\n if (msg.thread_root_id !== rootMessageId) return;\n setReplies((prev) => prev.map((m) => (m.id === msg.id ? msg : m)));\n });\n const offDeleted = conv.onMessageDeleted((evt) => {\n setReplies((prev) =>\n prev.map((m) => (m.id === evt.id ? { ...m, deleted_at: evt.deleted_at, body: null } : m)),\n );\n });\n\n return () => {\n cancelled = true;\n offNew();\n offUpdated();\n offDeleted();\n };\n }, [chat, conversationId, rootMessageId]);\n\n const loadMore = useCallback(async () => {\n if (!hasMore || loading) return;\n const after = newestSequenceRef.current;\n if (after === null) return;\n const page = await chat.messages.one(rootMessageId).replies({ limit: PAGE_SIZE, after });\n if (page.data.length === 0) {\n setHasMore(false);\n return;\n }\n setReplies((prev) => [...prev, ...page.data]);\n setHasMore(page.data.length === PAGE_SIZE);\n newestSequenceRef.current = page.data[page.data.length - 1]?.sequence ?? after;\n }, [chat, rootMessageId, hasMore, loading]);\n\n const sendReply = useCallback(\n async (attrs: Omit<MessageCreateRequest, 'reply_to_id'>) => {\n const id = attrs.id ?? safeUuid();\n const tempMsg: Message = {\n id,\n tenant_id: '',\n conversation_id: conversationId,\n sender_id: null,\n sender_external_id: null,\n type: attrs.type ?? 'text',\n body: attrs.body ?? null,\n reply_to_id: rootMessageId,\n thread_root_id: rootMessageId,\n mentions: attrs.mentions ?? [],\n reactions: {},\n edited_at: null,\n deleted_at: null,\n sequence: Number.MAX_SAFE_INTEGER,\n inserted_at: new Date().toISOString(),\n updated_at: new Date().toISOString(),\n };\n setReplies((prev) => [...prev, tempMsg]);\n\n try {\n const sent = await chat.conversations.one(conversationId).messages.send({\n ...attrs,\n id,\n reply_to_id: rootMessageId,\n });\n setReplies((prev) => upsertById(prev, sent));\n return sent;\n } catch (err) {\n setReplies((prev) => prev.filter((m) => m.id !== id));\n throw err;\n }\n },\n [chat, conversationId, rootMessageId],\n );\n\n const edit = useCallback(\n async (messageId: Uuid, body: string): Promise<Message> => {\n let previous: Message | undefined;\n setReplies((prev) =>\n prev.map((m) => {\n if (m.id !== messageId) return m;\n previous = m;\n return { ...m, body, edited_at: new Date().toISOString() };\n }),\n );\n\n try {\n const updated = await chat.messages.one(messageId).update({ body });\n setReplies((prev) => prev.map((m) => (m.id === messageId ? updated : m)));\n return updated;\n } catch (err) {\n if (previous) {\n const restore = previous;\n setReplies((prev) => prev.map((m) => (m.id === messageId ? restore : m)));\n }\n throw err;\n }\n },\n [chat],\n );\n\n const deleteReply = useCallback(\n async (messageId: Uuid): Promise<void> => {\n let previous: Message | undefined;\n setReplies((prev) =>\n prev.map((m) => {\n if (m.id !== messageId) return m;\n previous = m;\n return { ...m, body: null, deleted_at: new Date().toISOString() };\n }),\n );\n\n try {\n await chat.messages.one(messageId).delete();\n } catch (err) {\n if (previous) {\n const restore = previous;\n setReplies((prev) => prev.map((m) => (m.id === messageId ? restore : m)));\n }\n throw err;\n }\n },\n [chat],\n );\n\n return {\n replies,\n loading,\n error,\n hasMore,\n loadMore,\n sendReply,\n edit,\n delete: deleteReply,\n };\n}\n\nfunction upsertById(prev: Message[], msg: Message): Message[] {\n const idx = prev.findIndex((m) => m.id === msg.id);\n if (idx === -1) return [...prev, msg];\n const next = prev.slice();\n next[idx] = msg;\n return next;\n}\n","import { useCallback, useEffect, useRef, useState } from 'react';\nimport { usePoolse } from './provider.js';\nimport { useMe } from './use-me.js';\n\ninterface UseTypingState {\n /**\n * Set of `external_id`s currently typing (your own user identifiers,\n * the same string you'd pass to `userResolver`). Excludes the\n * current user — they know they're typing.\n */\n typing: Set<string>;\n /**\n * Send a typing ping to the server. Debounced inside the hook to\n * once per 500 ms — the server squashes further with its own\n * per-(user, conversation) window.\n */\n signalTyping: () => void;\n}\n\n// How long after the most recent `typing:start` ping we assume the\n// remote user has stopped typing. The server emits one ping every\n// ~500ms while the keystroke debounce is hot; 4s gives a comfortable\n// safety margin without leaving the chip on after the user clearly\n// stopped. Independent of the server's own `typing:stop` window so\n// the UI is responsive even if that broadcast is late or dropped.\nconst TYPING_TIMEOUT_MS = 4000;\n\n/**\n * Tracks who's typing in `conversationId`. Subscribes to the\n * `typing:start` / `typing:stop` broadcasts, plus two purely\n * client-side eviction paths that keep the chip from lingering when\n * the server is slow (or never) to send `typing:stop`:\n *\n * 1. Per-user inactivity timer — each `typing:start` resets a 4 s\n * timeout for that `external_id`; when it fires we drop them\n * from the set. Covers \"they stopped typing without sending\".\n * 2. `message:new` from the same sender — if a typing user sends a\n * message, we evict them immediately. Covers \"they just sent\".\n */\nexport function useTyping(conversationId: string): UseTypingState {\n const chat = usePoolse();\n const { me } = useMe();\n const [typing, setTyping] = useState<Set<string>>(new Set());\n const lastPingRef = useRef(0);\n\n // `me` resolves asynchronously after first render; read it from a\n // ref inside the event handlers so the subscription doesn't need to\n // re-attach when `me` lands (which would briefly drop incoming\n // typing events from other users).\n const meExtRef = useRef<string | null>(me?.external_id ?? null);\n meExtRef.current = me?.external_id ?? null;\n\n useEffect(() => {\n setTyping(new Set());\n const timers = new Map<string, ReturnType<typeof setTimeout>>();\n\n const evict = (ext: string) => {\n const t = timers.get(ext);\n if (t) {\n clearTimeout(t);\n timers.delete(ext);\n }\n setTyping((prev) => {\n if (!prev.has(ext)) return prev;\n const next = new Set(prev);\n next.delete(ext);\n return next;\n });\n };\n\n const conv = chat.realtime.conversation(conversationId);\n\n const offStart = conv.onTypingStart((evt) => {\n const ext = evt.external_id;\n if (!ext) return;\n // Don't render the current user's own typing — they know.\n if (meExtRef.current && ext === meExtRef.current) return;\n // (Re)arm the inactivity timer for this user.\n const existing = timers.get(ext);\n if (existing) clearTimeout(existing);\n timers.set(\n ext,\n setTimeout(() => evict(ext), TYPING_TIMEOUT_MS),\n );\n setTyping((prev) => {\n if (prev.has(ext)) return prev;\n const next = new Set(prev);\n next.add(ext);\n return next;\n });\n });\n\n const offStop = conv.onTypingStop((evt) => {\n const ext = evt.external_id;\n if (!ext) return;\n if (meExtRef.current && ext === meExtRef.current) return;\n evict(ext);\n });\n\n // If the typing user sends a message, they're definitely done\n // typing — evict immediately rather than waiting for the server's\n // typing:stop broadcast.\n const offMessage = conv.onMessage((msg) => {\n const ext = msg.sender_external_id;\n if (!ext) return;\n if (meExtRef.current && ext === meExtRef.current) return;\n evict(ext);\n });\n\n return () => {\n offStart();\n offStop();\n offMessage();\n for (const t of timers.values()) clearTimeout(t);\n timers.clear();\n };\n }, [chat, conversationId]);\n\n const signalTyping = useCallback(() => {\n const now = Date.now();\n if (now - lastPingRef.current < 500) return;\n lastPingRef.current = now;\n chat.realtime.conversation(conversationId).sendTyping();\n }, [chat, conversationId]);\n\n return { typing, signalTyping };\n}\n","import type { PresenceSnapshot } from '@poolse/sdk';\nimport { useEffect, useState } from 'react';\nimport { usePoolse } from './provider.js';\n\ninterface UsePresenceState {\n /**\n * Set of `external_id`s currently online in this conversation —\n * the tenant's own user identifiers. Empty set when no one is on\n * the channel (note: an empty result during reconnect is normal;\n * pair with `useRealtimeStatus()` if you need to distinguish).\n */\n online: Set<string>;\n}\n\n// Pull external_id out of the first meta entry for each user_id key.\n// Phoenix.Presence supports multiple metas per join (e.g. same user\n// in two tabs); we surface the external_id once since it's identical\n// across the user's metas.\nfunction externalIdsFrom(state: PresenceSnapshot): string[] {\n const out: string[] = [];\n for (const presence of Object.values(state)) {\n const meta = presence?.metas?.[0];\n if (meta?.external_id) out.push(meta.external_id);\n }\n return out;\n}\n\n/**\n * Who's currently joined to `conversationId`'s channel. Backed by\n * Phoenix.Presence broadcasts (`presence_state` snapshot on join,\n * `presence_diff` on changes).\n */\nexport function usePresence(conversationId: string): UsePresenceState {\n const chat = usePoolse();\n const [online, setOnline] = useState<Set<string>>(new Set());\n\n useEffect(() => {\n setOnline(new Set());\n\n if (!conversationId) return;\n\n const conv = chat.realtime.conversation(conversationId);\n\n const applyState = (state: PresenceSnapshot) => {\n setOnline(new Set(externalIdsFrom(state)));\n };\n\n const applyDiff = (diff: { joins?: PresenceSnapshot; leaves?: PresenceSnapshot }) => {\n setOnline((prev) => {\n const next = new Set(prev);\n if (diff.joins) externalIdsFrom(diff.joins).forEach((ext) => next.add(ext));\n if (diff.leaves) externalIdsFrom(diff.leaves).forEach((ext) => next.delete(ext));\n return next;\n });\n };\n\n const offState = conv.onPresenceState(applyState);\n const offDiff = conv.onPresenceDiff(applyDiff as (s: PresenceSnapshot) => void);\n\n return () => {\n offState();\n offDiff();\n };\n }, [chat, conversationId]);\n\n return { online };\n}\n","import type { RealtimeStatus } from '@poolse/sdk';\nimport { useEffect, useState } from 'react';\nimport { usePoolse } from './provider.js';\n\n/**\n * Connection status of the underlying WebSocket. Useful for showing a\n * \"reconnecting…\" banner without coupling to socket internals.\n *\n * Returns one of: `'idle' | 'connecting' | 'connected' | 'reconnecting' | 'closed'`.\n */\nexport function useRealtimeStatus(): RealtimeStatus {\n const chat = usePoolse();\n const [status, setStatus] = useState<RealtimeStatus>(chat.realtime.getStatus());\n\n useEffect(() => {\n setStatus(chat.realtime.getStatus());\n return chat.realtime.onStatus(setStatus);\n }, [chat]);\n\n return status;\n}\n","import type { Attachment, AttachmentUploadInput } from '@poolse/sdk';\nimport { safeUuid } from '@poolse/sdk';\nimport { useCallback, useEffect, useRef, useState } from 'react';\nimport { usePoolse } from './provider.js';\n\nexport type UploadItemStatus = 'pending' | 'uploading' | 'ready' | 'error' | 'cancelled';\n\nexport interface UploadItem {\n /** Local-only id (random per-enqueue). Stable for keys + `cancel(localId)` / `remove(localId)`. */\n localId: string;\n filename: string;\n contentType: string;\n byteSize: number;\n status: UploadItemStatus;\n /** Bytes uploaded so far; 0 until the PUT actually begins. */\n loaded: number;\n /** Resolved attachment row once `status === 'ready'`. Null otherwise. */\n attachment: Attachment | null;\n /** Set when `status === 'error'`. */\n error: Error | null;\n}\n\ninterface UseAttachmentUploadState {\n /** Every enqueued item, in enqueue order, until removed by `remove()` / `reset()`. */\n queue: UploadItem[];\n /**\n * Last attachment that reached `ready`, for the common one-file\n * \"did the upload finish\" check. Null after `reset()` / `remove()`\n * of the most recent ready item. Multi-file callers should iterate\n * `queue` instead.\n */\n attachment: Attachment | null;\n /** True while at least one item is `pending` or `uploading`. */\n uploading: boolean;\n /** Most recent item-level error, or null. */\n error: Error | null;\n /**\n * Enqueue a single upload. Resolves with the final attachment row.\n * Rejects with the underlying error (item's `status` becomes\n * `'error'`); aborts surface as a DOMException('AbortError') and the\n * item's status becomes `'cancelled'`.\n */\n upload: (input: AttachmentUploadInput) => Promise<Attachment>;\n /**\n * Enqueue many at once — drag-and-drop, multi-file picker. Items run\n * in parallel (the SDK is per-call independent). Resolves with the\n * attachments in the same order as the input; if any item fails the\n * whole promise rejects after the others settle.\n */\n uploadAll: (inputs: AttachmentUploadInput[]) => Promise<Attachment[]>;\n /** Abort an in-flight upload. Sets the item's status to `cancelled`. No-op if not in flight. */\n cancel: (localId: string) => void;\n /** Drop an item from the queue. Cancels first if it's still in flight. */\n remove: (localId: string) => void;\n /** Drop everything + abort any in-flight uploads. */\n reset: () => void;\n}\n\ninterface InFlight {\n controller: AbortController;\n}\n\n/**\n * Stateful wrapper around `chat.attachments.upload`. Exposes a queue\n * of in-flight / completed uploads with per-item progress + per-item\n * cancel — drag-and-drop, multi-file picker, retry chips, all without\n * the host app reimplementing AbortController plumbing.\n *\n * ```tsx\n * const { upload, queue, cancel, remove } = useAttachmentUpload();\n * const onPick = async (files: File[]) => {\n * const atts = await uploadAll(files.map(f => ({\n * body: f, contentType: f.type, byteSize: f.size, filename: f.name\n * })));\n * await chat.conversations.one(convId).messages.send({\n * body: '', attachment_ids: atts.map(a => a.id),\n * });\n * };\n * ```\n *\n * The legacy `upload(input)` → `Promise<Attachment>` shape is preserved\n * so older callers keep working — they just won't render the queue UI.\n */\nexport function useAttachmentUpload(): UseAttachmentUploadState {\n const chat = usePoolse();\n const [queue, setQueue] = useState<UploadItem[]>([]);\n const inFlightRef = useRef<Map<string, InFlight>>(new Map());\n // Track mount status so async resolves don't setState on unmounted\n // components. Strict-mode double-effects re-arm this on remount.\n const mountedRef = useRef(true);\n useEffect(() => {\n mountedRef.current = true;\n return () => {\n mountedRef.current = false;\n // Reading inFlightRef at cleanup time is the point: we abort\n // whatever is uploading *now*. The lint rule's usual advice —\n // snapshot the ref inside the effect — would capture the empty\n // map from mount and abort nothing.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n for (const v of inFlightRef.current.values()) v.controller.abort();\n inFlightRef.current.clear();\n };\n }, []);\n\n const updateItem = useCallback((localId: string, patch: Partial<UploadItem>) => {\n if (!mountedRef.current) return;\n setQueue((q) => q.map((it) => (it.localId === localId ? { ...it, ...patch } : it)));\n }, []);\n\n const runUpload = useCallback(\n async (localId: string, input: AttachmentUploadInput): Promise<Attachment> => {\n const controller = new AbortController();\n inFlightRef.current.set(localId, { controller });\n updateItem(localId, { status: 'uploading', loaded: 0 });\n try {\n const att = await chat.attachments.upload(input, {\n signal: controller.signal,\n onProgress: (e) => updateItem(localId, { loaded: e.loaded }),\n });\n updateItem(localId, {\n status: 'ready',\n loaded: input.byteSize,\n attachment: att,\n error: null,\n });\n return att;\n } catch (err) {\n if ((err as DOMException)?.name === 'AbortError') {\n updateItem(localId, { status: 'cancelled' });\n throw err;\n }\n const e = err instanceof Error ? err : new Error(String(err));\n updateItem(localId, { status: 'error', error: e });\n throw e;\n } finally {\n inFlightRef.current.delete(localId);\n }\n },\n [chat, updateItem],\n );\n\n const enqueue = useCallback((input: AttachmentUploadInput): UploadItem => {\n const localId = generateLocalId();\n const item: UploadItem = {\n localId,\n filename: input.filename ?? 'file',\n contentType: input.contentType,\n byteSize: input.byteSize,\n status: 'pending',\n loaded: 0,\n attachment: null,\n error: null,\n };\n setQueue((q) => [...q, item]);\n return item;\n }, []);\n\n const upload = useCallback(\n (input: AttachmentUploadInput): Promise<Attachment> => {\n const item = enqueue(input);\n return runUpload(item.localId, input);\n },\n [enqueue, runUpload],\n );\n\n const uploadAll = useCallback(\n (inputs: AttachmentUploadInput[]): Promise<Attachment[]> => {\n // Enqueue all first so the UI shows the full queue immediately,\n // then start the PUTs in parallel. Order in resolved array\n // matches input order regardless of which PUT finishes first.\n const items = inputs.map((inp) => ({ item: enqueue(inp), input: inp }));\n return Promise.all(items.map(({ item, input }) => runUpload(item.localId, input)));\n },\n [enqueue, runUpload],\n );\n\n const cancel = useCallback((localId: string) => {\n const inf = inFlightRef.current.get(localId);\n if (inf) inf.controller.abort();\n }, []);\n\n const remove = useCallback((localId: string) => {\n const inf = inFlightRef.current.get(localId);\n if (inf) inf.controller.abort();\n setQueue((q) => q.filter((it) => it.localId !== localId));\n }, []);\n\n const reset = useCallback(() => {\n for (const v of inFlightRef.current.values()) v.controller.abort();\n inFlightRef.current.clear();\n setQueue([]);\n }, []);\n\n const uploading = queue.some((it) => it.status === 'pending' || it.status === 'uploading');\n // Last error in queue order — pendings/readies have null, so the\n // most recently transitioned-to-error item wins.\n const error = queue.reduce<Error | null>((acc, it) => it.error ?? acc, null);\n // Last ready attachment — same convenience.\n const attachment = queue.reduce<Attachment | null>((acc, it) => it.attachment ?? acc, null);\n\n return { queue, attachment, uploading, error, upload, uploadAll, cancel, remove, reset };\n}\n\nfunction generateLocalId(): string {\n return safeUuid();\n}\n","import type { Uuid } from '@poolse/sdk';\nimport { useEffect, useState } from 'react';\nimport { usePoolse } from './provider.js';\n\ninterface UseAttachmentUrlState {\n /** Presigned GET URL, or null while loading / on error. */\n url: string | null;\n loading: boolean;\n error: Error | null;\n}\n\n/**\n * Resolve an attachment's presigned download URL. Pass `null` to\n * skip the fetch — useful in routing-driven views where the id may\n * not be known yet.\n *\n * Doesn't auto-refresh: the server's URL TTL is ~1 hour and most\n * UI lifetimes are much shorter. If you do need a refresh (long-lived\n * dashboard, etc.), remount the hook or wrap it in a parent that\n * re-keys on a timer.\n *\n * ```tsx\n * const { url } = useAttachmentUrl(message.custom_data?.attachment_id ?? null);\n * return url ? <img src={url} /> : <Spinner />;\n * ```\n */\nexport function useAttachmentUrl(attachmentId: Uuid | null): UseAttachmentUrlState {\n const chat = usePoolse();\n const [url, setUrl] = useState<string | null>(null);\n const [loading, setLoading] = useState(attachmentId !== null);\n const [error, setError] = useState<Error | null>(null);\n\n useEffect(() => {\n if (attachmentId === null) {\n setUrl(null);\n setLoading(false);\n setError(null);\n return;\n }\n let cancelled = false;\n const controller = new AbortController();\n setLoading(true);\n setError(null);\n chat.attachments\n .one(attachmentId)\n .downloadUrl({ signal: controller.signal })\n .then((res) => {\n if (cancelled) return;\n setUrl(res.url);\n setLoading(false);\n })\n .catch((err: unknown) => {\n if (cancelled) return;\n if ((err as DOMException)?.name === 'AbortError') return;\n setError(err instanceof Error ? err : new Error(String(err)));\n setLoading(false);\n });\n return () => {\n cancelled = true;\n controller.abort();\n };\n }, [chat, attachmentId]);\n\n return { url, loading, error };\n}\n","// React binding over `chat.users.get(externalId)`.\n//\n// Uses plain useState + useEffect (NOT `useSyncExternalStore`).\n// useSyncExternalStore reaches into React internals and surfaces\n// any latent React-duplication immediately as \"Invalid hook call\".\n// The pattern below works the same way for our purposes — read\n// from the cache on mount, subscribe for updates, update state —\n// without that fragility.\n\nimport type { PoolseUserProfile } from '@poolse/sdk';\nimport { useEffect, useState } from 'react';\nimport { usePoolse } from './provider.js';\n\nexport interface UseUserState {\n /** Resolved profile, or null when the resolver returned null / errored / isn't configured. */\n profile: PoolseUserProfile | null;\n /** True while the SDK is mid-fetch (or before the first fetch fires). */\n loading: boolean;\n}\n\nconst EMPTY: UseUserState = { profile: null, loading: false };\n\n/**\n * Resolve the tenant's `external_id` (your own user id) to\n * `{ displayName, avatarUrl }` via the configured `userResolver`.\n *\n * Returns `{ profile: null, loading: false }` when:\n * * no resolver is configured\n * * resolver returned null (user not found)\n * * resolver threw (logged once, then cached as null)\n *\n * Pass `null` / empty string to opt out (the hook becomes a no-op).\n * Useful for self bubbles (you already know who you are).\n */\nexport function useUser(externalId: string | null | undefined): UseUserState {\n const chat = usePoolse();\n const [state, setState] = useState<UseUserState>(() => {\n if (!externalId) return EMPTY;\n const cached = chat.users.peek(externalId);\n if (cached === undefined) return { profile: null, loading: true };\n return { profile: cached, loading: false };\n });\n\n useEffect(() => {\n if (!externalId) {\n setState(EMPTY);\n return;\n }\n\n const apply = () => {\n const cached = chat.users.peek(externalId);\n if (cached === undefined) {\n setState({ profile: null, loading: true });\n void chat.users.get(externalId);\n } else {\n setState({ profile: cached, loading: false });\n }\n };\n\n const off = chat.users.subscribe(externalId, apply);\n apply();\n return off;\n }, [chat, externalId]);\n\n return state;\n}\n","// Bubble grouping + day-separator helpers — extracted from\n// ConversationView so they're testable in isolation and reusable\n// if a customer rolls their own message-list layout.\n\nimport { isCallLogMessage, type Message } from '@poolse/sdk';\n\n/**\n * Where this message sits inside a same-sender, same-day, in-window\n * cluster. Drives the bubble's corner treatment + the row's\n * inter-cluster margin.\n *\n * * `standalone` — single bubble, gets the tail\n * * `first` — first of multi; all corners rounded\n * * `middle` — interior; all corners rounded\n * * `last` — last of multi; gets the tail\n */\nexport type GroupPosition = 'first' | 'middle' | 'last' | 'standalone';\n\nexport function computeGroupPosition(\n msg: Message,\n prev: Message | null,\n next: Message | null,\n windowMs: number,\n): GroupPosition {\n const continuesPrev = sameGroup(msg, prev, windowMs);\n const continuesNext = sameGroup(next, msg, windowMs);\n if (continuesPrev && continuesNext) return 'middle';\n if (continuesPrev) return 'last';\n if (continuesNext) return 'first';\n return 'standalone';\n}\n\nexport function sameGroup(a: Message | null, b: Message | null, windowMs: number): boolean {\n if (!a || !b) return false;\n // Call-log rows are centered separator-like lines, never part of a\n // bubble cluster — and they must not glue the bubbles around them\n // together either.\n if (isCallLogMessage(a) || isCallLogMessage(b)) return false;\n if (a.sender_id !== b.sender_id) return false;\n if (!sameDay(a.inserted_at, b.inserted_at)) return false;\n const ta = new Date(a.inserted_at).getTime();\n const tb = new Date(b.inserted_at).getTime();\n return Math.abs(ta - tb) <= windowMs;\n}\n\nexport function sameDay(a: string, b: string): boolean {\n const da = new Date(a);\n const db = new Date(b);\n return (\n da.getFullYear() === db.getFullYear() &&\n da.getMonth() === db.getMonth() &&\n da.getDate() === db.getDate()\n );\n}\n\n/**\n * \"Today\" / \"Yesterday\" / \"Mon, 26 May\" / \"26 May 2024\" — same\n * convention as iMessage / WhatsApp / Telegram. `now` is exposed\n * for deterministic testing; defaults to the current wall clock.\n */\nexport function formatDayLabel(iso: string, now: Date = new Date()): string {\n const d = new Date(iso);\n const startOfDay = (x: Date) => new Date(x.getFullYear(), x.getMonth(), x.getDate()).getTime();\n const diffDays = Math.floor((startOfDay(now) - startOfDay(d)) / 86_400_000);\n if (diffDays === 0) return 'Today';\n if (diffDays === 1) return 'Yesterday';\n if (diffDays < 7) {\n return d.toLocaleDateString(undefined, { weekday: 'long' });\n }\n if (d.getFullYear() === now.getFullYear()) {\n return d.toLocaleDateString(undefined, { weekday: 'short', day: 'numeric', month: 'short' });\n }\n return d.toLocaleDateString(undefined, { day: 'numeric', month: 'short', year: 'numeric' });\n}\n","import type {\n CallDevice,\n CallDeviceKind,\n CallParticipant,\n CallRoomStatus,\n CameraFacing,\n LiveKitModule,\n} from '@poolse/sdk';\nimport { CallRoom } from '@poolse/sdk';\nimport { useCallback, useEffect, useMemo, useRef, useState } from 'react';\n\nimport { usePoolse } from './provider.js';\n\nexport interface UseCallRoomOptions {\n /**\n * `livekit-client`, imported by your app:\n *\n * import * as livekit from 'livekit-client';\n *\n * Passed in rather than imported by the SDK because Metro bundles from\n * the static import graph and cannot follow the `require` that tsup\n * emits — a dependency the SDK imports for itself never reaches a\n * React Native bundle.\n */\n livekit: LiveKitModule;\n /** Publish the camera on join. An audio call starts with it off. */\n video?: boolean;\n /** Join muted. */\n muted?: boolean;\n /** Which camera to open with. Defaults to the front one. */\n facing?: CameraFacing;\n /**\n * How long the last participant may sit alone before {@link\n * UseCallRoom.alone} turns true, in milliseconds. Defaults to 1500.\n * Pass `0` to never report it.\n */\n aloneGraceMs?: number;\n}\n\nexport interface UseCallRoom {\n status: CallRoomStatus;\n /** Everyone on the call, the local participant first. */\n participants: CallParticipant[];\n cameraEnabled: boolean;\n micEnabled: boolean;\n /** Which camera is publishing. Meaningless while the camera is off. */\n facingMode: CameraFacing;\n /**\n * Selectable devices, refreshed as they are plugged in and removed.\n *\n * The web's answer to a phone's speaker button — a laptop has no\n * earpiece, but it does have several microphones and a pair of\n * headphones, and choosing between them is the same job. Sparse on\n * React Native, where routing goes through the platform audio session\n * instead (see `useCallAudio` in `@poolse/react-native`).\n */\n devices: Record<CallDeviceKind, CallDevice[]>;\n /** Device id in use per kind, where the platform reports one. */\n activeDevices: Partial<Record<CallDeviceKind, string>>;\n /** Move the call onto another camera, microphone or output. */\n selectDevice: (kind: CallDeviceKind, deviceId: string) => Promise<void>;\n /**\n * Re-read the device list.\n *\n * Called for you on connect and whenever devices change, so this is\n * for the case neither covers: a browser only reveals device ids and\n * labels once the page holds a matching permission, and the moment\n * that permission lands is not an event you can subscribe to. Call it\n * when opening a picker and the list will be right by the time it is\n * on screen.\n */\n refreshDevices: () => void;\n /**\n * Everyone else has gone and is not coming back.\n *\n * Turns true only after somebody else has actually been on the call,\n * so the caller waiting for an answer never trips it. Wire it to your\n * hang-up path — a peer whose app was killed or whose phone lost\n * signal sends no `call:hangup`, and without this the survivor is\n * left on a call screen that will never close on its own.\n *\n * useEffect(() => {\n * if (media.alone) void calls.hangUp();\n * }, [media.alone]);\n */\n alone: boolean;\n error: Error | null;\n /**\n * Whether this deployment has an SFU.\n *\n * `null` until a join has been attempted, then `false` if the API\n * answered 503. A `false` here is not a failure — it means fall back\n * to `useVoiceRoom`, which is how every call worked before the SFU.\n */\n sfuAvailable: boolean | null;\n /** Connect. Resolves `false` when there is no SFU. */\n join: () => Promise<boolean>;\n leave: () => void;\n setCameraEnabled: (enabled: boolean) => Promise<void>;\n toggleCamera: () => Promise<void>;\n /** Swap between the front and rear cameras. */\n switchCamera: () => Promise<void>;\n setMicrophoneEnabled: (enabled: boolean) => Promise<void>;\n toggleMic: () => Promise<void>;\n}\n\n/**\n * A call's media, carried by the SFU.\n *\n * Media only. Ringing, accept/decline/hangup and the poolse roster stay\n * with `useCalls` and `useVoiceRoom`; this is what people sound and look\n * like. A call screen normally uses both.\n *\n * const media = useCallRoom(conversationId, { livekit, video: true });\n * await media.join();\n * await media.toggleCamera();\n *\n * Both the camera and the microphone can be turned on and off at any\n * point during the call — that is the SFU's doing, since renegotiating a\n * live connection is exactly what the peer-to-peer mesh cannot do.\n */\nexport function useCallRoom(conversationId: string | null, opts: UseCallRoomOptions): UseCallRoom {\n const poolse = usePoolse();\n\n const [status, setStatus] = useState<CallRoomStatus>('idle');\n const [participants, setParticipants] = useState<CallParticipant[]>([]);\n const [cameraEnabled, setCamera] = useState(false);\n const [micEnabled, setMic] = useState(false);\n const [facingMode, setFacing] = useState<CameraFacing>(opts.facing ?? 'user');\n const [alone, setAlone] = useState(false);\n const [devices, setDevices] = useState<Record<CallDeviceKind, CallDevice[]>>({\n videoinput: [],\n audioinput: [],\n audiooutput: [],\n });\n const [activeDevices, setActiveDevices] = useState<Partial<Record<CallDeviceKind, string>>>({});\n const [error, setError] = useState<Error | null>(null);\n const [sfuAvailable, setSfuAvailable] = useState<boolean | null>(null);\n\n // Kept current, but read only when a room is built.\n //\n // This used to pin the FIRST value, which quietly broke every video\n // call. The options are an inline object literal, so pinning avoided\n // rebuilding the room on each render — but a call screen mounts long\n // before a call exists, and at that point `video` is false because\n // nothing is ringing yet. The room was then constructed later, on the\n // conversation id arriving, from options captured when there was no\n // call: audio, always. Cameras never opened on a video call and the\n // toggle looked broken.\n //\n // Assigning during render keeps the ref current without triggering\n // one, and the memo below still only reads it when it actually\n // constructs a room — so nothing rebuilds per render either.\n const optsRef = useRef(opts);\n optsRef.current = opts;\n\n // Whether THIS hook holds the room. Leaving without having joined\n // would release a claim we never made.\n const joined = useRef(false);\n\n /**\n * The room this hook is currently responsible for.\n *\n * Connecting takes time, and a call can end during it — the far side\n * hangs up, the user navigates away, the conversation changes. When\n * that happened the effect's cleanup ran while `joined` was still\n * false, because `join()` had not resolved yet, so nothing released\n * the room. The connection then completed into a room no component\n * held: audio flowing, no UI, and no way to hang it up.\n *\n * Comparing against this on resolve is what closes that window.\n */\n const held = useRef<CallRoom | null>(null);\n\n const room = useMemo(() => {\n if (!conversationId) return null;\n\n return poolse.call(conversationId, {\n livekit: optsRef.current.livekit,\n ...(optsRef.current.video !== undefined ? { video: optsRef.current.video } : {}),\n ...(optsRef.current.muted !== undefined ? { muted: optsRef.current.muted } : {}),\n ...(optsRef.current.facing !== undefined ? { facing: optsRef.current.facing } : {}),\n ...(optsRef.current.aloneGraceMs !== undefined\n ? { aloneGraceMs: optsRef.current.aloneGraceMs }\n : {}),\n });\n }, [poolse, conversationId]);\n\n // Track state changes that originate below React — a camera that\n // failed to start, or the SFU dropping us — rather than assuming our\n // last call succeeded.\n const refreshDevices = useCallback((target: CallRoom) => {\n void Promise.all([\n target.listDevices('videoinput'),\n target.listDevices('audioinput'),\n target.listDevices('audiooutput'),\n ]).then(([videoinput, audioinput, audiooutput]) => {\n setDevices({ videoinput, audioinput, audiooutput });\n\n // Built by omission rather than by assigning undefined: under\n // `exactOptionalPropertyTypes` a present-but-undefined key is not\n // the same as an absent one, and \"the platform does not report\n // this\" is genuinely absence.\n const active: Partial<Record<CallDeviceKind, string>> = {};\n for (const kind of ['videoinput', 'audioinput', 'audiooutput'] as const) {\n const id = target.getActiveDevice(kind);\n if (id) active[kind] = id;\n }\n setActiveDevices(active);\n });\n }, []);\n\n const sync = useCallback((target: CallRoom | null) => {\n if (!target) return;\n setCamera(target.isCameraEnabled());\n setMic(target.isMicrophoneEnabled());\n setFacing(target.getFacingMode());\n }, []);\n\n useEffect(() => {\n if (!room) {\n setStatus('idle');\n setParticipants([]);\n return;\n }\n\n setStatus(room.getStatus());\n setParticipants(room.getParticipants());\n\n held.current = room;\n\n // Latched rather than pulsed: a consumer that hangs up in an effect\n // needs the signal to survive until it has been read, and a call\n // that has been abandoned is never un-abandoned.\n setAlone(false);\n\n const offStatus = room.onStatus(setStatus);\n const offRoster = room.onParticipants((next) => {\n setParticipants(next);\n sync(room);\n });\n const offAlone = room.onAlone(() => setAlone(true));\n\n const offDevices = room.onDevices(() => refreshDevices(room));\n const offError = room.onError(setError);\n\n return () => {\n offStatus();\n offRoster();\n offAlone();\n offDevices();\n offError();\n held.current = null;\n // Unmounting mid-call must disconnect, or the SFU keeps publishing\n // a participant nobody is behind.\n if (joined.current) {\n joined.current = false;\n room.leave();\n }\n };\n }, [room, sync, refreshDevices]);\n\n const join = useCallback(async (): Promise<boolean> => {\n const target = room;\n if (!target) return false;\n setError(null);\n\n try {\n const connected = await target.join();\n\n // Superseded while connecting. Release it here — the cleanup that\n // would normally have done so already ran, and found nothing to\n // release because this promise had not resolved yet.\n if (held.current !== target) {\n if (connected) target.leave();\n return false;\n }\n\n joined.current = connected;\n setSfuAvailable(connected);\n sync(target);\n // Only once connected: enumerating before the call holds its\n // permissions gives a list of unlabelled placeholders.\n if (connected) refreshDevices(target);\n return connected;\n } catch (err) {\n setError(err instanceof Error ? err : new Error(String(err)));\n // A thrown join is a real failure, not a missing SFU — the caller\n // should surface it rather than quietly falling back.\n setSfuAvailable(true);\n return false;\n }\n }, [room, sync, refreshDevices]);\n\n const leave = useCallback(() => {\n if (!joined.current) return;\n joined.current = false;\n room?.leave();\n }, [room]);\n\n const setCameraEnabled = useCallback(\n async (enabled: boolean) => {\n if (!room) return;\n await room.setCameraEnabled(enabled);\n sync(room);\n },\n [room, sync],\n );\n\n const setMicrophoneEnabled = useCallback(\n async (enabled: boolean) => {\n if (!room) return;\n await room.setMicrophoneEnabled(enabled);\n sync(room);\n },\n [room, sync],\n );\n\n // Read the live value rather than the rendered one: a toggle fired\n // twice quickly would otherwise both read the same stale state and\n // end up where it started.\n const toggleCamera = useCallback(async () => {\n if (!room) return;\n await setCameraEnabled(!room.isCameraEnabled());\n }, [room, setCameraEnabled]);\n\n const toggleMic = useCallback(async () => {\n if (!room) return;\n await setMicrophoneEnabled(!room.isMicrophoneEnabled());\n }, [room, setMicrophoneEnabled]);\n\n const switchCamera = useCallback(async () => {\n if (!room) return;\n await room.switchCamera();\n setFacing(room.getFacingMode());\n }, [room]);\n\n const refresh = useCallback(() => {\n if (room) refreshDevices(room);\n }, [room, refreshDevices]);\n\n const selectDevice = useCallback(\n async (kind: CallDeviceKind, deviceId: string) => {\n if (!room) return;\n await room.setActiveDevice(kind, deviceId);\n setActiveDevices((current) => ({\n ...current,\n [kind]: room.getActiveDevice(kind) ?? deviceId,\n }));\n },\n [room],\n );\n\n return {\n status,\n participants,\n cameraEnabled,\n micEnabled,\n facingMode,\n alone,\n devices,\n activeDevices,\n refreshDevices: refresh,\n error,\n sfuAvailable,\n join,\n leave,\n setCameraEnabled,\n toggleCamera,\n switchCamera,\n selectDevice,\n setMicrophoneEnabled,\n toggleMic,\n };\n}\n","import { useEffect, useRef, useState } from 'react';\n\nexport interface AloneWatchOptions {\n /** Whether the call is actually carrying media right now. */\n active: boolean;\n /** How many OTHER people are on the call — excluding yourself. */\n others: number;\n /** Grace period before the verdict. `0` disables the watch. */\n graceMs: number;\n}\n\n/**\n * Report when this client is the last one left on a call.\n *\n * The mesh's counterpart to `CallRoom`'s built-in check. It lives here\n * rather than in `VoiceRoom` because the mesh's roster arrives as\n * presence on poolse's own channel, which the hook already holds — and\n * duplicating the subscription inside the SDK to watch a number the\n * hook can see would buy nothing.\n *\n * Two guards, both load-bearing:\n *\n * * Nobody has to have been here — `seenPeer` — before an empty room\n * counts as abandonment. Otherwise the caller who connects first,\n * alone by definition until the callee joins, ends their own call.\n * * The verdict waits out `graceMs`, so two people hanging up in the\n * same tick, or a reconnect that briefly empties presence, does not\n * read as everyone walking out.\n *\n * Latches once true: a consumer hanging up in an effect needs the\n * signal to survive being read, and an abandoned call is never\n * un-abandoned. Resets when the call goes inactive.\n */\nexport function useAloneWatch({ active, others, graceMs }: AloneWatchOptions): boolean {\n const [alone, setAlone] = useState(false);\n const seenPeer = useRef(false);\n\n useEffect(() => {\n if (!active) {\n seenPeer.current = false;\n setAlone(false);\n return;\n }\n\n if (others > 0) {\n seenPeer.current = true;\n return;\n }\n\n if (graceMs <= 0 || !seenPeer.current) return;\n\n const timer = setTimeout(() => setAlone(true), graceMs);\n // Cleared by the next run whenever `others` changes, so somebody\n // rejoining inside the grace period cancels the verdict.\n return () => clearTimeout(timer);\n }, [active, others, graceMs]);\n\n return alone;\n}\n","import type { VoiceParticipant, VoiceRoomOptions, VoiceStatus } from '@poolse/sdk';\nimport { useCallback, useEffect, useMemo, useRef, useState } from 'react';\nimport { useAloneWatch } from './internal/alone-watch.js';\nimport { usePoolse } from './provider.js';\n\nexport interface UseVoiceRoom {\n status: VoiceStatus;\n /** Everyone currently in the room, oldest join first. */\n participants: VoiceParticipant[];\n muted: boolean;\n /**\n * Everyone else has left and is not coming back.\n *\n * The mesh equivalent of `useCallRoom`'s flag of the same name — see\n * there for why a call needs this on top of the explicit hang-up\n * signal. Only meaningful for a room being used to carry a call; a\n * Discord-style room you sit in alone is a normal state, so wire this\n * to hang-up only on the call surface.\n */\n alone: boolean;\n error: Error | null;\n /** Acquire the mic and connect. Safe to call twice. */\n join: () => Promise<void>;\n leave: () => void;\n toggleMute: () => void;\n}\n\n/**\n * Discord-style voice room for a conversation: join, see who else is\n * in, watch who's talking, mute yourself.\n *\n * The room is torn down when the conversation changes or the component\n * unmounts, so a navigation away hangs up rather than leaving a phantom\n * participant behind.\n *\n * const voice = useVoiceRoom(conversationId);\n * <Button onPress={voice.join} title=\"Join Voice\" />\n *\n * For ringing someone who hasn't joined yet, see `useCalls`.\n */\nexport function useVoiceRoom(\n conversationId: string | null,\n opts: VoiceRoomOptions & {\n /** Grace before {@link UseVoiceRoom.alone}. Defaults to 1500; `0` disables. */\n aloneGraceMs?: number;\n } = {},\n): UseVoiceRoom {\n const poolse = usePoolse();\n\n const [status, setStatus] = useState<VoiceStatus>('idle');\n const [participants, setParticipants] = useState<VoiceParticipant[]>([]);\n const [muted, setMuted] = useState(false);\n const [error, setError] = useState<Error | null>(null);\n\n // Options are usually an inline object literal, which would re-run\n // the subscribe effect on every render. Pin them to the first value:\n // ICE servers and the WebRTC adapter don't meaningfully change for\n // the lifetime of a room.\n const optsRef = useRef(opts);\n\n // Whether THIS hook holds the room open. The SDK hands out one room\n // per conversation and counts holders, so leaving without having\n // joined would release someone else's claim — a call screen unmounting\n // would cut the audio out from under a voice bar in the same\n // conversation.\n const joined = useRef(false);\n\n /**\n * The room this hook is responsible for right now.\n *\n * Same window as `useCallRoom`: a call that ends while the room is\n * still connecting ran its cleanup before `join()` resolved, so\n * nothing released the room and it finished connecting with no\n * component behind it — audio with no UI.\n */\n const held = useRef<ReturnType<typeof poolse.realtime.voice> | null>(null);\n\n const room = useMemo(\n () => (conversationId ? poolse.realtime.voice(conversationId, optsRef.current) : null),\n [poolse, conversationId],\n );\n\n useEffect(() => {\n if (!room) return;\n\n held.current = room;\n setStatus(room.getStatus());\n setParticipants(room.getParticipants());\n setMuted(room.isMuted());\n\n const offStatus = room.onStatus(setStatus);\n const offRoster = room.onParticipants(setParticipants);\n const offError = room.onError(setError);\n\n return () => {\n offStatus();\n offRoster();\n offError();\n held.current = null;\n // Leaving on unmount is deliberate: the server only broadcasts\n // `voice:left` on an explicit leave, so skipping it would strand\n // us in everyone else's roster. Only release a claim we made.\n if (joined.current) {\n joined.current = false;\n room.leave();\n }\n };\n }, [room]);\n\n const join = useCallback(async () => {\n const target = room;\n if (!target) return;\n setError(null);\n try {\n await target.join();\n\n // Superseded while connecting — release it rather than leaving a\n // room nobody holds. See `held`.\n if (held.current !== target) {\n target.leave();\n return;\n }\n joined.current = true;\n } catch (err) {\n setError(err instanceof Error ? err : new Error(String(err)));\n }\n }, [room]);\n\n const leave = useCallback(() => {\n if (!joined.current) return;\n joined.current = false;\n room?.leave();\n }, [room]);\n\n const toggleMute = useCallback(() => {\n if (!room) return;\n setMuted(room.toggleMute());\n }, [room]);\n\n // `participants` includes the local participant, so anyone else is\n // whatever is left over.\n const alone = useAloneWatch({\n active: status === 'connected',\n others: Math.max(0, participants.length - 1),\n graceMs: optsRef.current.aloneGraceMs ?? 1500,\n });\n\n return { status, participants, muted, alone, error, join, leave, toggleMute };\n}\n","import type { CallMedia, IncomingCall, OutgoingCall } from '@poolse/sdk';\nimport { useCallback, useEffect, useMemo, useRef, useState } from 'react';\nimport { usePoolse } from './provider.js';\n\n/** Where a call is in its lifecycle, from this device's point of view. */\nexport type CallPhase =\n | 'idle'\n /** We placed a call and are waiting for an answer. */\n | 'ringing-out'\n /** Someone is ringing us. */\n | 'ringing-in'\n /** Both sides agreed; the voice room should be joined now. */\n | 'active'\n /** The far side said no. */\n | 'declined'\n /** The person we called is already on another call. */\n | 'busy'\n /** Nobody picked up before the ring timeout elapsed. */\n | 'timed-out';\n\nexport interface UseCallsOptions {\n /**\n * How long a ring may go unanswered, in milliseconds, before it is\n * given up on. Defaults to 45s, roughly what the mainstream call apps\n * use. Pass `0` to ring indefinitely.\n *\n * The server deliberately holds no timer — only the UI knows when it\n * stopped waiting — so this is what actually ends an unanswered call.\n * Both directions are covered: an outbound ring cancels itself, and an\n * inbound one gives up too, otherwise a caller that crashed mid-ring\n * would leave the callee's phone ringing forever.\n */\n ringTimeoutMs?: number;\n}\n\nexport interface UseCalls {\n phase: CallPhase;\n /** Set while `phase` is `ringing-in`. */\n incoming: IncomingCall | null;\n /** Set while `phase` is `ringing-out` or `active`. */\n outgoing: OutgoingCall | null;\n /**\n * Conversation whose voice room should be joined once `phase` turns\n * `active` — the same id for both caller and callee.\n */\n activeConversationId: string | null;\n /**\n * What the current call opened as.\n *\n * `'audio'` when nothing is in flight. Either side can still turn\n * their camera on mid-call — this is what was rung, which is what the\n * incoming UI has to commit to before the user answers.\n */\n media: CallMedia;\n error: Error | null;\n /** Ring every other member of a conversation. */\n call: (conversationId: string, media?: CallMedia) => Promise<void>;\n /**\n * Register a ring that arrived by some route other than the socket —\n * in practice a VoIP push.\n *\n * Without this the push path shows a ring the state machine knows\n * nothing about, and every signal that ends a call is guarded on\n * state the machine never had: the caller hanging up sent\n * `call:cancelled`, the guard found no matching `incoming`, and the\n * callee's phone rang on until its own timeout.\n *\n * Idempotent per call id, because the socket almost always delivers\n * the same call a moment later — that is one ring arriving twice, not\n * a second caller.\n */\n ring: (call: IncomingCall) => void;\n /**\n * A call was torn down from outside this state machine.\n *\n * The counterpart to {@link ring}: the caller withdrew, or the call\n * ended, and the news reached this device as a VoIP push rather than\n * over the socket — which is the normal case for a phone that was\n * asleep when the ring arrived and whose socket may not be up yet.\n *\n * Ignores call ids this client is not in, so a teardown for a\n * previous call cannot end the current one.\n */\n dropped: (callId: string) => void;\n /**\n * Answer the inbound ring.\n *\n * Pass the call explicitly when it didn't arrive over the socket — a\n * VoIP push can launch the app cold, in which case this hook has no\n * `incoming` state and the push payload is the only source of truth.\n */\n accept: (call?: IncomingCall) => Promise<void>;\n /** Reject the inbound ring. Takes an explicit call for the same\n * cold-launch reason as {@link accept}. */\n decline: (call?: IncomingCall) => Promise<void>;\n /** Hang up an outbound ring before it's answered. */\n cancel: () => Promise<void>;\n /**\n * End the call, whatever state it is in.\n *\n * The one action a UI's hang-up button should call: it sends the right\n * signal for the current phase — cancel while ringing out, decline\n * while ringing in, hangup once connected — and always returns to\n * idle, even if the signal fails. `reset` alone clears local state\n * only, which leaves the other side in the call.\n */\n hangUp: () => Promise<void>;\n /** Drop back to idle — call after leaving the room, or to clear a\n * `declined` / `busy` / `timed-out` state the UI has finished\n * showing. */\n reset: () => void;\n /**\n * Tell the hook how many OTHER people are currently on the call's\n * media. `hangUp` consults it: with two or more others connected,\n * hanging up just leaves — the call continues without you — and the\n * end-the-call signal is only sent when at most one other remains.\n * Every hang-up path funnels through the hook (the in-call button,\n * CallKit's end event, the OS back gesture), so this is the ONE\n * place group calls are protected from being ended by a leaver.\n */\n reportOthersOnCall: (count: number) => void;\n}\n\n/**\n * WhatsApp-style calling: ring a conversation, show an incoming-call\n * screen, accept or decline.\n *\n * This hook is only the *invitation* half. Audio starts when you join\n * the voice room, which the host app does once `phase` is `active`:\n *\n * const calls = useCalls(myUserId);\n * const voice = useVoiceRoom(calls.activeConversationId);\n *\n * useEffect(() => {\n * if (calls.phase === 'active') void voice.join();\n * }, [calls.phase]);\n *\n * Keeping them separate means a \"join voice\" button and a ringing call\n * share exactly one implementation of the media path.\n */\nexport function useCalls(userId: string | null, opts: UseCallsOptions = {}): UseCalls {\n const ringTimeoutMs = opts.ringTimeoutMs ?? 45_000;\n const poolse = usePoolse();\n\n const [phase, setPhase] = useState<CallPhase>('idle');\n\n // The phase as of the last render, readable from a socket callback\n // without making every subscription depend on it — re-subscribing on\n // each phase change would drop events in the gap.\n const phaseRef = useRef<CallPhase>('idle');\n phaseRef.current = phase;\n const [incoming, setIncoming] = useState<IncomingCall | null>(null);\n const [outgoing, setOutgoing] = useState<OutgoingCall | null>(null);\n const [activeConversationId, setActiveConversationId] = useState<string | null>(null);\n\n /**\n * The id of the call this client is in, once it is in one.\n *\n * Tracked separately because neither `incoming` nor `outgoing`\n * survives being answered — `accept()` clears `incoming`, and a callee\n * never had an `outgoing`. Without this the callee's `hangUp()` had no\n * call id at all and returned before sending anything, so answering a\n * call meant you could never end it for the other side: they sat in a\n * call the app had already left.\n *\n * It is also what makes the socket handlers below able to tell a\n * signal about THIS call from a late one about a previous call.\n */\n const [activeCallId, setActiveCallId] = useState<string | null>(null);\n\n /**\n * What the call in progress opened as.\n *\n * Tracked for the same reason as {@link activeCallId}: `accept()`\n * clears `incoming`, and a callee never had an `outgoing`, so once a\n * call was answered there was nothing left to read the media type\n * from and it fell back to `'audio'`. The callee's room was then\n * built for an audio call and never opened the camera — so on a video\n * call the caller's camera came on and the callee's did not, which\n * reads as the default being random when it is really \"whichever end\n * you were on\".\n */\n const [activeMedia, setActiveMedia] = useState<CallMedia | null>(null);\n const [error, setError] = useState<Error | null>(null);\n\n // Same reason as `phaseRef`: the handlers are bound once, and must be\n // able to ask \"is this signal about the call I am in?\" without\n // re-subscribing on every state change.\n const incomingRef = useRef<IncomingCall | null>(null);\n incomingRef.current = incoming;\n const outgoingRef = useRef<OutgoingCall | null>(null);\n outgoingRef.current = outgoing;\n const activeCallIdRef = useRef<string | null>(null);\n activeCallIdRef.current = activeCallId;\n\n /** Is this signal about the call this client is currently in? */\n const isCurrent = useCallback((callId: string) => {\n return (\n callId === activeCallIdRef.current ||\n callId === incomingRef.current?.callId ||\n callId === outgoingRef.current?.callId\n );\n }, []);\n\n /**\n * Who has said no to the outbound call, and how.\n *\n * A group ring is not over because one person waved it away. Everyone\n * still has a phone ringing, and ending the call on the first refusal\n * hangs up on all of them. So refusals accumulate here and the call\n * only ends once nobody is left who might still pick up.\n *\n * Keyed by user id, so the same person's device sending both a busy\n * and a decline counts once.\n */\n const rejectedRef = useRef<Map<string, 'declined' | 'busy'>>(new Map());\n\n /**\n * An accept or decline the user made before the socket resource\n * existed.\n *\n * `useCalls(userId)` builds nothing until it has a user id, and the\n * host app gets that from `useMe()` — a network round trip. A VoIP\n * push launches the app cold and CallKit lets the user answer or\n * refuse immediately, which is comfortably before that request comes\n * back. Both actions then hit `if (!calls) return` and were dropped on\n * the floor: the caller was told nothing and rang on.\n */\n const pendingRef = useRef<{ kind: 'accept' | 'decline'; call: IncomingCall } | null>(null);\n\n // Held in a ref so the timeout effect can reach the current handlers\n // without re-arming the timer every time one of them is recreated —\n // re-arming would silently extend the ring forever.\n const actionsRef = useRef<{ cancel: () => Promise<void>; decline: () => Promise<void> }>({\n cancel: async () => {},\n decline: async () => {},\n });\n\n const calls = useMemo(() => (userId ? poolse.realtime.calls(userId) : null), [poolse, userId]);\n\n /**\n * Apply one callee's refusal to an outbound ring.\n *\n * Ends the call only when there is nobody left it could still be\n * answered by — see {@link rejectedRef}. A server that doesn't report\n * who was rung leaves `calleeUserIds` empty, and then the first\n * refusal ends the call, which is the old behaviour and the right\n * fallback: better to hang up early than to ring forever.\n */\n const reject = useCallback((callId: string, userId: string, kind: 'declined' | 'busy') => {\n // Only a ring can be refused. Once somebody has answered, a decline\n // from a member who never joined is them dropping out of a call that\n // is happily going on without them — not the end of it.\n if (phaseRef.current !== 'ringing-out') return;\n\n const out = outgoingRef.current;\n if (!out || out.callId !== callId) return;\n\n rejectedRef.current.set(userId, kind);\n\n const outstanding = out.calleeUserIds.filter((id) => !rejectedRef.current.has(id));\n if (out.calleeUserIds.length > 0 && outstanding.length > 0) return;\n\n // \"Busy\" and \"declined\" are different sentences to show the user, so\n // a call that everybody was busy for says so; any outright refusal\n // makes it a decline.\n const allBusy = [...rejectedRef.current.values()].every((k) => k === 'busy');\n setPhase(allBusy ? 'busy' : 'declined');\n setOutgoing(null);\n setActiveCallId(null);\n setActiveMedia(null);\n }, []);\n\n useEffect(() => {\n if (!calls) return;\n\n const offIncoming = calls.onIncoming((call) => {\n // The same ring arriving by both routes. A VoIP push gets here\n // first and `ring()` recorded it; the socket then delivers the\n // identical call. Treating that as a second caller would answer\n // the user's own call with `call:busy`.\n if (call.callId === incomingRef.current?.callId) return;\n if (call.callId === activeCallIdRef.current) return;\n\n // One call at a time. A second ring must not replace the screen\n // mid-decision — but it must not vanish silently either, or the\n // second caller can't tell \"busy\" from \"ignoring me\". Answer it\n // automatically so their UI can say so.\n //\n // The decision reads a ref rather than a `setPhase` updater.\n // Updaters must be pure: React runs them during render and may run\n // them more than once, so sending `call:busy` from inside one\n // could reject a call the user was in fact being shown — and did,\n // under StrictMode's double-invoke.\n if (phaseRef.current !== 'idle') {\n void calls.markBusy(call).catch(() => {\n // Best effort: failing to send busy just degrades to the old\n // silence, which must not break the call in progress.\n });\n return;\n }\n setIncoming(call);\n setPhase('ringing-in');\n });\n\n // Every handler below is guarded on the call id. A signal that\n // arrives late, or belongs to a call this client already finished\n // with, must not touch the call it is in now — that is how a live\n // call ended up being torn down by a `call:cancelled` for a\n // different one.\n\n const offAccepted = calls.onAccepted((call) => {\n // Only our own outbound call. Nothing else should move us into a\n // call we did not place.\n if (outgoingRef.current && call.callId !== outgoingRef.current.callId) return;\n setPhase('active');\n setActiveConversationId(call.conversationId);\n setActiveCallId(call.callId);\n });\n\n const offDeclined = calls.onDeclined((call) => {\n if (!isCurrent(call.callId)) return;\n reject(call.callId, call.userId, 'declined');\n });\n\n const offBusy = calls.onBusy((call) => {\n if (!isCurrent(call.callId)) return;\n reject(call.callId, call.userId, 'busy');\n });\n\n // The other side hung up a connected call. Without this the screen\n // stays open on a call that no longer exists.\n const offEnded = calls.onEnded((call) => {\n if (!isCurrent(call.callId)) return;\n setPhase('idle');\n setIncoming(null);\n setOutgoing(null);\n setActiveConversationId(null);\n setActiveCallId(null);\n setActiveMedia(null);\n });\n\n const offCancelled = calls.onCancelled((call) => {\n // Strictly the ring we are showing.\n //\n // This used to fall through to `setPhase('idle')` whenever\n // `incoming` was null — which is precisely the state `accept()`\n // leaves behind. A caller's ring timeout firing as the callee\n // answered would then drop the callee straight out of the call\n // they had just joined, leaving media running with no UI.\n if (call.callId !== incomingRef.current?.callId) return;\n setIncoming(null);\n setPhase('idle');\n setActiveCallId(null);\n setActiveMedia(null);\n });\n\n return () => {\n offIncoming();\n offAccepted();\n offDeclined();\n offBusy();\n offEnded();\n offCancelled();\n };\n }, [calls, isCurrent, reject]);\n\n /**\n * Send whatever the user decided before the socket was ready.\n *\n * Runs the moment `calls` exists — see {@link pendingRef}. The local\n * state was already moved when the action was taken, so this is purely\n * about telling the other side.\n */\n useEffect(() => {\n if (!calls) return;\n const queued = pendingRef.current;\n if (!queued) return;\n pendingRef.current = null;\n\n const sent = queued.kind === 'accept' ? calls.accept(queued.call) : calls.decline(queued.call);\n void sent.catch((err: unknown) => {\n setError(err instanceof Error ? err : new Error(String(err)));\n });\n }, [calls]);\n\n const call = useCallback(\n async (conversationId: string, media: CallMedia = 'audio') => {\n if (!calls) return;\n setError(null);\n // A fresh ring, so nobody has refused it yet. Left over from the\n // previous call, one stale entry could end this one early.\n rejectedRef.current = new Map();\n try {\n const placed = await calls.invite(conversationId, media);\n setOutgoing(placed);\n setActiveCallId(placed.callId);\n setActiveMedia(placed.media);\n setPhase('ringing-out');\n } catch (err) {\n setError(err instanceof Error ? err : new Error(String(err)));\n setPhase('idle');\n }\n },\n [calls],\n );\n\n /**\n * Record a ring that reached us outside the socket. See {@link\n * UseCalls.ring}.\n */\n const ring = useCallback((call: IncomingCall) => {\n // Already showing it, or already in it. Both mean this is the same\n // call arriving twice rather than anything new.\n if (incomingRef.current?.callId === call.callId) return;\n if (activeCallIdRef.current === call.callId) return;\n // Deliberately silent when busy: the socket's `onIncoming` is what\n // sends `call:busy`, and doing it here too would send it twice.\n if (phaseRef.current !== 'idle') return;\n\n setIncoming(call);\n setPhase('ringing-in');\n }, []);\n\n /** See {@link UseCalls.dropped}. */\n const dropped = useCallback(\n (callId: string) => {\n // Whatever was waiting to be sent about THIS call is moot — there\n // is no longer a call to accept or refuse. Checked before the\n // guard below, because taking the action already cleared the\n // state that guard reads: a decline made before the socket was up\n // leaves nothing behind but the queued signal itself.\n if (pendingRef.current?.call.callId === callId) pendingRef.current = null;\n\n if (!isCurrent(callId)) return;\n rejectedRef.current = new Map();\n setPhase('idle');\n setIncoming(null);\n setOutgoing(null);\n setActiveConversationId(null);\n setActiveCallId(null);\n setActiveMedia(null);\n },\n [isCurrent],\n );\n\n const accept = useCallback(\n async (call?: IncomingCall) => {\n const target = call ?? incoming;\n if (!target) return;\n\n // Answered before the socket resource exists — hold it and send it\n // the moment there is somewhere to send it to. Local state still\n // moves, so the UI follows the user rather than the network.\n if (!calls) {\n pendingRef.current = { kind: 'accept', call: target };\n setActiveConversationId(target.conversationId);\n setActiveCallId(target.callId);\n setActiveMedia(target.media);\n setPhase('active');\n setIncoming(null);\n return;\n }\n\n // Local state moves FIRST — the UI follows the user's answer, not\n // the network. Waiting for the server's reply before showing the\n // call meant a slow ack stranded the user on the ring screen with\n // a red \"timed out\" while the call was in fact connecting.\n setActiveConversationId(target.conversationId);\n // Recorded BEFORE `incoming` is cleared — it is the only thing\n // that will still know which call this is once the ring state\n // is gone, and it is what `hangUp` needs to tell the other side.\n setActiveCallId(target.callId);\n setActiveMedia(target.media);\n setPhase('active');\n setIncoming(null);\n\n try {\n await calls.accept(target);\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n // A TIMEOUT is not a verdict: the server usually processed the\n // accept and only the ack was lost. The call proves itself —\n // media connects, or the alone-watch ends it. Showing an error\n // over a working call taught people to ignore errors.\n if (message.includes('timed out')) return;\n // An explicit rejection IS a verdict — the call is gone\n // (withdrawn, rung out, hung up). Stand down.\n setPhase('idle');\n setActiveConversationId(null);\n setActiveCallId(null);\n setActiveMedia(null);\n setError(err instanceof Error ? err : new Error(String(err)));\n }\n },\n [calls, incoming],\n );\n\n const decline = useCallback(\n async (call?: IncomingCall) => {\n const target = call ?? incoming;\n if (!target) return;\n\n // Same as `accept`: refusing a call before the socket is up must\n // still reach the caller, or their phone rings until it times out.\n if (!calls) {\n pendingRef.current = { kind: 'decline', call: target };\n setIncoming(null);\n setActiveCallId(null);\n setActiveMedia(null);\n setPhase('idle');\n return;\n }\n\n try {\n await calls.decline(target);\n } catch (err) {\n setError(err instanceof Error ? err : new Error(String(err)));\n } finally {\n // Local state clears either way: a failed decline shouldn't\n // leave the ring screen stuck on screen.\n setIncoming(null);\n setActiveCallId(null);\n setActiveMedia(null);\n setPhase('idle');\n }\n },\n [calls, incoming],\n );\n\n const cancel = useCallback(async () => {\n if (!calls || !outgoing) return;\n try {\n await calls.cancel(outgoing);\n } catch (err) {\n setError(err instanceof Error ? err : new Error(String(err)));\n } finally {\n setOutgoing(null);\n setActiveCallId(null);\n setActiveMedia(null);\n setPhase('idle');\n }\n }, [calls, outgoing]);\n\n actionsRef.current = { cancel, decline };\n\n // Give up on a ring that nobody answered.\n useEffect(() => {\n if (ringTimeoutMs <= 0) return;\n if (phase !== 'ringing-out' && phase !== 'ringing-in') return;\n\n const outbound = phase === 'ringing-out';\n const timer = setTimeout(() => {\n // Tell the far side before changing local state, so their UI\n // stops ringing too rather than waiting out its own timer.\n void (outbound ? actionsRef.current.cancel() : actionsRef.current.decline()).finally(() => {\n // cancel()/decline() both land on 'idle'; outbound gets a\n // distinct phase so the UI can say \"no answer\" instead of\n // silently dismissing the call.\n if (outbound) setPhase('timed-out');\n });\n }, ringTimeoutMs);\n\n return () => clearTimeout(timer);\n }, [phase, ringTimeoutMs]);\n\n /**\n * End the call and tell the other side.\n *\n * Local state is cleared in `finally` on purpose: a failed signal must\n * never strand the user on a call screen they cannot dismiss.\n */\n const othersOnCallRef = useRef(0);\n const reportOthersOnCall = useCallback((count: number) => {\n othersOnCallRef.current = count;\n }, []);\n\n const hangUp = useCallback(async () => {\n // Leaving a GROUP call is not ending it: walk out quietly and the\n // others keep talking. The signal that tears the call down for\n // everyone is reserved for the last pair.\n if (phaseRef.current === 'active' && othersOnCallRef.current >= 2) {\n setPhase('idle');\n setIncoming(null);\n setOutgoing(null);\n setActiveConversationId(null);\n setActiveCallId(null);\n setActiveMedia(null);\n setError(null);\n return;\n }\n const conversationId =\n activeConversationId ?? incoming?.conversationId ?? outgoing?.conversationId;\n // `activeCallId` first, and that is the whole fix: answering a call\n // clears `incoming`, and a callee never had an `outgoing`, so this\n // used to resolve to undefined and return before signalling. The\n // caller was left in a call the callee had already walked out of.\n const callId = activeCallId ?? incoming?.callId ?? outgoing?.callId;\n\n try {\n if (!calls || !callId || !conversationId) return;\n\n if (phase === 'ringing-out' && outgoing) {\n await calls.cancel(outgoing);\n } else if (phase === 'ringing-in' && incoming) {\n await calls.decline(incoming);\n } else if (phase === 'active') {\n await calls.hangUp({ callId, conversationId });\n }\n } catch (err) {\n setError(err instanceof Error ? err : new Error(String(err)));\n } finally {\n setPhase('idle');\n setIncoming(null);\n setOutgoing(null);\n setActiveConversationId(null);\n setActiveCallId(null);\n setActiveMedia(null);\n }\n }, [calls, phase, incoming, outgoing, activeConversationId, activeCallId]);\n\n const reset = useCallback(() => {\n rejectedRef.current = new Map();\n pendingRef.current = null;\n setPhase('idle');\n setIncoming(null);\n setOutgoing(null);\n setActiveConversationId(null);\n setActiveCallId(null);\n setActiveMedia(null);\n setError(null);\n }, []);\n\n // Whichever end we are: the callee learns it from the ring, the\n // caller from the invite it placed, and `activeMedia` carries it\n // through being answered — the point at which both of the other two\n // can be gone. Idle reports audio rather than holding the last call's\n // value, so a fresh audio call can never inherit video from the one\n // before it.\n const media: CallMedia = incoming?.media ?? outgoing?.media ?? activeMedia ?? 'audio';\n\n return {\n phase,\n incoming,\n outgoing,\n activeConversationId,\n media,\n error,\n call,\n ring,\n dropped,\n accept,\n decline,\n cancel,\n hangUp,\n reportOthersOnCall,\n reset,\n };\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/provider.tsx","../src/use-me.ts","../src/use-conversation.ts","../src/use-conversations.ts","../src/use-members.ts","../src/use-messages.ts","../src/use-reactions.ts","../src/use-thread.ts","../src/use-typing.ts","../src/use-presence.ts","../src/use-realtime-status.ts","../src/use-attachment-upload.ts","../src/use-attachment-url.ts","../src/use-user.ts","../src/grouping.ts","../src/use-call-room.ts","../src/internal/alone-watch.ts","../src/use-voice-room.ts","../src/use-calls.ts","../src/use-live-call.ts"],"names":["useEffect","useState","useCallback","useMemo","useRef","PAGE_SIZE","upsertById","safeUuid","userId","call","media"],"mappings":"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","file":"index.js","sourcesContent":["import { Poolse, type PoolseConfig } from '@poolse/sdk';\nimport { createContext, useContext, useEffect, useMemo, useRef, type ReactNode } from 'react';\n\ninterface PoolseContextValue {\n chat: Poolse;\n}\n\nconst PoolseContext = createContext<PoolseContextValue | null>(null);\n\nexport interface PoolseProviderProps {\n /**\n * SDK configuration. The provider builds the `Poolse` instance ONCE\n * per mount and reads `getToken` (and the other function-typed\n * options) from a ref on each call, so it's safe to pass a fresh\n * callback or a fresh object literal on every render.\n *\n * Re-mount the provider (give it a new `key`) when you genuinely\n * want a fresh client — typically after a sign-out, a tenant swap,\n * or an `apiUrl` change. Mutating `apiUrl` / `wsUrl` / `socketPath`\n * after mount is a no-op (the values are captured at construction\n * time); dev mode logs a warning when this happens.\n */\n config: PoolseConfig;\n children: ReactNode;\n}\n\n/**\n * Top-level provider. Wrap your tree once with this; every hook in\n * `@poolse/react` reads from the context.\n *\n * ```tsx\n * <PoolseProvider config={{apiUrl, getToken}}>\n * <App />\n * </PoolseProvider>\n * ```\n *\n * The `Poolse` instance is destroyed on unmount — closes the WebSocket\n * and drops every joined channel.\n */\nexport function PoolseProvider({ config, children }: PoolseProviderProps) {\n // Hold the latest config in a ref so the SDK reads current callbacks\n // without us rebuilding the client. Without this, the standard call\n // site `<Provider config={{apiUrl, getToken}}>` re-creates `Poolse`\n // on every parent render — closing the socket mid-flight and\n // re-firing every REST call. Refs let us keep ONE SDK instance per\n // mount while still honoring a freshly-bound `getToken` closed over\n // new auth state.\n const configRef = useRef(config);\n configRef.current = config;\n\n // Captured at mount for the dev-mode change warning below.\n const initialConnectionRef = useRef<{\n apiUrl: string | undefined;\n wsUrl: string | undefined;\n socketPath: string | undefined;\n } | null>(null);\n\n const chat = useMemo(() => {\n const initial = configRef.current;\n initialConnectionRef.current = {\n apiUrl: initial.apiUrl,\n wsUrl: initial.wsUrl,\n socketPath: initial.socketPath,\n };\n return new Poolse({\n // apiUrl is optional in PoolseConfig — only forward when set\n // so the SDK can fall back to its hosted-endpoint default.\n ...(initial.apiUrl !== undefined ? { apiUrl: initial.apiUrl } : {}),\n // Always read the latest callbacks from the ref — they're free\n // to change between renders.\n getToken: () => configRef.current.getToken(),\n ...(initial.fetch\n ? { fetch: ((...args) => configRef.current.fetch!(...args)) as typeof globalThis.fetch }\n : {}),\n ...(initial.maxRetries !== undefined ? { maxRetries: initial.maxRetries } : {}),\n ...(initial.baseBackoffMs !== undefined ? { baseBackoffMs: initial.baseBackoffMs } : {}),\n ...(initial.maxBackoffMs !== undefined ? { maxBackoffMs: initial.maxBackoffMs } : {}),\n ...(initial.generateIdempotencyKey\n ? { generateIdempotencyKey: () => configRef.current.generateIdempotencyKey!() }\n : {}),\n ...(initial.wsUrl !== undefined ? { wsUrl: initial.wsUrl } : {}),\n ...(initial.socketPath !== undefined ? { socketPath: initial.socketPath } : {}),\n ...(initial.onSocketError\n ? { onSocketError: (err) => configRef.current.onSocketError!(err) }\n : {}),\n // Customer's user metadata resolver — name + avatar lookup.\n // Read through the ref so the customer can swap the closure\n // (e.g. switch tenant context) without re-mounting.\n ...(initial.userResolver\n ? { userResolver: (id: string) => configRef.current.userResolver!(id) }\n : {}),\n });\n // Mount-once: the `Poolse` instance owns a WebSocket and channel\n // subscriptions, so it MUST be stable for the life of the mount.\n // Changing `apiUrl` / `wsUrl` / `socketPath` requires a remount.\n }, []);\n\n // Surface mistakes early in dev: connection-shaped fields are\n // captured at construction time, so changing them after mount has\n // no effect (callbacks like `getToken` ARE re-read from the ref).\n if (process.env.NODE_ENV !== 'production') {\n // eslint-disable-next-line react-hooks/rules-of-hooks\n useEffect(() => {\n const initial = initialConnectionRef.current;\n if (!initial) return;\n if (\n initial.apiUrl !== config.apiUrl ||\n initial.wsUrl !== config.wsUrl ||\n initial.socketPath !== config.socketPath\n ) {\n console.warn(\n '[poolse] connection-shaped config (apiUrl / wsUrl / socketPath) ' +\n 'changed after <PoolseProvider> mounted. These are captured at ' +\n 'construction time — remount the provider with a new `key` to ' +\n 'switch environments.',\n );\n }\n }, [config.apiUrl, config.wsUrl, config.socketPath]);\n }\n\n useEffect(() => {\n return () => {\n chat.destroy();\n };\n }, [chat]);\n\n const value = useMemo(() => ({ chat }), [chat]);\n\n return <PoolseContext.Provider value={value}>{children}</PoolseContext.Provider>;\n}\n\n/**\n * Access the underlying `Poolse` instance. Most app code should prefer\n * higher-level hooks (`useMessages`, `useTyping`, etc.) but the raw\n * client is here for escape-hatch usage (custom REST calls, direct\n * realtime control).\n */\nexport function usePoolse(): Poolse {\n const value = useContext(PoolseContext);\n\n if (!value) {\n throw new Error(\n 'usePoolse(): no <PoolseProvider> in the tree. Wrap your component ' +\n 'with `<PoolseProvider config={{apiUrl, getToken}}>` first.',\n );\n }\n\n return value.chat;\n}\n","import type { Me } from '@poolse/sdk';\nimport { useEffect, useState } from 'react';\nimport { usePoolse } from './provider.js';\n\ninterface UseMeState {\n me: Me | null;\n loading: boolean;\n error: Error | null;\n}\n\n/**\n * The currently-signed-in End User (`/v1/me`). Fetches once on mount\n * and never re-fetches automatically — user identity is stable for\n * the JWT's lifetime.\n *\n * Most apps won't need this; the JWT subject is enough. Useful when\n * the UI needs the display name / external_id without re-asking the\n * Customer's backend.\n */\nexport function useMe(): UseMeState {\n const chat = usePoolse();\n const [state, setState] = useState<UseMeState>({\n me: null,\n loading: true,\n error: null,\n });\n\n useEffect(() => {\n let cancelled = false;\n const controller = new AbortController();\n\n chat.me\n .show(controller.signal)\n .then((me) => {\n if (!cancelled) setState({ me, loading: false, error: null });\n })\n .catch((err: unknown) => {\n if (!cancelled) {\n setState({\n me: null,\n loading: false,\n error: err instanceof Error ? err : new Error(String(err)),\n });\n }\n });\n\n return () => {\n cancelled = true;\n controller.abort();\n };\n }, [chat]);\n\n return state;\n}\n","import type { Conversation, Uuid } from '@poolse/sdk';\nimport { useCallback, useEffect, useState } from 'react';\nimport { usePoolse } from './provider.js';\n\ninterface UseConversationState {\n /** The fetched conversation, or `null` while loading or on error. */\n conversation: Conversation | null;\n loading: boolean;\n error: Error | null;\n /** Re-run the GET. Use after a `chat.conversations.one(id).update(...)` to refresh state. */\n refetch: () => Promise<void>;\n}\n\n/**\n * Fetch a single conversation by id. Re-fetches when `id` changes\n * (e.g. routing to a different conversation in the same component).\n *\n * Doesn't subscribe to realtime updates yet — the backend doesn't\n * broadcast `conversation:updated` to user channels. Use `refetch()`\n * after a mutation if you need fresh state in the same render cycle.\n *\n * ```ts\n * const { conversation, loading } = useConversation(convId);\n * if (loading) return <Spinner />;\n * if (!conversation) return <NotFound />;\n * return <h1>{conversation.name ?? 'Untitled'}</h1>;\n * ```\n */\nexport function useConversation(id: Uuid | null): UseConversationState {\n const chat = usePoolse();\n const [conversation, setConversation] = useState<Conversation | null>(null);\n const [loading, setLoading] = useState(id !== null);\n const [error, setError] = useState<Error | null>(null);\n\n // The fetcher is wrapped in useCallback so it's stable across\n // renders for the same id — lets callers depend on it in their\n // own effects (e.g. polling) without re-firing on every render.\n const fetcher = useCallback(\n async (signal?: AbortSignal): Promise<void> => {\n if (id === null) return;\n setLoading(true);\n setError(null);\n try {\n const conv = await chat.conversations.one(id).show(signal);\n setConversation(conv);\n } catch (err) {\n // Ignore AbortError — the caller hit unmount or a new id.\n if ((err as DOMException)?.name === 'AbortError') return;\n setError(err instanceof Error ? err : new Error(String(err)));\n } finally {\n setLoading(false);\n }\n },\n [chat, id],\n );\n\n useEffect(() => {\n if (id === null) {\n setConversation(null);\n setLoading(false);\n setError(null);\n return;\n }\n const controller = new AbortController();\n void fetcher(controller.signal);\n return () => controller.abort();\n }, [fetcher, id]);\n\n const refetch = useCallback(() => fetcher(), [fetcher]);\n\n return { conversation, loading, error, refetch };\n}\n","import type { Conversation, ConversationCreateRequest, Uuid } from '@poolse/sdk';\nimport { useCallback, useEffect, useMemo, useState } from 'react';\nimport { usePoolse } from './provider.js';\nimport { useMe } from './use-me.js';\n\ninterface UseConversationsState {\n conversations: Conversation[];\n loading: boolean;\n error: Error | null;\n refetch: () => Promise<void>;\n create: (attrs: ConversationCreateRequest) => Promise<Conversation>;\n /**\n * Per-conversation unread count, keyed by conversation id. Sourced\n * from `Conversation.unread_count` on the initial fetch and kept\n * fresh as the caller marks conversations read (via `markRead`).\n *\n * Note: cross-conversation incrementing on a new inbound message\n * requires subscribing to every conversation channel, which the SDK\n * doesn't do by default. Counts in this map are accurate for the\n * conversation the caller has open + correct at fetch time for the\n * rest; refetch on a fresh tab focus for true reconciliation.\n */\n unreadCounts: Record<Uuid, number>;\n /** Force a conversation's unread to 0 — invoked by `markReadUpTo`. */\n markConversationRead: (conversationId: Uuid) => void;\n}\n\n/**\n * List of conversations the current End User can see.\n *\n * On mount: REST-fetches the list and subscribes to the user's\n * `user:<id>` channel for `conversation:created` events — fired by\n * the server both when this user creates a conversation AND when\n * someone else adds them to one. New rows are prepended to local\n * state with id-based dedup so an optimistic `create()` followed by\n * the realtime echo doesn't insert twice.\n *\n * `refetch()` is still here for explicit re-syncs (e.g. after a\n * mutation that the SDK doesn't yet observe — name changes,\n * settings updates). `create()` returns the canonical server row.\n */\nexport function useConversations(): UseConversationsState {\n const chat = usePoolse();\n const { me } = useMe();\n const [conversations, setConversations] = useState<Conversation[]>([]);\n const [loading, setLoading] = useState(true);\n const [error, setError] = useState<Error | null>(null);\n\n const refetch = useCallback(async () => {\n setLoading(true);\n try {\n const list = await chat.conversations.list();\n setConversations(list.data);\n setError(null);\n } catch (err) {\n setError(err instanceof Error ? err : new Error(String(err)));\n } finally {\n setLoading(false);\n }\n }, [chat]);\n\n const create = useCallback(\n async (attrs: ConversationCreateRequest) => {\n const conv = await chat.conversations.create(attrs);\n // Optimistically prepend; if the realtime echo arrives later\n // for the same conv (because the server also broadcast it to\n // us as the creator), the id-based dedup in `prepend` keeps\n // it from inserting twice.\n setConversations((prev) => prepend(prev, conv));\n return conv;\n },\n [chat],\n );\n\n useEffect(() => {\n void refetch();\n }, [refetch]);\n\n // Realtime: subscribe to `user:<me.id>` for both `conversation:created`\n // (new membership) and `conversation:updated` (a member of an existing\n // conversation sent a message). Re-subscribes if `me.id` changes.\n useEffect(() => {\n if (!me) return;\n const userChan = chat.realtime.user(me.id);\n const offCreated = userChan.onConversationCreated((conv) => {\n setConversations((prev) => prepend(prev, conv));\n });\n const offUpdated = userChan.onConversationUpdated(({ conversation, by_user_id }) => {\n const fromMe = by_user_id === me.id;\n setConversations((prev) => mergeUpdated(prev, conversation, fromMe));\n });\n return () => {\n offCreated();\n offUpdated();\n };\n }, [chat, me]);\n\n // Force-zero an unread count without mutating the conversation row.\n // Wired by ConversationView's auto-mark-read on scroll so the sidebar\n // badge clears the moment the caller's IntersectionObserver fires\n // — before the server roundtrip + realtime echo for `member:read`.\n const markConversationRead = useCallback((conversationId: Uuid) => {\n setConversations((prev) =>\n prev.map((c) => (c.id === conversationId ? { ...c, unread_count: 0 } : c)),\n );\n }, []);\n\n const unreadCounts = useMemo<Record<Uuid, number>>(() => {\n const out: Record<Uuid, number> = {};\n for (const c of conversations) {\n if (typeof c.unread_count === 'number' && c.unread_count > 0) {\n out[c.id] = c.unread_count;\n }\n }\n return out;\n }, [conversations]);\n\n return { conversations, loading, error, refetch, create, unreadCounts, markConversationRead };\n}\n\n/**\n * Prepend `conv` if its id isn't already in `prev`; otherwise replace\n * the existing row (covers the race where the realtime echo arrives\n * for a conversation our local `create()` already inserted).\n */\nfunction prepend(prev: Conversation[], conv: Conversation): Conversation[] {\n const idx = prev.findIndex((c) => c.id === conv.id);\n if (idx === -1) return [conv, ...prev];\n const next = prev.slice();\n next[idx] = conv;\n return next;\n}\n\n/**\n * Apply a `conversation:updated` realtime payload: merge the fresh\n * surface fields (preview, timestamp, sequence, unread_count) into\n * the existing row and float it to the top.\n *\n * Preferred source for `unread_count` is the wire payload —\n * @poolse/server now computes per-member counts excluding tombstoned\n * messages and injects them into each member's broadcast, so the\n * value is authoritative for both new-message and delete events.\n * Older servers don't include it; we fall back to the legacy\n * \"increment when not from me\" heuristic so the badge still moves\n * for unconsumed sends.\n *\n * If the conversation isn't in our local list yet (rare — joined\n * via a different tab, or we just signed in), prepend the wire row\n * as-is.\n */\nfunction mergeUpdated(prev: Conversation[], next: Conversation, fromMe: boolean): Conversation[] {\n const idx = prev.findIndex((c) => c.id === next.id);\n if (idx === -1) return [next, ...prev];\n const existing = prev[idx]!;\n const wireUnread = typeof next.unread_count === 'number' ? next.unread_count : null;\n const unread_count =\n wireUnread !== null ? wireUnread : fromMe ? 0 : (existing.unread_count ?? 0) + 1;\n const merged: Conversation = {\n ...existing,\n last_message_at: next.last_message_at,\n last_message_preview: next.last_message_preview,\n last_sequence: next.last_sequence,\n unread_count,\n };\n const rest = prev.slice(0, idx).concat(prev.slice(idx + 1));\n return [merged, ...rest];\n}\n","import type { AddMemberOptions, MemberReadEvent, MemberRole, Membership, Uuid } from '@poolse/sdk';\nimport { useCallback, useEffect, useRef, useState } from 'react';\nimport { usePoolse } from './provider.js';\n\ninterface UseMembersState {\n members: Membership[];\n loading: boolean;\n error: Error | null;\n refetch: () => Promise<void>;\n /**\n * Add one or more users by `external_id`. Unknown ids are\n * auto-provisioned on the server. Returned memberships are\n * appended to local state on success.\n */\n addMembers: (externalIds: string[], opts?: { role?: MemberRole }) => Promise<Membership[]>;\n /**\n * Remove a member by `external_id`. The SDK translates to the\n * internal user_id under the hood. Optimistically removes from\n * state; rolls back on server error.\n */\n removeMember: (externalId: string) => Promise<void>;\n}\n\n/**\n * Live-ish membership list for a conversation. Initial REST fetch on\n * mount; mutation helpers update local state in place.\n *\n * Realtime: subscribes to `member:read` on the conversation channel\n * and advances the matching membership's `last_read_message_id` /\n * `last_read_at` so the sender's read-receipt glyph flips from \"sent\"\n * to \"read\" without a refetch. `member:joined` / `member:left` aren't\n * broadcast yet — for cross-client adds/removes, call `refetch()`.\n */\nexport function useMembers(conversationId: Uuid): UseMembersState {\n const chat = usePoolse();\n const [members, setMembers] = useState<Membership[]>([]);\n const [loading, setLoading] = useState(true);\n const [error, setError] = useState<Error | null>(null);\n\n // Shadow ref tracking the latest committed members. Lets the\n // optimistic rollback path capture a snapshot synchronously\n // without racing the React updater queue against an `await`.\n const membersRef = useRef<Membership[]>([]);\n membersRef.current = members;\n\n // Buffer for `member:read` events that arrive BEFORE the initial\n // fetch lands. The realtime subscription runs almost immediately on\n // mount; the HTTP fetch takes a roundtrip. If another user reads in\n // that window, the broadcast fires while local state is still empty\n // and the `prev.map` no-ops — leaving the read invisible forever.\n // We buffer here and replay inside the fetcher after `setMembers`\n // commits the snapshot.\n const pendingReadsRef = useRef<MemberReadEvent[]>([]);\n const hasFetchedRef = useRef(false);\n\n const applyRead = (list: Membership[], evt: MemberReadEvent): Membership[] =>\n list.map((m) =>\n m.user_id === evt.user_id\n ? {\n ...m,\n last_read_message_id: evt.last_read_message_id,\n last_read_at: evt.last_read_at,\n }\n : m,\n );\n\n const fetcher = useCallback(\n async (signal?: AbortSignal): Promise<void> => {\n // Empty id = \"skip fetch\" — used by callers that conditionally\n // want member data (e.g. ConversationView's `mentions={false}\n // readReceipts={false}` configuration). Better than asking\n // every caller to wrap in `enabled ? useMembers(id) : null`.\n if (!conversationId) {\n setLoading(false);\n setMembers([]);\n setError(null);\n return;\n }\n setLoading(true);\n setError(null);\n try {\n const { data } = await chat.conversations.one(conversationId).listMembers(signal);\n // Drain any buffered `member:read` events that fired before the\n // fetch landed. Without this, reads that arrive in the\n // subscribe→response gap would be lost.\n let next = data;\n if (pendingReadsRef.current.length > 0) {\n for (const evt of pendingReadsRef.current) next = applyRead(next, evt);\n pendingReadsRef.current = [];\n }\n setMembers(next);\n hasFetchedRef.current = true;\n } catch (err) {\n if ((err as DOMException)?.name === 'AbortError') return;\n setError(err instanceof Error ? err : new Error(String(err)));\n } finally {\n setLoading(false);\n }\n },\n [chat, conversationId],\n );\n\n useEffect(() => {\n // Reset per-conversation state so a swap of `conversationId`\n // doesn't carry stale buffered reads from a previous channel.\n hasFetchedRef.current = false;\n pendingReadsRef.current = [];\n const controller = new AbortController();\n void fetcher(controller.signal);\n return () => controller.abort();\n }, [fetcher]);\n\n // Real-time read-cursor sync. When ANY member reads, advance their\n // membership row locally — the sender's UI uses\n // max(memberships.last_read_message_id.sequence) to decide whether\n // to show the \"read\" glyph, so this single state edit drives the\n // whole receipt UI.\n useEffect(() => {\n if (!conversationId) return;\n const channel = chat.realtime.conversation(conversationId);\n const off = channel.onMemberRead((evt) => {\n // Buffer if the initial fetch hasn't landed — the fetcher's\n // try-block drains the buffer once it has membership rows to\n // apply the read to. See the matching ref pair above.\n if (!hasFetchedRef.current) {\n pendingReadsRef.current.push(evt);\n return;\n }\n setMembers((prev) => applyRead(prev, evt));\n });\n return () => off();\n }, [chat, conversationId]);\n\n const refetch = useCallback(() => fetcher(), [fetcher]);\n\n const addMembers = useCallback(\n async (externalIds: string[], opts: { role?: MemberRole } = {}) => {\n const addOpts: AddMemberOptions = opts.role !== undefined ? { role: opts.role } : {};\n const { data } = await chat.conversations\n .one(conversationId)\n .addMembers(externalIds, addOpts);\n // Dedup by id in case the server returns a row that was already\n // a member (idempotent re-add).\n setMembers((prev) => {\n const byId = new Map(prev.map((m) => [m.id, m]));\n for (const m of data) byId.set(m.id, m);\n return Array.from(byId.values());\n });\n return data;\n },\n [chat, conversationId],\n );\n\n const removeMember = useCallback(\n async (externalId: string) => {\n const snapshot = membersRef.current;\n // Translate external_id → internal user_id via the loaded member\n // list. The DELETE endpoint takes user_id in the path, but the\n // consumer never has to know that.\n const target = snapshot.find((m) => m.external_id === externalId);\n if (!target) return; // not a member; idempotent no-op\n\n const targetUserId: Uuid = target.user_id;\n setMembers((prev) => prev.filter((m) => m.external_id !== externalId));\n try {\n await chat.conversations.one(conversationId).removeMember(targetUserId);\n } catch (err) {\n setMembers(snapshot);\n throw err;\n }\n },\n [chat, conversationId],\n );\n\n return { members, loading, error, refetch, addMembers, removeMember };\n}\n","import type { Message, MessageCreateRequest, Uuid } from '@poolse/sdk';\nimport { safeUuid } from '@poolse/sdk';\nimport { useCallback, useEffect, useRef, useState } from 'react';\nimport { usePoolse } from './provider.js';\nimport { useMe } from './use-me.js';\n\ninterface UseMessagesState {\n /** Newest-last array. The wire returns newest-first; we reverse so list rendering matches reading order. */\n messages: Message[];\n loading: boolean;\n error: Error | null;\n hasMore: boolean;\n /** Load an older page (lower sequence numbers). Idempotent if no older messages exist. */\n loadMore: () => Promise<void>;\n /** Optimistically append + POST. Replaces the optimistic row with the server response on success. */\n send: (attrs: MessageCreateRequest) => Promise<Message>;\n /**\n * Edit a message you previously sent. Optimistically updates the\n * local row, rolls back on server error. Server enforces\n * sender-only authorization — calling this for a message you didn't\n * send will throw an ApiError.\n */\n edit: (messageId: Uuid, body: string) => Promise<Message>;\n /**\n * Soft-delete a message you sent (or that you have admin authority\n * over). Optimistically applies the tombstone (`deleted_at` + null\n * body) locally, rolls back on error.\n */\n delete: (messageId: Uuid) => Promise<void>;\n /**\n * Advance the caller's read cursor to `messageId`. Server emits\n * read-receipt updates to other members; the conversation's\n * unread count drops to zero. No local state mutation — this is\n * \"tell the server we read up to here\".\n */\n markReadUpTo: (messageId: Uuid) => Promise<void>;\n /**\n * Re-fetch the newest page (PAGE_SIZE) and replace the cached\n * messages. Useful when the app returns from background or the\n * realtime socket reconnects after a drop — any messages we missed\n * while disconnected are pulled in via REST. Pagination resets:\n * `hasMore` becomes true again so `loadMore()` will walk back from\n * the new tail.\n */\n refetch: () => Promise<void>;\n}\n\nconst PAGE_SIZE = 50;\n\n/**\n * Live message list for `conversationId`. Combines:\n *\n * * Initial REST fetch (newest 50) on mount.\n * * WebSocket subscription for `message:new`, `message:updated`,\n * `message:deleted` — applied in-place to the cached array.\n * * Optimistic-send via `send()` — the message appears immediately\n * under the SAME id the server will assign (we pre-generate it\n * client-side and pass it through), so the realtime echo and the\n * REST response both arrive carrying that id and get deduped by\n * `findIndex(m => m.id === msg.id)`. No heuristic match, no race.\n *\n * Re-mounting with the same `conversationId` reuses the underlying\n * channel — no extra socket traffic.\n */\nexport function useMessages(conversationId: string): UseMessagesState {\n const chat = usePoolse();\n const { me } = useMe();\n const [messages, setMessages] = useState<Message[]>([]);\n const [loading, setLoading] = useState(true);\n const [error, setError] = useState<Error | null>(null);\n const [hasMore, setHasMore] = useState(true);\n\n // Cursor for `loadMore` — the lowest sequence currently in state.\n const oldestSequenceRef = useRef<number | null>(null);\n // Mutable refetch implementation. Set per-effect (it captures the\n // current conversation's `messages` resource handle). Exposed\n // through the stable `refetch` callback below so consumers can wire\n // it to e.g. `AppState` 'active' without re-binding on every render.\n const refetchRef = useRef<(() => Promise<void>) | null>(null);\n\n // Hold `me.id` in a ref so `send()` stays stable across renders\n // (otherwise its identity changes every time `me` reloads, which\n // would re-create handlers in calling components).\n const meIdRef = useRef<string | null>(me?.id ?? null);\n meIdRef.current = me?.id ?? null;\n const meExternalIdRef = useRef<string | null>(me?.external_id ?? null);\n meExternalIdRef.current = me?.external_id ?? null;\n\n useEffect(() => {\n let cancelled = false;\n setLoading(true);\n setMessages([]);\n setError(null);\n setHasMore(true);\n oldestSequenceRef.current = null;\n\n const handle = chat.conversations.one(conversationId).messages;\n\n handle\n .list({ limit: PAGE_SIZE })\n .then((page) => {\n if (cancelled) return;\n // Wire is newest-first; flip for natural reading order.\n const ordered = [...page.data].reverse();\n setMessages(ordered);\n setHasMore(page.data.length === PAGE_SIZE);\n oldestSequenceRef.current = ordered[0]?.sequence ?? null;\n setLoading(false);\n })\n .catch((err: unknown) => {\n if (cancelled) return;\n setError(err instanceof Error ? err : new Error(String(err)));\n setLoading(false);\n });\n\n refetchRef.current = async () => {\n const page = await handle.list({ limit: PAGE_SIZE });\n const ordered = [...page.data].reverse();\n setMessages(ordered);\n setHasMore(page.data.length === PAGE_SIZE);\n oldestSequenceRef.current = ordered[0]?.sequence ?? null;\n };\n\n // Realtime listeners.\n const conv = chat.realtime.conversation(conversationId);\n\n const offNew = conv.onMessage((msg) => {\n // Thread replies don't live in the main feed — they belong to\n // the side-pane that `useThread` populates. So when a reply\n // arrives over realtime, route it to the root's reply_count\n // ONLY, and skip the main-list upsert. The server now mirrors\n // this rule on the REST list (`WHERE thread_root_id IS NULL`),\n // so post-refresh state matches realtime behavior.\n if (msg.thread_root_id) {\n setMessages((prev) =>\n prev.map((m) =>\n m.id === msg.thread_root_id ? { ...m, reply_count: (m.reply_count ?? 0) + 1 } : m,\n ),\n );\n return;\n }\n // Top-level message: standard by-id upsert. Covers three cases:\n // 1) Brand-new message from another user → append.\n // 2) Echo of our own optimistic send (id we generated below) →\n // replace the temp row in place (preserves position).\n // 3) Re-delivery on channel rejoin → idempotent replace.\n setMessages((prev) => upsertById(prev, msg));\n });\n\n const offUpdated = conv.onMessageUpdated((msg) => {\n setMessages((prev) => prev.map((m) => (m.id === msg.id ? msg : m)));\n });\n\n const offDeleted = conv.onMessageDeleted((evt) => {\n setMessages((prev) => {\n // Capture the pre-delete row so we can find the thread root if\n // this message was a reply — the delete payload doesn't carry\n // `thread_root_id`, so we have to look it up locally.\n const target = prev.find((m) => m.id === evt.id);\n const updated = prev.map((m) =>\n m.id === evt.id ? { ...m, deleted_at: evt.deleted_at, body: null } : m,\n );\n if (target?.thread_root_id) {\n return updated.map((m) =>\n m.id === target.thread_root_id\n ? { ...m, reply_count: Math.max(0, (m.reply_count ?? 0) - 1) }\n : m,\n );\n }\n return updated;\n });\n });\n\n return () => {\n cancelled = true;\n offNew();\n offUpdated();\n offDeleted();\n // Don't leave the channel — another component may still be reading\n // this conversation. The Poolse.destroy() at provider-unmount\n // tears everything down.\n };\n }, [chat, conversationId]);\n\n const loadMore = useCallback(async () => {\n if (!hasMore || loading) return;\n const before = oldestSequenceRef.current;\n if (!before) return;\n\n const opts: { limit: number; before?: number } = { limit: PAGE_SIZE };\n if (before !== null) opts.before = before;\n\n const page = await chat.conversations.one(conversationId).messages.list(opts);\n if (page.data.length === 0) {\n setHasMore(false);\n return;\n }\n const older = [...page.data].reverse();\n setMessages((prev) => [...older, ...prev]);\n setHasMore(page.data.length === PAGE_SIZE);\n oldestSequenceRef.current = older[0]?.sequence ?? oldestSequenceRef.current;\n }, [chat, conversationId, hasMore, loading]);\n\n const send = useCallback(\n async (attrs: MessageCreateRequest) => {\n // Generate the message id client-side and pass it through, so\n // the optimistic row, the REST response, and the realtime echo\n // ALL share one id — id-based upsert handles every race.\n const id = attrs.id ?? safeUuid();\n const tempMsg: Message = {\n id,\n tenant_id: '',\n conversation_id: conversationId,\n // Stamp the current user's id so the optimistic row renders\n // on the right (self) side from the moment it appears. Null\n // here would briefly flash the row on the \"other\" side until\n // the realtime echo replaced it with the canonical row.\n sender_id: meIdRef.current,\n sender_external_id: meExternalIdRef.current,\n type: attrs.type ?? 'text',\n body: attrs.body ?? null,\n reply_to_id: attrs.reply_to_id ?? null,\n thread_root_id: null,\n // Optimistic quote: keep the id locally so the bubble can flag\n // itself as a quote-reply immediately. `quoted_message` (the\n // preview card body/sender) only lands when the server echo\n // arrives — the UI can render a placeholder (\"Quoted message\")\n // in the gap or wait silently; current bubble does the latter.\n quoted_message_id: attrs.quoted_message_id ?? null,\n mentions: attrs.mentions ?? [],\n reactions: {},\n edited_at: null,\n deleted_at: null,\n // MAX_SAFE_INTEGER sorts the temp row to the very end (newest\n // position) until the server returns the real `sequence`.\n sequence: Number.MAX_SAFE_INTEGER,\n inserted_at: new Date().toISOString(),\n updated_at: new Date().toISOString(),\n };\n\n setMessages((prev) => [...prev, tempMsg]);\n\n try {\n const sent = await chat.conversations.one(conversationId).messages.send({ ...attrs, id });\n // Both REST and realtime carry the same id; whichever lands\n // first wins, and the second is an idempotent replace.\n setMessages((prev) => upsertById(prev, sent));\n return sent;\n } catch (err) {\n setMessages((prev) => prev.filter((m) => m.id !== id));\n throw err;\n }\n },\n [chat, conversationId],\n );\n\n const edit = useCallback(\n async (messageId: Uuid, body: string): Promise<Message> => {\n // Optimistic: capture the previous body so we can roll back if the\n // PATCH fails. `edited_at` is set to \"now\" client-side; the server\n // will overwrite with its authoritative timestamp on the realtime\n // echo + REST response.\n let previous: Message | undefined;\n setMessages((prev) =>\n prev.map((m) => {\n if (m.id !== messageId) return m;\n previous = m;\n return { ...m, body, edited_at: new Date().toISOString() };\n }),\n );\n\n try {\n const updated = await chat.messages.one(messageId).update({ body });\n // Replace with the canonical row (right edited_at, etc).\n setMessages((prev) => prev.map((m) => (m.id === messageId ? updated : m)));\n return updated;\n } catch (err) {\n if (previous) {\n const restore = previous;\n setMessages((prev) => prev.map((m) => (m.id === messageId ? restore : m)));\n }\n throw err;\n }\n },\n [chat],\n );\n\n const deleteMessage = useCallback(\n async (messageId: Uuid): Promise<void> => {\n // Optimistic tombstone — same shape the realtime delete handler\n // applies, so the UI is consistent regardless of which path\n // (REST response or WS push) lands first.\n let previous: Message | undefined;\n setMessages((prev) =>\n prev.map((m) => {\n if (m.id !== messageId) return m;\n previous = m;\n return { ...m, body: null, deleted_at: new Date().toISOString() };\n }),\n );\n\n try {\n await chat.messages.one(messageId).delete();\n } catch (err) {\n if (previous) {\n const restore = previous;\n setMessages((prev) => prev.map((m) => (m.id === messageId ? restore : m)));\n }\n throw err;\n }\n },\n [chat],\n );\n\n const markReadUpTo = useCallback(\n async (messageId: Uuid): Promise<void> => {\n // Fire-and-forget — server updates the caller's last_read_message_id\n // and broadcasts the resulting membership update to other clients\n // (which is what drives read-receipt glyphs in their UIs).\n await chat.conversations.one(conversationId).messages.markRead(messageId);\n },\n [chat, conversationId],\n );\n\n const refetch = useCallback(async (): Promise<void> => {\n const fn = refetchRef.current;\n if (!fn) return;\n await fn();\n }, []);\n\n return {\n messages,\n loading,\n error,\n hasMore,\n loadMore,\n send,\n edit,\n delete: deleteMessage,\n markReadUpTo,\n refetch,\n };\n}\n\nfunction upsertById(prev: Message[], msg: Message): Message[] {\n const idx = prev.findIndex((m) => m.id === msg.id);\n if (idx === -1) return [...prev, msg];\n const next = prev.slice();\n next[idx] = msg;\n return next;\n}\n","import type { Uuid } from '@poolse/sdk';\nimport { useCallback, useEffect, useRef, useState } from 'react';\nimport { usePoolse } from './provider.js';\n\n/**\n * Map of emoji → list of user_ids who reacted with it. Matches the\n * shape of `Message.reactions` so initial seeding from a message you\n * already have in state is a direct assignment.\n */\nexport type ReactionMap = Record<string, Uuid[]>;\n\ninterface UseReactionsState {\n reactions: ReactionMap;\n /** Add the caller's reaction (idempotent server-side). */\n addReaction: (emoji: string) => Promise<void>;\n /** Remove the caller's reaction. No-op if not present. */\n removeReaction: (emoji: string) => Promise<void>;\n}\n\ninterface UseReactionsOptions {\n /**\n * Required for the in-channel subscription — the realtime layer\n * routes reaction events through the conversation channel, not a\n * per-message channel. Pass the conversation id you already know.\n */\n conversationId: Uuid;\n /**\n * Seed the local reaction map from a message you already have\n * (e.g. from `useMessages`). Without this the hook starts empty\n * and only sees deltas from the realtime stream.\n */\n initialReactions?: ReactionMap;\n /**\n * Current user's id. When provided, optimistic mutate updates the\n * local map immediately for that user; when omitted, we wait for\n * the server's `reaction:added` echo to update state.\n */\n currentUserId?: Uuid | null;\n}\n\n/**\n * Live reaction map for a single message. Subscribes to\n * `reaction:added` / `reaction:removed` realtime events filtered to\n * `messageId`, and provides mutation helpers.\n *\n * ```ts\n * const { reactions, addReaction } = useReactions(msg.id, {\n * conversationId: msg.conversation_id,\n * initialReactions: msg.reactions,\n * currentUserId: me?.id,\n * });\n * <button onClick={() => addReaction('🎉')}>🎉 {reactions['🎉']?.length ?? 0}</button>\n * ```\n */\nexport function useReactions(messageId: Uuid, opts: UseReactionsOptions): UseReactionsState {\n const chat = usePoolse();\n const [reactions, setReactions] = useState<ReactionMap>(opts.initialReactions ?? {});\n\n // Keep currentUserId in a ref so the realtime callbacks (set up in\n // the mount effect) always see the latest value without having to\n // re-subscribe when it changes.\n const currentUserIdRef = useRef<Uuid | null>(opts.currentUserId ?? null);\n currentUserIdRef.current = opts.currentUserId ?? null;\n\n // Shadow ref of the latest committed reactions map — used by\n // `removeReaction` for synchronous snapshot capture so the\n // optimistic rollback isn't racing the React updater queue.\n const reactionsRef = useRef<ReactionMap>(reactions);\n reactionsRef.current = reactions;\n\n useEffect(() => {\n const conv = chat.realtime.conversation(opts.conversationId);\n\n const offAdded = conv.onReactionAdded((evt) => {\n if (evt.message_id !== messageId) return;\n setReactions((prev) => addUser(prev, evt.emoji, evt.user_id));\n });\n\n const offRemoved = conv.onReactionRemoved((evt) => {\n if (evt.message_id !== messageId) return;\n setReactions((prev) => removeUser(prev, evt.emoji, evt.user_id));\n });\n\n return () => {\n offAdded();\n offRemoved();\n };\n }, [chat, opts.conversationId, messageId]);\n\n const addReaction = useCallback(\n async (emoji: string) => {\n const uid = currentUserIdRef.current;\n // Optimistic add when we know who we are; otherwise wait for echo.\n if (uid) setReactions((prev) => addUser(prev, emoji, uid));\n try {\n await chat.messages.one(messageId).addReaction(emoji);\n } catch (err) {\n if (uid) setReactions((prev) => removeUser(prev, emoji, uid));\n throw err;\n }\n },\n [chat, messageId],\n );\n\n const removeReaction = useCallback(\n async (emoji: string) => {\n const uid = currentUserIdRef.current;\n const snapshot = reactionsRef.current;\n if (uid) setReactions((prev) => removeUser(prev, emoji, uid));\n try {\n await chat.messages.one(messageId).removeReaction(emoji);\n } catch (err) {\n if (uid) setReactions(snapshot);\n throw err;\n }\n },\n [chat, messageId],\n );\n\n return { reactions, addReaction, removeReaction };\n}\n\nfunction addUser(prev: ReactionMap, emoji: string, userId: Uuid): ReactionMap {\n const existing = prev[emoji] ?? [];\n if (existing.includes(userId)) return prev;\n return { ...prev, [emoji]: [...existing, userId] };\n}\n\nfunction removeUser(prev: ReactionMap, emoji: string, userId: Uuid): ReactionMap {\n const existing = prev[emoji];\n if (!existing || !existing.includes(userId)) return prev;\n const next = existing.filter((id) => id !== userId);\n if (next.length === 0) {\n const { [emoji]: _, ...rest } = prev;\n return rest;\n }\n return { ...prev, [emoji]: next };\n}\n","import type { Message, MessageCreateRequest, Uuid } from '@poolse/sdk';\nimport { safeUuid } from '@poolse/sdk';\nimport { useCallback, useEffect, useRef, useState } from 'react';\nimport { usePoolse } from './provider.js';\n\ninterface UseThreadState {\n /** Replies, oldest-first (the wire returns oldest-first; we don't flip). */\n replies: Message[];\n loading: boolean;\n error: Error | null;\n /** More older-than-current-page replies available on the server. */\n hasMore: boolean;\n /** Load the next page after the current newest reply. Idempotent if no more. */\n loadMore: () => Promise<void>;\n /**\n * Send a reply into this thread. Fills `reply_to_id` with the root\n * message id automatically; pass `body` (and any other\n * `MessageCreateRequest` fields) as you would to `useMessages.send`.\n */\n sendReply: (attrs: Omit<MessageCreateRequest, 'reply_to_id'>) => Promise<Message>;\n /**\n * Edit a reply (or the root message). Optimistic with rollback —\n * mirrors `useMessages.edit`. Server enforces sender-only authz.\n */\n edit: (messageId: Uuid, body: string) => Promise<Message>;\n /**\n * Soft-delete a reply (or the root message). Optimistic tombstone\n * (`deleted_at` + null body) — mirrors `useMessages.delete`.\n */\n delete: (messageId: Uuid) => Promise<void>;\n}\n\n// Threads load top-down all-at-once: most discussions stay well under\n// 500 replies, the side-pane has no infinite-scroll affordance, and\n// avoiding pagination keeps the UX simple. `loadMore` remains as an\n// escape hatch in case a thread does exceed this on the rare day.\nconst PAGE_SIZE = 500;\n\n/**\n * Thread view rooted at `rootMessageId`. Loads replies oldest-first\n * with cursor pagination (`after: sequence`), subscribes to the\n * conversation channel's `message:new` event filtered by\n * `thread_root_id === rootMessageId`, and provides a `sendReply`\n * that wires `reply_to_id` for you.\n *\n * Like `useMessages`, the optimistic send uses the same id the\n * server will assign (auto-generated by the SDK), so the realtime\n * echo just upserts in place — no double-render.\n */\nexport function useThread(conversationId: Uuid, rootMessageId: Uuid): UseThreadState {\n const chat = usePoolse();\n const [replies, setReplies] = useState<Message[]>([]);\n const [loading, setLoading] = useState(true);\n const [error, setError] = useState<Error | null>(null);\n const [hasMore, setHasMore] = useState(true);\n\n // Cursor for `loadMore` — the highest sequence currently in state.\n const newestSequenceRef = useRef<number | null>(null);\n\n useEffect(() => {\n let cancelled = false;\n setLoading(true);\n setReplies([]);\n setError(null);\n setHasMore(true);\n newestSequenceRef.current = null;\n\n chat.messages\n .one(rootMessageId)\n .replies({ limit: PAGE_SIZE })\n .then((page) => {\n if (cancelled) return;\n setReplies(page.data);\n setHasMore(page.data.length === PAGE_SIZE);\n newestSequenceRef.current = page.data[page.data.length - 1]?.sequence ?? null;\n setLoading(false);\n })\n .catch((err: unknown) => {\n if (cancelled) return;\n setError(err instanceof Error ? err : new Error(String(err)));\n setLoading(false);\n });\n\n // Realtime: filter conversation messages for thread membership.\n const conv = chat.realtime.conversation(conversationId);\n const offNew = conv.onMessage((msg) => {\n if (msg.thread_root_id !== rootMessageId) return;\n setReplies((prev) => upsertById(prev, msg));\n });\n const offUpdated = conv.onMessageUpdated((msg) => {\n if (msg.thread_root_id !== rootMessageId) return;\n setReplies((prev) => prev.map((m) => (m.id === msg.id ? msg : m)));\n });\n const offDeleted = conv.onMessageDeleted((evt) => {\n setReplies((prev) =>\n prev.map((m) => (m.id === evt.id ? { ...m, deleted_at: evt.deleted_at, body: null } : m)),\n );\n });\n\n return () => {\n cancelled = true;\n offNew();\n offUpdated();\n offDeleted();\n };\n }, [chat, conversationId, rootMessageId]);\n\n const loadMore = useCallback(async () => {\n if (!hasMore || loading) return;\n const after = newestSequenceRef.current;\n if (after === null) return;\n const page = await chat.messages.one(rootMessageId).replies({ limit: PAGE_SIZE, after });\n if (page.data.length === 0) {\n setHasMore(false);\n return;\n }\n setReplies((prev) => [...prev, ...page.data]);\n setHasMore(page.data.length === PAGE_SIZE);\n newestSequenceRef.current = page.data[page.data.length - 1]?.sequence ?? after;\n }, [chat, rootMessageId, hasMore, loading]);\n\n const sendReply = useCallback(\n async (attrs: Omit<MessageCreateRequest, 'reply_to_id'>) => {\n const id = attrs.id ?? safeUuid();\n const tempMsg: Message = {\n id,\n tenant_id: '',\n conversation_id: conversationId,\n sender_id: null,\n sender_external_id: null,\n type: attrs.type ?? 'text',\n body: attrs.body ?? null,\n reply_to_id: rootMessageId,\n thread_root_id: rootMessageId,\n mentions: attrs.mentions ?? [],\n reactions: {},\n edited_at: null,\n deleted_at: null,\n sequence: Number.MAX_SAFE_INTEGER,\n inserted_at: new Date().toISOString(),\n updated_at: new Date().toISOString(),\n };\n setReplies((prev) => [...prev, tempMsg]);\n\n try {\n const sent = await chat.conversations.one(conversationId).messages.send({\n ...attrs,\n id,\n reply_to_id: rootMessageId,\n });\n setReplies((prev) => upsertById(prev, sent));\n return sent;\n } catch (err) {\n setReplies((prev) => prev.filter((m) => m.id !== id));\n throw err;\n }\n },\n [chat, conversationId, rootMessageId],\n );\n\n const edit = useCallback(\n async (messageId: Uuid, body: string): Promise<Message> => {\n let previous: Message | undefined;\n setReplies((prev) =>\n prev.map((m) => {\n if (m.id !== messageId) return m;\n previous = m;\n return { ...m, body, edited_at: new Date().toISOString() };\n }),\n );\n\n try {\n const updated = await chat.messages.one(messageId).update({ body });\n setReplies((prev) => prev.map((m) => (m.id === messageId ? updated : m)));\n return updated;\n } catch (err) {\n if (previous) {\n const restore = previous;\n setReplies((prev) => prev.map((m) => (m.id === messageId ? restore : m)));\n }\n throw err;\n }\n },\n [chat],\n );\n\n const deleteReply = useCallback(\n async (messageId: Uuid): Promise<void> => {\n let previous: Message | undefined;\n setReplies((prev) =>\n prev.map((m) => {\n if (m.id !== messageId) return m;\n previous = m;\n return { ...m, body: null, deleted_at: new Date().toISOString() };\n }),\n );\n\n try {\n await chat.messages.one(messageId).delete();\n } catch (err) {\n if (previous) {\n const restore = previous;\n setReplies((prev) => prev.map((m) => (m.id === messageId ? restore : m)));\n }\n throw err;\n }\n },\n [chat],\n );\n\n return {\n replies,\n loading,\n error,\n hasMore,\n loadMore,\n sendReply,\n edit,\n delete: deleteReply,\n };\n}\n\nfunction upsertById(prev: Message[], msg: Message): Message[] {\n const idx = prev.findIndex((m) => m.id === msg.id);\n if (idx === -1) return [...prev, msg];\n const next = prev.slice();\n next[idx] = msg;\n return next;\n}\n","import { useCallback, useEffect, useRef, useState } from 'react';\nimport { usePoolse } from './provider.js';\nimport { useMe } from './use-me.js';\n\ninterface UseTypingState {\n /**\n * Set of `external_id`s currently typing (your own user identifiers,\n * the same string you'd pass to `userResolver`). Excludes the\n * current user — they know they're typing.\n */\n typing: Set<string>;\n /**\n * Send a typing ping to the server. Debounced inside the hook to\n * once per 500 ms — the server squashes further with its own\n * per-(user, conversation) window.\n */\n signalTyping: () => void;\n}\n\n// How long after the most recent `typing:start` ping we assume the\n// remote user has stopped typing. The server emits one ping every\n// ~500ms while the keystroke debounce is hot; 4s gives a comfortable\n// safety margin without leaving the chip on after the user clearly\n// stopped. Independent of the server's own `typing:stop` window so\n// the UI is responsive even if that broadcast is late or dropped.\nconst TYPING_TIMEOUT_MS = 4000;\n\n/**\n * Tracks who's typing in `conversationId`. Subscribes to the\n * `typing:start` / `typing:stop` broadcasts, plus two purely\n * client-side eviction paths that keep the chip from lingering when\n * the server is slow (or never) to send `typing:stop`:\n *\n * 1. Per-user inactivity timer — each `typing:start` resets a 4 s\n * timeout for that `external_id`; when it fires we drop them\n * from the set. Covers \"they stopped typing without sending\".\n * 2. `message:new` from the same sender — if a typing user sends a\n * message, we evict them immediately. Covers \"they just sent\".\n */\nexport function useTyping(conversationId: string): UseTypingState {\n const chat = usePoolse();\n const { me } = useMe();\n const [typing, setTyping] = useState<Set<string>>(new Set());\n const lastPingRef = useRef(0);\n\n // `me` resolves asynchronously after first render; read it from a\n // ref inside the event handlers so the subscription doesn't need to\n // re-attach when `me` lands (which would briefly drop incoming\n // typing events from other users).\n const meExtRef = useRef<string | null>(me?.external_id ?? null);\n meExtRef.current = me?.external_id ?? null;\n\n useEffect(() => {\n setTyping(new Set());\n const timers = new Map<string, ReturnType<typeof setTimeout>>();\n\n const evict = (ext: string) => {\n const t = timers.get(ext);\n if (t) {\n clearTimeout(t);\n timers.delete(ext);\n }\n setTyping((prev) => {\n if (!prev.has(ext)) return prev;\n const next = new Set(prev);\n next.delete(ext);\n return next;\n });\n };\n\n const conv = chat.realtime.conversation(conversationId);\n\n const offStart = conv.onTypingStart((evt) => {\n const ext = evt.external_id;\n if (!ext) return;\n // Don't render the current user's own typing — they know.\n if (meExtRef.current && ext === meExtRef.current) return;\n // (Re)arm the inactivity timer for this user.\n const existing = timers.get(ext);\n if (existing) clearTimeout(existing);\n timers.set(\n ext,\n setTimeout(() => evict(ext), TYPING_TIMEOUT_MS),\n );\n setTyping((prev) => {\n if (prev.has(ext)) return prev;\n const next = new Set(prev);\n next.add(ext);\n return next;\n });\n });\n\n const offStop = conv.onTypingStop((evt) => {\n const ext = evt.external_id;\n if (!ext) return;\n if (meExtRef.current && ext === meExtRef.current) return;\n evict(ext);\n });\n\n // If the typing user sends a message, they're definitely done\n // typing — evict immediately rather than waiting for the server's\n // typing:stop broadcast.\n const offMessage = conv.onMessage((msg) => {\n const ext = msg.sender_external_id;\n if (!ext) return;\n if (meExtRef.current && ext === meExtRef.current) return;\n evict(ext);\n });\n\n return () => {\n offStart();\n offStop();\n offMessage();\n for (const t of timers.values()) clearTimeout(t);\n timers.clear();\n };\n }, [chat, conversationId]);\n\n const signalTyping = useCallback(() => {\n const now = Date.now();\n if (now - lastPingRef.current < 500) return;\n lastPingRef.current = now;\n chat.realtime.conversation(conversationId).sendTyping();\n }, [chat, conversationId]);\n\n return { typing, signalTyping };\n}\n","import type { PresenceSnapshot } from '@poolse/sdk';\nimport { useEffect, useState } from 'react';\nimport { usePoolse } from './provider.js';\n\ninterface UsePresenceState {\n /**\n * Set of `external_id`s currently online in this conversation —\n * the tenant's own user identifiers. Empty set when no one is on\n * the channel (note: an empty result during reconnect is normal;\n * pair with `useRealtimeStatus()` if you need to distinguish).\n */\n online: Set<string>;\n}\n\n// Pull external_id out of the first meta entry for each user_id key.\n// Phoenix.Presence supports multiple metas per join (e.g. same user\n// in two tabs); we surface the external_id once since it's identical\n// across the user's metas.\nfunction externalIdsFrom(state: PresenceSnapshot): string[] {\n const out: string[] = [];\n for (const presence of Object.values(state)) {\n const meta = presence?.metas?.[0];\n if (meta?.external_id) out.push(meta.external_id);\n }\n return out;\n}\n\n/**\n * Who's currently joined to `conversationId`'s channel. Backed by\n * Phoenix.Presence broadcasts (`presence_state` snapshot on join,\n * `presence_diff` on changes).\n */\nexport function usePresence(conversationId: string): UsePresenceState {\n const chat = usePoolse();\n const [online, setOnline] = useState<Set<string>>(new Set());\n\n useEffect(() => {\n setOnline(new Set());\n\n if (!conversationId) return;\n\n const conv = chat.realtime.conversation(conversationId);\n\n const applyState = (state: PresenceSnapshot) => {\n setOnline(new Set(externalIdsFrom(state)));\n };\n\n const applyDiff = (diff: { joins?: PresenceSnapshot; leaves?: PresenceSnapshot }) => {\n setOnline((prev) => {\n const next = new Set(prev);\n if (diff.joins) externalIdsFrom(diff.joins).forEach((ext) => next.add(ext));\n if (diff.leaves) externalIdsFrom(diff.leaves).forEach((ext) => next.delete(ext));\n return next;\n });\n };\n\n const offState = conv.onPresenceState(applyState);\n const offDiff = conv.onPresenceDiff(applyDiff as (s: PresenceSnapshot) => void);\n\n return () => {\n offState();\n offDiff();\n };\n }, [chat, conversationId]);\n\n return { online };\n}\n","import type { RealtimeStatus } from '@poolse/sdk';\nimport { useEffect, useState } from 'react';\nimport { usePoolse } from './provider.js';\n\n/**\n * Connection status of the underlying WebSocket. Useful for showing a\n * \"reconnecting…\" banner without coupling to socket internals.\n *\n * Returns one of: `'idle' | 'connecting' | 'connected' | 'reconnecting' | 'closed'`.\n */\nexport function useRealtimeStatus(): RealtimeStatus {\n const chat = usePoolse();\n const [status, setStatus] = useState<RealtimeStatus>(chat.realtime.getStatus());\n\n useEffect(() => {\n setStatus(chat.realtime.getStatus());\n return chat.realtime.onStatus(setStatus);\n }, [chat]);\n\n return status;\n}\n","import type { Attachment, AttachmentUploadInput } from '@poolse/sdk';\nimport { safeUuid } from '@poolse/sdk';\nimport { useCallback, useEffect, useRef, useState } from 'react';\nimport { usePoolse } from './provider.js';\n\nexport type UploadItemStatus = 'pending' | 'uploading' | 'ready' | 'error' | 'cancelled';\n\nexport interface UploadItem {\n /** Local-only id (random per-enqueue). Stable for keys + `cancel(localId)` / `remove(localId)`. */\n localId: string;\n filename: string;\n contentType: string;\n byteSize: number;\n status: UploadItemStatus;\n /** Bytes uploaded so far; 0 until the PUT actually begins. */\n loaded: number;\n /** Resolved attachment row once `status === 'ready'`. Null otherwise. */\n attachment: Attachment | null;\n /** Set when `status === 'error'`. */\n error: Error | null;\n}\n\ninterface UseAttachmentUploadState {\n /** Every enqueued item, in enqueue order, until removed by `remove()` / `reset()`. */\n queue: UploadItem[];\n /**\n * Last attachment that reached `ready`, for the common one-file\n * \"did the upload finish\" check. Null after `reset()` / `remove()`\n * of the most recent ready item. Multi-file callers should iterate\n * `queue` instead.\n */\n attachment: Attachment | null;\n /** True while at least one item is `pending` or `uploading`. */\n uploading: boolean;\n /** Most recent item-level error, or null. */\n error: Error | null;\n /**\n * Enqueue a single upload. Resolves with the final attachment row.\n * Rejects with the underlying error (item's `status` becomes\n * `'error'`); aborts surface as a DOMException('AbortError') and the\n * item's status becomes `'cancelled'`.\n */\n upload: (input: AttachmentUploadInput) => Promise<Attachment>;\n /**\n * Enqueue many at once — drag-and-drop, multi-file picker. Items run\n * in parallel (the SDK is per-call independent). Resolves with the\n * attachments in the same order as the input; if any item fails the\n * whole promise rejects after the others settle.\n */\n uploadAll: (inputs: AttachmentUploadInput[]) => Promise<Attachment[]>;\n /** Abort an in-flight upload. Sets the item's status to `cancelled`. No-op if not in flight. */\n cancel: (localId: string) => void;\n /** Drop an item from the queue. Cancels first if it's still in flight. */\n remove: (localId: string) => void;\n /** Drop everything + abort any in-flight uploads. */\n reset: () => void;\n}\n\ninterface InFlight {\n controller: AbortController;\n}\n\n/**\n * Stateful wrapper around `chat.attachments.upload`. Exposes a queue\n * of in-flight / completed uploads with per-item progress + per-item\n * cancel — drag-and-drop, multi-file picker, retry chips, all without\n * the host app reimplementing AbortController plumbing.\n *\n * ```tsx\n * const { upload, queue, cancel, remove } = useAttachmentUpload();\n * const onPick = async (files: File[]) => {\n * const atts = await uploadAll(files.map(f => ({\n * body: f, contentType: f.type, byteSize: f.size, filename: f.name\n * })));\n * await chat.conversations.one(convId).messages.send({\n * body: '', attachment_ids: atts.map(a => a.id),\n * });\n * };\n * ```\n *\n * The legacy `upload(input)` → `Promise<Attachment>` shape is preserved\n * so older callers keep working — they just won't render the queue UI.\n */\nexport function useAttachmentUpload(): UseAttachmentUploadState {\n const chat = usePoolse();\n const [queue, setQueue] = useState<UploadItem[]>([]);\n const inFlightRef = useRef<Map<string, InFlight>>(new Map());\n // Track mount status so async resolves don't setState on unmounted\n // components. Strict-mode double-effects re-arm this on remount.\n const mountedRef = useRef(true);\n useEffect(() => {\n mountedRef.current = true;\n return () => {\n mountedRef.current = false;\n // Reading inFlightRef at cleanup time is the point: we abort\n // whatever is uploading *now*. The lint rule's usual advice —\n // snapshot the ref inside the effect — would capture the empty\n // map from mount and abort nothing.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n for (const v of inFlightRef.current.values()) v.controller.abort();\n inFlightRef.current.clear();\n };\n }, []);\n\n const updateItem = useCallback((localId: string, patch: Partial<UploadItem>) => {\n if (!mountedRef.current) return;\n setQueue((q) => q.map((it) => (it.localId === localId ? { ...it, ...patch } : it)));\n }, []);\n\n const runUpload = useCallback(\n async (localId: string, input: AttachmentUploadInput): Promise<Attachment> => {\n const controller = new AbortController();\n inFlightRef.current.set(localId, { controller });\n updateItem(localId, { status: 'uploading', loaded: 0 });\n try {\n const att = await chat.attachments.upload(input, {\n signal: controller.signal,\n onProgress: (e) => updateItem(localId, { loaded: e.loaded }),\n });\n updateItem(localId, {\n status: 'ready',\n loaded: input.byteSize,\n attachment: att,\n error: null,\n });\n return att;\n } catch (err) {\n if ((err as DOMException)?.name === 'AbortError') {\n updateItem(localId, { status: 'cancelled' });\n throw err;\n }\n const e = err instanceof Error ? err : new Error(String(err));\n updateItem(localId, { status: 'error', error: e });\n throw e;\n } finally {\n inFlightRef.current.delete(localId);\n }\n },\n [chat, updateItem],\n );\n\n const enqueue = useCallback((input: AttachmentUploadInput): UploadItem => {\n const localId = generateLocalId();\n const item: UploadItem = {\n localId,\n filename: input.filename ?? 'file',\n contentType: input.contentType,\n byteSize: input.byteSize,\n status: 'pending',\n loaded: 0,\n attachment: null,\n error: null,\n };\n setQueue((q) => [...q, item]);\n return item;\n }, []);\n\n const upload = useCallback(\n (input: AttachmentUploadInput): Promise<Attachment> => {\n const item = enqueue(input);\n return runUpload(item.localId, input);\n },\n [enqueue, runUpload],\n );\n\n const uploadAll = useCallback(\n (inputs: AttachmentUploadInput[]): Promise<Attachment[]> => {\n // Enqueue all first so the UI shows the full queue immediately,\n // then start the PUTs in parallel. Order in resolved array\n // matches input order regardless of which PUT finishes first.\n const items = inputs.map((inp) => ({ item: enqueue(inp), input: inp }));\n return Promise.all(items.map(({ item, input }) => runUpload(item.localId, input)));\n },\n [enqueue, runUpload],\n );\n\n const cancel = useCallback((localId: string) => {\n const inf = inFlightRef.current.get(localId);\n if (inf) inf.controller.abort();\n }, []);\n\n const remove = useCallback((localId: string) => {\n const inf = inFlightRef.current.get(localId);\n if (inf) inf.controller.abort();\n setQueue((q) => q.filter((it) => it.localId !== localId));\n }, []);\n\n const reset = useCallback(() => {\n for (const v of inFlightRef.current.values()) v.controller.abort();\n inFlightRef.current.clear();\n setQueue([]);\n }, []);\n\n const uploading = queue.some((it) => it.status === 'pending' || it.status === 'uploading');\n // Last error in queue order — pendings/readies have null, so the\n // most recently transitioned-to-error item wins.\n const error = queue.reduce<Error | null>((acc, it) => it.error ?? acc, null);\n // Last ready attachment — same convenience.\n const attachment = queue.reduce<Attachment | null>((acc, it) => it.attachment ?? acc, null);\n\n return { queue, attachment, uploading, error, upload, uploadAll, cancel, remove, reset };\n}\n\nfunction generateLocalId(): string {\n return safeUuid();\n}\n","import type { Uuid } from '@poolse/sdk';\nimport { useEffect, useState } from 'react';\nimport { usePoolse } from './provider.js';\n\ninterface UseAttachmentUrlState {\n /** Presigned GET URL, or null while loading / on error. */\n url: string | null;\n loading: boolean;\n error: Error | null;\n}\n\n/**\n * Resolve an attachment's presigned download URL. Pass `null` to\n * skip the fetch — useful in routing-driven views where the id may\n * not be known yet.\n *\n * Doesn't auto-refresh: the server's URL TTL is ~1 hour and most\n * UI lifetimes are much shorter. If you do need a refresh (long-lived\n * dashboard, etc.), remount the hook or wrap it in a parent that\n * re-keys on a timer.\n *\n * ```tsx\n * const { url } = useAttachmentUrl(message.custom_data?.attachment_id ?? null);\n * return url ? <img src={url} /> : <Spinner />;\n * ```\n */\nexport function useAttachmentUrl(attachmentId: Uuid | null): UseAttachmentUrlState {\n const chat = usePoolse();\n const [url, setUrl] = useState<string | null>(null);\n const [loading, setLoading] = useState(attachmentId !== null);\n const [error, setError] = useState<Error | null>(null);\n\n useEffect(() => {\n if (attachmentId === null) {\n setUrl(null);\n setLoading(false);\n setError(null);\n return;\n }\n let cancelled = false;\n const controller = new AbortController();\n setLoading(true);\n setError(null);\n chat.attachments\n .one(attachmentId)\n .downloadUrl({ signal: controller.signal })\n .then((res) => {\n if (cancelled) return;\n setUrl(res.url);\n setLoading(false);\n })\n .catch((err: unknown) => {\n if (cancelled) return;\n if ((err as DOMException)?.name === 'AbortError') return;\n setError(err instanceof Error ? err : new Error(String(err)));\n setLoading(false);\n });\n return () => {\n cancelled = true;\n controller.abort();\n };\n }, [chat, attachmentId]);\n\n return { url, loading, error };\n}\n","// React binding over `chat.users.get(externalId)`.\n//\n// Uses plain useState + useEffect (NOT `useSyncExternalStore`).\n// useSyncExternalStore reaches into React internals and surfaces\n// any latent React-duplication immediately as \"Invalid hook call\".\n// The pattern below works the same way for our purposes — read\n// from the cache on mount, subscribe for updates, update state —\n// without that fragility.\n\nimport type { PoolseUserProfile } from '@poolse/sdk';\nimport { useEffect, useState } from 'react';\nimport { usePoolse } from './provider.js';\n\nexport interface UseUserState {\n /** Resolved profile, or null when the resolver returned null / errored / isn't configured. */\n profile: PoolseUserProfile | null;\n /** True while the SDK is mid-fetch (or before the first fetch fires). */\n loading: boolean;\n}\n\nconst EMPTY: UseUserState = { profile: null, loading: false };\n\n/**\n * Resolve the tenant's `external_id` (your own user id) to\n * `{ displayName, avatarUrl }` via the configured `userResolver`.\n *\n * Returns `{ profile: null, loading: false }` when:\n * * no resolver is configured\n * * resolver returned null (user not found)\n * * resolver threw (logged once, then cached as null)\n *\n * Pass `null` / empty string to opt out (the hook becomes a no-op).\n * Useful for self bubbles (you already know who you are).\n */\nexport function useUser(externalId: string | null | undefined): UseUserState {\n const chat = usePoolse();\n const [state, setState] = useState<UseUserState>(() => {\n if (!externalId) return EMPTY;\n const cached = chat.users.peek(externalId);\n if (cached === undefined) return { profile: null, loading: true };\n return { profile: cached, loading: false };\n });\n\n useEffect(() => {\n if (!externalId) {\n setState(EMPTY);\n return;\n }\n\n const apply = () => {\n const cached = chat.users.peek(externalId);\n if (cached === undefined) {\n setState({ profile: null, loading: true });\n void chat.users.get(externalId);\n } else {\n setState({ profile: cached, loading: false });\n }\n };\n\n const off = chat.users.subscribe(externalId, apply);\n apply();\n return off;\n }, [chat, externalId]);\n\n return state;\n}\n","// Bubble grouping + day-separator helpers — extracted from\n// ConversationView so they're testable in isolation and reusable\n// if a customer rolls their own message-list layout.\n\nimport { isCallLogMessage, type Message } from '@poolse/sdk';\n\n/**\n * Where this message sits inside a same-sender, same-day, in-window\n * cluster. Drives the bubble's corner treatment + the row's\n * inter-cluster margin.\n *\n * * `standalone` — single bubble, gets the tail\n * * `first` — first of multi; all corners rounded\n * * `middle` — interior; all corners rounded\n * * `last` — last of multi; gets the tail\n */\nexport type GroupPosition = 'first' | 'middle' | 'last' | 'standalone';\n\nexport function computeGroupPosition(\n msg: Message,\n prev: Message | null,\n next: Message | null,\n windowMs: number,\n): GroupPosition {\n const continuesPrev = sameGroup(msg, prev, windowMs);\n const continuesNext = sameGroup(next, msg, windowMs);\n if (continuesPrev && continuesNext) return 'middle';\n if (continuesPrev) return 'last';\n if (continuesNext) return 'first';\n return 'standalone';\n}\n\nexport function sameGroup(a: Message | null, b: Message | null, windowMs: number): boolean {\n if (!a || !b) return false;\n // Call-log rows are centered separator-like lines, never part of a\n // bubble cluster — and they must not glue the bubbles around them\n // together either.\n if (isCallLogMessage(a) || isCallLogMessage(b)) return false;\n if (a.sender_id !== b.sender_id) return false;\n if (!sameDay(a.inserted_at, b.inserted_at)) return false;\n const ta = new Date(a.inserted_at).getTime();\n const tb = new Date(b.inserted_at).getTime();\n return Math.abs(ta - tb) <= windowMs;\n}\n\nexport function sameDay(a: string, b: string): boolean {\n const da = new Date(a);\n const db = new Date(b);\n return (\n da.getFullYear() === db.getFullYear() &&\n da.getMonth() === db.getMonth() &&\n da.getDate() === db.getDate()\n );\n}\n\n/**\n * \"Today\" / \"Yesterday\" / \"Mon, 26 May\" / \"26 May 2024\" — same\n * convention as iMessage / WhatsApp / Telegram. `now` is exposed\n * for deterministic testing; defaults to the current wall clock.\n */\nexport function formatDayLabel(iso: string, now: Date = new Date()): string {\n const d = new Date(iso);\n const startOfDay = (x: Date) => new Date(x.getFullYear(), x.getMonth(), x.getDate()).getTime();\n const diffDays = Math.floor((startOfDay(now) - startOfDay(d)) / 86_400_000);\n if (diffDays === 0) return 'Today';\n if (diffDays === 1) return 'Yesterday';\n if (diffDays < 7) {\n return d.toLocaleDateString(undefined, { weekday: 'long' });\n }\n if (d.getFullYear() === now.getFullYear()) {\n return d.toLocaleDateString(undefined, { weekday: 'short', day: 'numeric', month: 'short' });\n }\n return d.toLocaleDateString(undefined, { day: 'numeric', month: 'short', year: 'numeric' });\n}\n","import type {\n CallDevice,\n CallDeviceKind,\n CallParticipant,\n CallRoomStatus,\n CameraFacing,\n LiveKitModule,\n} from '@poolse/sdk';\nimport { CallRoom } from '@poolse/sdk';\nimport { useCallback, useEffect, useMemo, useRef, useState } from 'react';\n\nimport { usePoolse } from './provider.js';\n\nexport interface UseCallRoomOptions {\n /**\n * `livekit-client`, imported by your app:\n *\n * import * as livekit from 'livekit-client';\n *\n * Passed in rather than imported by the SDK because Metro bundles from\n * the static import graph and cannot follow the `require` that tsup\n * emits — a dependency the SDK imports for itself never reaches a\n * React Native bundle.\n */\n livekit: LiveKitModule;\n /** Publish the camera on join. An audio call starts with it off. */\n video?: boolean;\n /** Join muted. */\n muted?: boolean;\n /** Which camera to open with. Defaults to the front one. */\n facing?: CameraFacing;\n /**\n * How long the last participant may sit alone before {@link\n * UseCallRoom.alone} turns true, in milliseconds. Defaults to 1500.\n * Pass `0` to never report it.\n */\n aloneGraceMs?: number;\n}\n\nexport interface UseCallRoom {\n status: CallRoomStatus;\n /** Everyone on the call, the local participant first. */\n participants: CallParticipant[];\n cameraEnabled: boolean;\n micEnabled: boolean;\n /** Which camera is publishing. Meaningless while the camera is off. */\n facingMode: CameraFacing;\n /**\n * Selectable devices, refreshed as they are plugged in and removed.\n *\n * The web's answer to a phone's speaker button — a laptop has no\n * earpiece, but it does have several microphones and a pair of\n * headphones, and choosing between them is the same job. Sparse on\n * React Native, where routing goes through the platform audio session\n * instead (see `useCallAudio` in `@poolse/react-native`).\n */\n devices: Record<CallDeviceKind, CallDevice[]>;\n /** Device id in use per kind, where the platform reports one. */\n activeDevices: Partial<Record<CallDeviceKind, string>>;\n /** Move the call onto another camera, microphone or output. */\n selectDevice: (kind: CallDeviceKind, deviceId: string) => Promise<void>;\n /**\n * Re-read the device list.\n *\n * Called for you on connect and whenever devices change, so this is\n * for the case neither covers: a browser only reveals device ids and\n * labels once the page holds a matching permission, and the moment\n * that permission lands is not an event you can subscribe to. Call it\n * when opening a picker and the list will be right by the time it is\n * on screen.\n */\n refreshDevices: () => void;\n /**\n * Everyone else has gone and is not coming back.\n *\n * Turns true only after somebody else has actually been on the call,\n * so the caller waiting for an answer never trips it. Wire it to your\n * hang-up path — a peer whose app was killed or whose phone lost\n * signal sends no `call:hangup`, and without this the survivor is\n * left on a call screen that will never close on its own.\n *\n * useEffect(() => {\n * if (media.alone) void calls.hangUp();\n * }, [media.alone]);\n */\n alone: boolean;\n error: Error | null;\n /**\n * Whether this deployment has an SFU.\n *\n * `null` until a join has been attempted, then `false` if the API\n * answered 503. A `false` here is not a failure — it means fall back\n * to `useVoiceRoom`, which is how every call worked before the SFU.\n */\n sfuAvailable: boolean | null;\n /** Connect. Resolves `false` when there is no SFU. */\n join: () => Promise<boolean>;\n leave: () => void;\n setCameraEnabled: (enabled: boolean) => Promise<void>;\n toggleCamera: () => Promise<void>;\n /** Swap between the front and rear cameras. */\n switchCamera: () => Promise<void>;\n setMicrophoneEnabled: (enabled: boolean) => Promise<void>;\n toggleMic: () => Promise<void>;\n}\n\n/**\n * A call's media, carried by the SFU.\n *\n * Media only. Ringing, accept/decline/hangup and the poolse roster stay\n * with `useCalls` and `useVoiceRoom`; this is what people sound and look\n * like. A call screen normally uses both.\n *\n * const media = useCallRoom(conversationId, { livekit, video: true });\n * await media.join();\n * await media.toggleCamera();\n *\n * Both the camera and the microphone can be turned on and off at any\n * point during the call — that is the SFU's doing, since renegotiating a\n * live connection is exactly what the peer-to-peer mesh cannot do.\n */\nexport function useCallRoom(conversationId: string | null, opts: UseCallRoomOptions): UseCallRoom {\n const poolse = usePoolse();\n\n const [status, setStatus] = useState<CallRoomStatus>('idle');\n const [participants, setParticipants] = useState<CallParticipant[]>([]);\n const [cameraEnabled, setCamera] = useState(false);\n const [micEnabled, setMic] = useState(false);\n const [facingMode, setFacing] = useState<CameraFacing>(opts.facing ?? 'user');\n const [alone, setAlone] = useState(false);\n const [devices, setDevices] = useState<Record<CallDeviceKind, CallDevice[]>>({\n videoinput: [],\n audioinput: [],\n audiooutput: [],\n });\n const [activeDevices, setActiveDevices] = useState<Partial<Record<CallDeviceKind, string>>>({});\n const [error, setError] = useState<Error | null>(null);\n const [sfuAvailable, setSfuAvailable] = useState<boolean | null>(null);\n\n // Kept current, but read only when a room is built.\n //\n // This used to pin the FIRST value, which quietly broke every video\n // call. The options are an inline object literal, so pinning avoided\n // rebuilding the room on each render — but a call screen mounts long\n // before a call exists, and at that point `video` is false because\n // nothing is ringing yet. The room was then constructed later, on the\n // conversation id arriving, from options captured when there was no\n // call: audio, always. Cameras never opened on a video call and the\n // toggle looked broken.\n //\n // Assigning during render keeps the ref current without triggering\n // one, and the memo below still only reads it when it actually\n // constructs a room — so nothing rebuilds per render either.\n const optsRef = useRef(opts);\n optsRef.current = opts;\n\n // Whether THIS hook holds the room. Leaving without having joined\n // would release a claim we never made.\n const joined = useRef(false);\n\n /**\n * The room this hook is currently responsible for.\n *\n * Connecting takes time, and a call can end during it — the far side\n * hangs up, the user navigates away, the conversation changes. When\n * that happened the effect's cleanup ran while `joined` was still\n * false, because `join()` had not resolved yet, so nothing released\n * the room. The connection then completed into a room no component\n * held: audio flowing, no UI, and no way to hang it up.\n *\n * Comparing against this on resolve is what closes that window.\n */\n const held = useRef<CallRoom | null>(null);\n\n const room = useMemo(() => {\n if (!conversationId) return null;\n\n return poolse.call(conversationId, {\n livekit: optsRef.current.livekit,\n ...(optsRef.current.video !== undefined ? { video: optsRef.current.video } : {}),\n ...(optsRef.current.muted !== undefined ? { muted: optsRef.current.muted } : {}),\n ...(optsRef.current.facing !== undefined ? { facing: optsRef.current.facing } : {}),\n ...(optsRef.current.aloneGraceMs !== undefined\n ? { aloneGraceMs: optsRef.current.aloneGraceMs }\n : {}),\n });\n }, [poolse, conversationId]);\n\n // Track state changes that originate below React — a camera that\n // failed to start, or the SFU dropping us — rather than assuming our\n // last call succeeded.\n const refreshDevices = useCallback((target: CallRoom) => {\n void Promise.all([\n target.listDevices('videoinput'),\n target.listDevices('audioinput'),\n target.listDevices('audiooutput'),\n ]).then(([videoinput, audioinput, audiooutput]) => {\n setDevices({ videoinput, audioinput, audiooutput });\n\n // Built by omission rather than by assigning undefined: under\n // `exactOptionalPropertyTypes` a present-but-undefined key is not\n // the same as an absent one, and \"the platform does not report\n // this\" is genuinely absence.\n const active: Partial<Record<CallDeviceKind, string>> = {};\n for (const kind of ['videoinput', 'audioinput', 'audiooutput'] as const) {\n const id = target.getActiveDevice(kind);\n if (id) active[kind] = id;\n }\n setActiveDevices(active);\n });\n }, []);\n\n const sync = useCallback((target: CallRoom | null) => {\n if (!target) return;\n setCamera(target.isCameraEnabled());\n setMic(target.isMicrophoneEnabled());\n setFacing(target.getFacingMode());\n }, []);\n\n useEffect(() => {\n if (!room) {\n setStatus('idle');\n setParticipants([]);\n return;\n }\n\n setStatus(room.getStatus());\n setParticipants(room.getParticipants());\n\n held.current = room;\n\n // Latched rather than pulsed: a consumer that hangs up in an effect\n // needs the signal to survive until it has been read, and a call\n // that has been abandoned is never un-abandoned.\n setAlone(false);\n\n const offStatus = room.onStatus(setStatus);\n const offRoster = room.onParticipants((next) => {\n setParticipants(next);\n sync(room);\n });\n const offAlone = room.onAlone(() => setAlone(true));\n\n const offDevices = room.onDevices(() => refreshDevices(room));\n const offError = room.onError(setError);\n\n return () => {\n offStatus();\n offRoster();\n offAlone();\n offDevices();\n offError();\n held.current = null;\n // Unmounting mid-call must disconnect, or the SFU keeps publishing\n // a participant nobody is behind.\n if (joined.current) {\n joined.current = false;\n room.leave();\n }\n };\n }, [room, sync, refreshDevices]);\n\n const join = useCallback(async (): Promise<boolean> => {\n const target = room;\n if (!target) return false;\n setError(null);\n\n try {\n const connected = await target.join();\n\n // Superseded while connecting. Release it here — the cleanup that\n // would normally have done so already ran, and found nothing to\n // release because this promise had not resolved yet.\n if (held.current !== target) {\n if (connected) target.leave();\n return false;\n }\n\n joined.current = connected;\n setSfuAvailable(connected);\n sync(target);\n // Only once connected: enumerating before the call holds its\n // permissions gives a list of unlabelled placeholders.\n if (connected) refreshDevices(target);\n return connected;\n } catch (err) {\n setError(err instanceof Error ? err : new Error(String(err)));\n // A thrown join is a real failure, not a missing SFU — the caller\n // should surface it rather than quietly falling back.\n setSfuAvailable(true);\n return false;\n }\n }, [room, sync, refreshDevices]);\n\n const leave = useCallback(() => {\n if (!joined.current) return;\n joined.current = false;\n room?.leave();\n }, [room]);\n\n const setCameraEnabled = useCallback(\n async (enabled: boolean) => {\n if (!room) return;\n await room.setCameraEnabled(enabled);\n sync(room);\n },\n [room, sync],\n );\n\n const setMicrophoneEnabled = useCallback(\n async (enabled: boolean) => {\n if (!room) return;\n await room.setMicrophoneEnabled(enabled);\n sync(room);\n },\n [room, sync],\n );\n\n // Read the live value rather than the rendered one: a toggle fired\n // twice quickly would otherwise both read the same stale state and\n // end up where it started.\n const toggleCamera = useCallback(async () => {\n if (!room) return;\n await setCameraEnabled(!room.isCameraEnabled());\n }, [room, setCameraEnabled]);\n\n const toggleMic = useCallback(async () => {\n if (!room) return;\n await setMicrophoneEnabled(!room.isMicrophoneEnabled());\n }, [room, setMicrophoneEnabled]);\n\n const switchCamera = useCallback(async () => {\n if (!room) return;\n await room.switchCamera();\n setFacing(room.getFacingMode());\n }, [room]);\n\n const refresh = useCallback(() => {\n if (room) refreshDevices(room);\n }, [room, refreshDevices]);\n\n const selectDevice = useCallback(\n async (kind: CallDeviceKind, deviceId: string) => {\n if (!room) return;\n await room.setActiveDevice(kind, deviceId);\n setActiveDevices((current) => ({\n ...current,\n [kind]: room.getActiveDevice(kind) ?? deviceId,\n }));\n },\n [room],\n );\n\n return {\n status,\n participants,\n cameraEnabled,\n micEnabled,\n facingMode,\n alone,\n devices,\n activeDevices,\n refreshDevices: refresh,\n error,\n sfuAvailable,\n join,\n leave,\n setCameraEnabled,\n toggleCamera,\n switchCamera,\n selectDevice,\n setMicrophoneEnabled,\n toggleMic,\n };\n}\n","import { useEffect, useRef, useState } from 'react';\n\nexport interface AloneWatchOptions {\n /** Whether the call is actually carrying media right now. */\n active: boolean;\n /** How many OTHER people are on the call — excluding yourself. */\n others: number;\n /** Grace period before the verdict. `0` disables the watch. */\n graceMs: number;\n}\n\n/**\n * Report when this client is the last one left on a call.\n *\n * The mesh's counterpart to `CallRoom`'s built-in check. It lives here\n * rather than in `VoiceRoom` because the mesh's roster arrives as\n * presence on poolse's own channel, which the hook already holds — and\n * duplicating the subscription inside the SDK to watch a number the\n * hook can see would buy nothing.\n *\n * Two guards, both load-bearing:\n *\n * * Nobody has to have been here — `seenPeer` — before an empty room\n * counts as abandonment. Otherwise the caller who connects first,\n * alone by definition until the callee joins, ends their own call.\n * * The verdict waits out `graceMs`, so two people hanging up in the\n * same tick, or a reconnect that briefly empties presence, does not\n * read as everyone walking out.\n *\n * Latches once true: a consumer hanging up in an effect needs the\n * signal to survive being read, and an abandoned call is never\n * un-abandoned. Resets when the call goes inactive.\n */\nexport function useAloneWatch({ active, others, graceMs }: AloneWatchOptions): boolean {\n const [alone, setAlone] = useState(false);\n const seenPeer = useRef(false);\n\n useEffect(() => {\n if (!active) {\n seenPeer.current = false;\n setAlone(false);\n return;\n }\n\n if (others > 0) {\n seenPeer.current = true;\n return;\n }\n\n if (graceMs <= 0 || !seenPeer.current) return;\n\n const timer = setTimeout(() => setAlone(true), graceMs);\n // Cleared by the next run whenever `others` changes, so somebody\n // rejoining inside the grace period cancels the verdict.\n return () => clearTimeout(timer);\n }, [active, others, graceMs]);\n\n return alone;\n}\n","import type { VoiceParticipant, VoiceRoomOptions, VoiceStatus } from '@poolse/sdk';\nimport { useCallback, useEffect, useMemo, useRef, useState } from 'react';\nimport { useAloneWatch } from './internal/alone-watch.js';\nimport { usePoolse } from './provider.js';\n\nexport interface UseVoiceRoom {\n status: VoiceStatus;\n /** Everyone currently in the room, oldest join first. */\n participants: VoiceParticipant[];\n muted: boolean;\n /**\n * Everyone else has left and is not coming back.\n *\n * The mesh equivalent of `useCallRoom`'s flag of the same name — see\n * there for why a call needs this on top of the explicit hang-up\n * signal. Only meaningful for a room being used to carry a call; a\n * Discord-style room you sit in alone is a normal state, so wire this\n * to hang-up only on the call surface.\n */\n alone: boolean;\n error: Error | null;\n /** Acquire the mic and connect. Safe to call twice. */\n join: () => Promise<void>;\n leave: () => void;\n toggleMute: () => void;\n}\n\n/**\n * Discord-style voice room for a conversation: join, see who else is\n * in, watch who's talking, mute yourself.\n *\n * The room is torn down when the conversation changes or the component\n * unmounts, so a navigation away hangs up rather than leaving a phantom\n * participant behind.\n *\n * const voice = useVoiceRoom(conversationId);\n * <Button onPress={voice.join} title=\"Join Voice\" />\n *\n * For ringing someone who hasn't joined yet, see `useCalls`.\n */\nexport function useVoiceRoom(\n conversationId: string | null,\n opts: VoiceRoomOptions & {\n /** Grace before {@link UseVoiceRoom.alone}. Defaults to 1500; `0` disables. */\n aloneGraceMs?: number;\n } = {},\n): UseVoiceRoom {\n const poolse = usePoolse();\n\n const [status, setStatus] = useState<VoiceStatus>('idle');\n const [participants, setParticipants] = useState<VoiceParticipant[]>([]);\n const [muted, setMuted] = useState(false);\n const [error, setError] = useState<Error | null>(null);\n\n // Options are usually an inline object literal, which would re-run\n // the subscribe effect on every render. Pin them to the first value:\n // ICE servers and the WebRTC adapter don't meaningfully change for\n // the lifetime of a room.\n const optsRef = useRef(opts);\n\n // Whether THIS hook holds the room open. The SDK hands out one room\n // per conversation and counts holders, so leaving without having\n // joined would release someone else's claim — a call screen unmounting\n // would cut the audio out from under a voice bar in the same\n // conversation.\n const joined = useRef(false);\n\n /**\n * The room this hook is responsible for right now.\n *\n * Same window as `useCallRoom`: a call that ends while the room is\n * still connecting ran its cleanup before `join()` resolved, so\n * nothing released the room and it finished connecting with no\n * component behind it — audio with no UI.\n */\n const held = useRef<ReturnType<typeof poolse.realtime.voice> | null>(null);\n\n const room = useMemo(\n () => (conversationId ? poolse.realtime.voice(conversationId, optsRef.current) : null),\n [poolse, conversationId],\n );\n\n useEffect(() => {\n if (!room) return;\n\n held.current = room;\n setStatus(room.getStatus());\n setParticipants(room.getParticipants());\n setMuted(room.isMuted());\n\n const offStatus = room.onStatus(setStatus);\n const offRoster = room.onParticipants(setParticipants);\n const offError = room.onError(setError);\n\n return () => {\n offStatus();\n offRoster();\n offError();\n held.current = null;\n // Leaving on unmount is deliberate: the server only broadcasts\n // `voice:left` on an explicit leave, so skipping it would strand\n // us in everyone else's roster. Only release a claim we made.\n if (joined.current) {\n joined.current = false;\n room.leave();\n }\n };\n }, [room]);\n\n const join = useCallback(async () => {\n const target = room;\n if (!target) return;\n setError(null);\n try {\n await target.join();\n\n // Superseded while connecting — release it rather than leaving a\n // room nobody holds. See `held`.\n if (held.current !== target) {\n target.leave();\n return;\n }\n joined.current = true;\n } catch (err) {\n setError(err instanceof Error ? err : new Error(String(err)));\n }\n }, [room]);\n\n const leave = useCallback(() => {\n if (!joined.current) return;\n joined.current = false;\n room?.leave();\n }, [room]);\n\n const toggleMute = useCallback(() => {\n if (!room) return;\n setMuted(room.toggleMute());\n }, [room]);\n\n // `participants` includes the local participant, so anyone else is\n // whatever is left over.\n const alone = useAloneWatch({\n active: status === 'connected',\n others: Math.max(0, participants.length - 1),\n graceMs: optsRef.current.aloneGraceMs ?? 1500,\n });\n\n return { status, participants, muted, alone, error, join, leave, toggleMute };\n}\n","import type { CallMedia, IncomingCall, OutgoingCall } from '@poolse/sdk';\nimport { useCallback, useEffect, useMemo, useRef, useState } from 'react';\nimport { usePoolse } from './provider.js';\n\n/** Where a call is in its lifecycle, from this device's point of view. */\nexport type CallPhase =\n | 'idle'\n /** We placed a call and are waiting for an answer. */\n | 'ringing-out'\n /** Someone is ringing us. */\n | 'ringing-in'\n /** Both sides agreed; the voice room should be joined now. */\n | 'active'\n /** The far side said no. */\n | 'declined'\n /** The person we called is already on another call. */\n | 'busy'\n /** Nobody picked up before the ring timeout elapsed. */\n | 'timed-out';\n\nexport interface UseCallsOptions {\n /**\n * How long a ring may go unanswered, in milliseconds, before it is\n * given up on. Defaults to 45s, roughly what the mainstream call apps\n * use. Pass `0` to ring indefinitely.\n *\n * The server deliberately holds no timer — only the UI knows when it\n * stopped waiting — so this is what actually ends an unanswered call.\n * Both directions are covered: an outbound ring cancels itself, and an\n * inbound one gives up too, otherwise a caller that crashed mid-ring\n * would leave the callee's phone ringing forever.\n */\n ringTimeoutMs?: number;\n}\n\nexport interface UseCalls {\n phase: CallPhase;\n /** Set while `phase` is `ringing-in`. */\n incoming: IncomingCall | null;\n /** Set while `phase` is `ringing-out` or `active`. */\n outgoing: OutgoingCall | null;\n /**\n * Conversation whose voice room should be joined once `phase` turns\n * `active` — the same id for both caller and callee.\n */\n activeConversationId: string | null;\n /**\n * What the current call opened as.\n *\n * `'audio'` when nothing is in flight. Either side can still turn\n * their camera on mid-call — this is what was rung, which is what the\n * incoming UI has to commit to before the user answers.\n */\n media: CallMedia;\n error: Error | null;\n /** Ring every other member of a conversation. */\n call: (conversationId: string, media?: CallMedia) => Promise<void>;\n /**\n * Register a ring that arrived by some route other than the socket —\n * in practice a VoIP push.\n *\n * Without this the push path shows a ring the state machine knows\n * nothing about, and every signal that ends a call is guarded on\n * state the machine never had: the caller hanging up sent\n * `call:cancelled`, the guard found no matching `incoming`, and the\n * callee's phone rang on until its own timeout.\n *\n * Idempotent per call id, because the socket almost always delivers\n * the same call a moment later — that is one ring arriving twice, not\n * a second caller.\n */\n ring: (call: IncomingCall) => void;\n /**\n * A call was torn down from outside this state machine.\n *\n * The counterpart to {@link ring}: the caller withdrew, or the call\n * ended, and the news reached this device as a VoIP push rather than\n * over the socket — which is the normal case for a phone that was\n * asleep when the ring arrived and whose socket may not be up yet.\n *\n * Ignores call ids this client is not in, so a teardown for a\n * previous call cannot end the current one.\n */\n dropped: (callId: string) => void;\n /**\n * Answer the inbound ring.\n *\n * Pass the call explicitly when it didn't arrive over the socket — a\n * VoIP push can launch the app cold, in which case this hook has no\n * `incoming` state and the push payload is the only source of truth.\n */\n accept: (call?: IncomingCall) => Promise<void>;\n /** Reject the inbound ring. Takes an explicit call for the same\n * cold-launch reason as {@link accept}. */\n decline: (call?: IncomingCall) => Promise<void>;\n /** Hang up an outbound ring before it's answered. */\n cancel: () => Promise<void>;\n /**\n * End the call, whatever state it is in.\n *\n * The one action a UI's hang-up button should call: it sends the right\n * signal for the current phase — cancel while ringing out, decline\n * while ringing in, hangup once connected — and always returns to\n * idle, even if the signal fails. `reset` alone clears local state\n * only, which leaves the other side in the call.\n */\n hangUp: () => Promise<void>;\n /** Drop back to idle — call after leaving the room, or to clear a\n * `declined` / `busy` / `timed-out` state the UI has finished\n * showing. */\n reset: () => void;\n /**\n * Tell the hook how many OTHER people are currently on the call's\n * media. `hangUp` consults it: with two or more others connected,\n * hanging up just leaves — the call continues without you — and the\n * end-the-call signal is only sent when at most one other remains.\n * Every hang-up path funnels through the hook (the in-call button,\n * CallKit's end event, the OS back gesture), so this is the ONE\n * place group calls are protected from being ended by a leaver.\n */\n reportOthersOnCall: (count: number) => void;\n}\n\n/**\n * WhatsApp-style calling: ring a conversation, show an incoming-call\n * screen, accept or decline.\n *\n * This hook is only the *invitation* half. Audio starts when you join\n * the voice room, which the host app does once `phase` is `active`:\n *\n * const calls = useCalls(myUserId);\n * const voice = useVoiceRoom(calls.activeConversationId);\n *\n * useEffect(() => {\n * if (calls.phase === 'active') void voice.join();\n * }, [calls.phase]);\n *\n * Keeping them separate means a \"join voice\" button and a ringing call\n * share exactly one implementation of the media path.\n */\nexport function useCalls(userId: string | null, opts: UseCallsOptions = {}): UseCalls {\n const ringTimeoutMs = opts.ringTimeoutMs ?? 45_000;\n const poolse = usePoolse();\n\n const [phase, setPhase] = useState<CallPhase>('idle');\n\n // The phase as of the last render, readable from a socket callback\n // without making every subscription depend on it — re-subscribing on\n // each phase change would drop events in the gap.\n const phaseRef = useRef<CallPhase>('idle');\n phaseRef.current = phase;\n const [incoming, setIncoming] = useState<IncomingCall | null>(null);\n const [outgoing, setOutgoing] = useState<OutgoingCall | null>(null);\n const [activeConversationId, setActiveConversationId] = useState<string | null>(null);\n\n /**\n * The id of the call this client is in, once it is in one.\n *\n * Tracked separately because neither `incoming` nor `outgoing`\n * survives being answered — `accept()` clears `incoming`, and a callee\n * never had an `outgoing`. Without this the callee's `hangUp()` had no\n * call id at all and returned before sending anything, so answering a\n * call meant you could never end it for the other side: they sat in a\n * call the app had already left.\n *\n * It is also what makes the socket handlers below able to tell a\n * signal about THIS call from a late one about a previous call.\n */\n const [activeCallId, setActiveCallId] = useState<string | null>(null);\n\n /**\n * What the call in progress opened as.\n *\n * Tracked for the same reason as {@link activeCallId}: `accept()`\n * clears `incoming`, and a callee never had an `outgoing`, so once a\n * call was answered there was nothing left to read the media type\n * from and it fell back to `'audio'`. The callee's room was then\n * built for an audio call and never opened the camera — so on a video\n * call the caller's camera came on and the callee's did not, which\n * reads as the default being random when it is really \"whichever end\n * you were on\".\n */\n const [activeMedia, setActiveMedia] = useState<CallMedia | null>(null);\n const [error, setError] = useState<Error | null>(null);\n\n // Same reason as `phaseRef`: the handlers are bound once, and must be\n // able to ask \"is this signal about the call I am in?\" without\n // re-subscribing on every state change.\n const incomingRef = useRef<IncomingCall | null>(null);\n incomingRef.current = incoming;\n const outgoingRef = useRef<OutgoingCall | null>(null);\n outgoingRef.current = outgoing;\n const activeCallIdRef = useRef<string | null>(null);\n activeCallIdRef.current = activeCallId;\n\n /** Is this signal about the call this client is currently in? */\n const isCurrent = useCallback((callId: string) => {\n return (\n callId === activeCallIdRef.current ||\n callId === incomingRef.current?.callId ||\n callId === outgoingRef.current?.callId\n );\n }, []);\n\n /**\n * Who has said no to the outbound call, and how.\n *\n * A group ring is not over because one person waved it away. Everyone\n * still has a phone ringing, and ending the call on the first refusal\n * hangs up on all of them. So refusals accumulate here and the call\n * only ends once nobody is left who might still pick up.\n *\n * Keyed by user id, so the same person's device sending both a busy\n * and a decline counts once.\n */\n const rejectedRef = useRef<Map<string, 'declined' | 'busy'>>(new Map());\n\n /**\n * An accept or decline the user made before the socket resource\n * existed.\n *\n * `useCalls(userId)` builds nothing until it has a user id, and the\n * host app gets that from `useMe()` — a network round trip. A VoIP\n * push launches the app cold and CallKit lets the user answer or\n * refuse immediately, which is comfortably before that request comes\n * back. Both actions then hit `if (!calls) return` and were dropped on\n * the floor: the caller was told nothing and rang on.\n */\n const pendingRef = useRef<{ kind: 'accept' | 'decline'; call: IncomingCall } | null>(null);\n\n // Held in a ref so the timeout effect can reach the current handlers\n // without re-arming the timer every time one of them is recreated —\n // re-arming would silently extend the ring forever.\n const actionsRef = useRef<{ cancel: () => Promise<void>; decline: () => Promise<void> }>({\n cancel: async () => {},\n decline: async () => {},\n });\n\n const calls = useMemo(() => (userId ? poolse.realtime.calls(userId) : null), [poolse, userId]);\n\n /**\n * Apply one callee's refusal to an outbound ring.\n *\n * Ends the call only when there is nobody left it could still be\n * answered by — see {@link rejectedRef}. A server that doesn't report\n * who was rung leaves `calleeUserIds` empty, and then the first\n * refusal ends the call, which is the old behaviour and the right\n * fallback: better to hang up early than to ring forever.\n */\n const reject = useCallback((callId: string, userId: string, kind: 'declined' | 'busy') => {\n // Only a ring can be refused. Once somebody has answered, a decline\n // from a member who never joined is them dropping out of a call that\n // is happily going on without them — not the end of it.\n if (phaseRef.current !== 'ringing-out') return;\n\n const out = outgoingRef.current;\n if (!out || out.callId !== callId) return;\n\n rejectedRef.current.set(userId, kind);\n\n const outstanding = out.calleeUserIds.filter((id) => !rejectedRef.current.has(id));\n if (out.calleeUserIds.length > 0 && outstanding.length > 0) return;\n\n // \"Busy\" and \"declined\" are different sentences to show the user, so\n // a call that everybody was busy for says so; any outright refusal\n // makes it a decline.\n const allBusy = [...rejectedRef.current.values()].every((k) => k === 'busy');\n setPhase(allBusy ? 'busy' : 'declined');\n setOutgoing(null);\n setActiveCallId(null);\n setActiveMedia(null);\n }, []);\n\n useEffect(() => {\n if (!calls) return;\n\n const offIncoming = calls.onIncoming((call) => {\n // The same ring arriving by both routes. A VoIP push gets here\n // first and `ring()` recorded it; the socket then delivers the\n // identical call. Treating that as a second caller would answer\n // the user's own call with `call:busy`.\n if (call.callId === incomingRef.current?.callId) return;\n if (call.callId === activeCallIdRef.current) return;\n\n // One call at a time. A second ring must not replace the screen\n // mid-decision — but it must not vanish silently either, or the\n // second caller can't tell \"busy\" from \"ignoring me\". Answer it\n // automatically so their UI can say so.\n //\n // The decision reads a ref rather than a `setPhase` updater.\n // Updaters must be pure: React runs them during render and may run\n // them more than once, so sending `call:busy` from inside one\n // could reject a call the user was in fact being shown — and did,\n // under StrictMode's double-invoke.\n if (phaseRef.current !== 'idle') {\n void calls.markBusy(call).catch(() => {\n // Best effort: failing to send busy just degrades to the old\n // silence, which must not break the call in progress.\n });\n return;\n }\n setIncoming(call);\n setPhase('ringing-in');\n });\n\n // Every handler below is guarded on the call id. A signal that\n // arrives late, or belongs to a call this client already finished\n // with, must not touch the call it is in now — that is how a live\n // call ended up being torn down by a `call:cancelled` for a\n // different one.\n\n const offAccepted = calls.onAccepted((call) => {\n // Only our own outbound call. Nothing else should move us into a\n // call we did not place.\n if (outgoingRef.current && call.callId !== outgoingRef.current.callId) return;\n setPhase('active');\n setActiveConversationId(call.conversationId);\n setActiveCallId(call.callId);\n });\n\n const offDeclined = calls.onDeclined((call) => {\n if (!isCurrent(call.callId)) return;\n reject(call.callId, call.userId, 'declined');\n });\n\n const offBusy = calls.onBusy((call) => {\n if (!isCurrent(call.callId)) return;\n reject(call.callId, call.userId, 'busy');\n });\n\n // The other side hung up a connected call. Without this the screen\n // stays open on a call that no longer exists.\n const offEnded = calls.onEnded((call) => {\n if (!isCurrent(call.callId)) return;\n setPhase('idle');\n setIncoming(null);\n setOutgoing(null);\n setActiveConversationId(null);\n setActiveCallId(null);\n setActiveMedia(null);\n });\n\n const offCancelled = calls.onCancelled((call) => {\n // Strictly the ring we are showing.\n //\n // This used to fall through to `setPhase('idle')` whenever\n // `incoming` was null — which is precisely the state `accept()`\n // leaves behind. A caller's ring timeout firing as the callee\n // answered would then drop the callee straight out of the call\n // they had just joined, leaving media running with no UI.\n if (call.callId !== incomingRef.current?.callId) return;\n setIncoming(null);\n setPhase('idle');\n setActiveCallId(null);\n setActiveMedia(null);\n });\n\n return () => {\n offIncoming();\n offAccepted();\n offDeclined();\n offBusy();\n offEnded();\n offCancelled();\n };\n }, [calls, isCurrent, reject]);\n\n /**\n * Send whatever the user decided before the socket was ready.\n *\n * Runs the moment `calls` exists — see {@link pendingRef}. The local\n * state was already moved when the action was taken, so this is purely\n * about telling the other side.\n */\n useEffect(() => {\n if (!calls) return;\n const queued = pendingRef.current;\n if (!queued) return;\n pendingRef.current = null;\n\n const sent = queued.kind === 'accept' ? calls.accept(queued.call) : calls.decline(queued.call);\n void sent.catch((err: unknown) => {\n setError(err instanceof Error ? err : new Error(String(err)));\n });\n }, [calls]);\n\n const call = useCallback(\n async (conversationId: string, media: CallMedia = 'audio') => {\n if (!calls) return;\n setError(null);\n // A fresh ring, so nobody has refused it yet. Left over from the\n // previous call, one stale entry could end this one early.\n rejectedRef.current = new Map();\n try {\n const placed = await calls.invite(conversationId, media);\n setOutgoing(placed);\n setActiveCallId(placed.callId);\n setActiveMedia(placed.media);\n setPhase('ringing-out');\n } catch (err) {\n setError(err instanceof Error ? err : new Error(String(err)));\n setPhase('idle');\n }\n },\n [calls],\n );\n\n /**\n * Record a ring that reached us outside the socket. See {@link\n * UseCalls.ring}.\n */\n const ring = useCallback((call: IncomingCall) => {\n // Already showing it, or already in it. Both mean this is the same\n // call arriving twice rather than anything new.\n if (incomingRef.current?.callId === call.callId) return;\n if (activeCallIdRef.current === call.callId) return;\n // Deliberately silent when busy: the socket's `onIncoming` is what\n // sends `call:busy`, and doing it here too would send it twice.\n if (phaseRef.current !== 'idle') return;\n\n setIncoming(call);\n setPhase('ringing-in');\n }, []);\n\n /** See {@link UseCalls.dropped}. */\n const dropped = useCallback(\n (callId: string) => {\n // Whatever was waiting to be sent about THIS call is moot — there\n // is no longer a call to accept or refuse. Checked before the\n // guard below, because taking the action already cleared the\n // state that guard reads: a decline made before the socket was up\n // leaves nothing behind but the queued signal itself.\n if (pendingRef.current?.call.callId === callId) pendingRef.current = null;\n\n if (!isCurrent(callId)) return;\n rejectedRef.current = new Map();\n setPhase('idle');\n setIncoming(null);\n setOutgoing(null);\n setActiveConversationId(null);\n setActiveCallId(null);\n setActiveMedia(null);\n },\n [isCurrent],\n );\n\n const accept = useCallback(\n async (call?: IncomingCall) => {\n const target = call ?? incoming;\n if (!target) return;\n\n // Answered before the socket resource exists — hold it and send it\n // the moment there is somewhere to send it to. Local state still\n // moves, so the UI follows the user rather than the network.\n if (!calls) {\n pendingRef.current = { kind: 'accept', call: target };\n setActiveConversationId(target.conversationId);\n setActiveCallId(target.callId);\n setActiveMedia(target.media);\n setPhase('active');\n setIncoming(null);\n return;\n }\n\n // Local state moves FIRST — the UI follows the user's answer, not\n // the network. Waiting for the server's reply before showing the\n // call meant a slow ack stranded the user on the ring screen with\n // a red \"timed out\" while the call was in fact connecting.\n setActiveConversationId(target.conversationId);\n // Recorded BEFORE `incoming` is cleared — it is the only thing\n // that will still know which call this is once the ring state\n // is gone, and it is what `hangUp` needs to tell the other side.\n setActiveCallId(target.callId);\n setActiveMedia(target.media);\n setPhase('active');\n setIncoming(null);\n\n try {\n await calls.accept(target);\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n // A TIMEOUT is not a verdict: the server usually processed the\n // accept and only the ack was lost. The call proves itself —\n // media connects, or the alone-watch ends it. Showing an error\n // over a working call taught people to ignore errors.\n if (message.includes('timed out')) return;\n // An explicit rejection IS a verdict — the call is gone\n // (withdrawn, rung out, hung up). Stand down.\n setPhase('idle');\n setActiveConversationId(null);\n setActiveCallId(null);\n setActiveMedia(null);\n setError(err instanceof Error ? err : new Error(String(err)));\n }\n },\n [calls, incoming],\n );\n\n const decline = useCallback(\n async (call?: IncomingCall) => {\n const target = call ?? incoming;\n if (!target) return;\n\n // Same as `accept`: refusing a call before the socket is up must\n // still reach the caller, or their phone rings until it times out.\n if (!calls) {\n pendingRef.current = { kind: 'decline', call: target };\n setIncoming(null);\n setActiveCallId(null);\n setActiveMedia(null);\n setPhase('idle');\n return;\n }\n\n try {\n await calls.decline(target);\n } catch (err) {\n setError(err instanceof Error ? err : new Error(String(err)));\n } finally {\n // Local state clears either way: a failed decline shouldn't\n // leave the ring screen stuck on screen.\n setIncoming(null);\n setActiveCallId(null);\n setActiveMedia(null);\n setPhase('idle');\n }\n },\n [calls, incoming],\n );\n\n const cancel = useCallback(async () => {\n if (!calls || !outgoing) return;\n try {\n await calls.cancel(outgoing);\n } catch (err) {\n setError(err instanceof Error ? err : new Error(String(err)));\n } finally {\n setOutgoing(null);\n setActiveCallId(null);\n setActiveMedia(null);\n setPhase('idle');\n }\n }, [calls, outgoing]);\n\n actionsRef.current = { cancel, decline };\n\n // Give up on a ring that nobody answered.\n useEffect(() => {\n if (ringTimeoutMs <= 0) return;\n if (phase !== 'ringing-out' && phase !== 'ringing-in') return;\n\n const outbound = phase === 'ringing-out';\n const timer = setTimeout(() => {\n // Tell the far side before changing local state, so their UI\n // stops ringing too rather than waiting out its own timer.\n void (outbound ? actionsRef.current.cancel() : actionsRef.current.decline()).finally(() => {\n // cancel()/decline() both land on 'idle'; outbound gets a\n // distinct phase so the UI can say \"no answer\" instead of\n // silently dismissing the call.\n if (outbound) setPhase('timed-out');\n });\n }, ringTimeoutMs);\n\n return () => clearTimeout(timer);\n }, [phase, ringTimeoutMs]);\n\n /**\n * End the call and tell the other side.\n *\n * Local state is cleared in `finally` on purpose: a failed signal must\n * never strand the user on a call screen they cannot dismiss.\n */\n const othersOnCallRef = useRef(0);\n const reportOthersOnCall = useCallback((count: number) => {\n othersOnCallRef.current = count;\n }, []);\n\n const hangUp = useCallback(async () => {\n // Leaving a GROUP call is not ending it: walk out quietly and the\n // others keep talking. The signal that tears the call down for\n // everyone is reserved for the last pair.\n if (phaseRef.current === 'active' && othersOnCallRef.current >= 2) {\n setPhase('idle');\n setIncoming(null);\n setOutgoing(null);\n setActiveConversationId(null);\n setActiveCallId(null);\n setActiveMedia(null);\n setError(null);\n return;\n }\n const conversationId =\n activeConversationId ?? incoming?.conversationId ?? outgoing?.conversationId;\n // `activeCallId` first, and that is the whole fix: answering a call\n // clears `incoming`, and a callee never had an `outgoing`, so this\n // used to resolve to undefined and return before signalling. The\n // caller was left in a call the callee had already walked out of.\n const callId = activeCallId ?? incoming?.callId ?? outgoing?.callId;\n\n try {\n if (!calls || !callId || !conversationId) return;\n\n if (phase === 'ringing-out' && outgoing) {\n await calls.cancel(outgoing);\n } else if (phase === 'ringing-in' && incoming) {\n await calls.decline(incoming);\n } else if (phase === 'active') {\n await calls.hangUp({ callId, conversationId });\n }\n } catch (err) {\n setError(err instanceof Error ? err : new Error(String(err)));\n } finally {\n setPhase('idle');\n setIncoming(null);\n setOutgoing(null);\n setActiveConversationId(null);\n setActiveCallId(null);\n setActiveMedia(null);\n }\n }, [calls, phase, incoming, outgoing, activeConversationId, activeCallId]);\n\n const reset = useCallback(() => {\n rejectedRef.current = new Map();\n pendingRef.current = null;\n setPhase('idle');\n setIncoming(null);\n setOutgoing(null);\n setActiveConversationId(null);\n setActiveCallId(null);\n setActiveMedia(null);\n setError(null);\n }, []);\n\n // Whichever end we are: the callee learns it from the ring, the\n // caller from the invite it placed, and `activeMedia` carries it\n // through being answered — the point at which both of the other two\n // can be gone. Idle reports audio rather than holding the last call's\n // value, so a fresh audio call can never inherit video from the one\n // before it.\n const media: CallMedia = incoming?.media ?? outgoing?.media ?? activeMedia ?? 'audio';\n\n return {\n phase,\n incoming,\n outgoing,\n activeConversationId,\n media,\n error,\n call,\n ring,\n dropped,\n accept,\n decline,\n cancel,\n hangUp,\n reportOthersOnCall,\n reset,\n };\n}\n","import type { LiveCall } from '@poolse/sdk';\nimport { useCallback, useEffect, useRef, useState } from 'react';\nimport { usePoolse } from './provider.js';\n\nexport interface UseLiveCall {\n /** The call running on the conversation right now, or null. */\n call: LiveCall | null;\n /** User ids in the call's room at this moment (kept live by `call:participants`). */\n participantIds: string[];\n /** Re-read from the server. */\n refresh: () => void;\n}\n\n/**\n * Whether a call is running on `conversationId` — what a \"Call in\n * progress · Join\" banner needs. Reads once on mount (and after every\n * reconnect, since events sent while the socket was down are gone),\n * then follows the conversation's `call:started`, `call:participants`\n * and `call:finished` events. `null` id → always idle.\n */\nexport function useLiveCall(conversationId: string | null): UseLiveCall {\n const chat = usePoolse();\n const [call, setCall] = useState<LiveCall | null>(null);\n const [participantIds, setParticipantIds] = useState<string[]>([]);\n const callIdRef = useRef<string | null>(null);\n const seq = useRef(0);\n\n const apply = useCallback((next: LiveCall | null) => {\n callIdRef.current = next?.id ?? null;\n setCall(next);\n setParticipantIds(next ? next.participants.map((p) => p.user_id) : []);\n }, []);\n\n const refresh = useCallback(() => {\n if (!conversationId) return;\n const mine = ++seq.current;\n chat.liveCalls\n .get(conversationId)\n .then((c) => {\n if (mine === seq.current) apply(c);\n })\n .catch(() => {\n // A failed read keeps what we have; the next event or reconnect corrects it.\n });\n }, [chat, conversationId, apply]);\n\n useEffect(() => {\n apply(null);\n if (!conversationId) return;\n refresh();\n\n const conv = chat.realtime.conversation(conversationId);\n const offStarted = conv.onCallStarted((evt) => {\n seq.current++; // newer than any read in flight\n apply(evt.call);\n });\n const offParticipants = conv.onCallParticipants((evt) => {\n if (evt.call_id === callIdRef.current) setParticipantIds(evt.participants);\n // A roster for a call we never heard start (joined mid-call): read it.\n else refresh();\n });\n const offFinished = conv.onCallFinished((evt) => {\n if (evt.call_id !== callIdRef.current) return;\n seq.current++;\n apply(null);\n });\n let wasConnected = chat.realtime.getStatus() === 'connected';\n const offStatus = chat.realtime.onStatus((status) => {\n if (status === 'connected' && !wasConnected) refresh();\n wasConnected = status === 'connected';\n });\n return () => {\n offStarted();\n offParticipants();\n offFinished();\n offStatus();\n };\n }, [chat, conversationId, apply, refresh]);\n\n return { call, participantIds, refresh };\n}\n"]}
|