@poolse/react 0.2.0-alpha.3 → 0.2.0-alpha.4

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/CHANGELOG.md CHANGED
@@ -8,6 +8,18 @@ All notable changes to `@poolse/react` are documented here. Format follows
8
8
 
9
9
  ### Added
10
10
 
11
+ - `useMessages` now maintains `Message.reply_count` live — increments
12
+ on inbound thread reply, decrements on reply soft-delete. No server
13
+ round-trip; the thread pill in `<MessageRow>` updates immediately.
14
+
15
+ ### Fixed
16
+
17
+ - `useMembers` catch path now `console.error`s the underlying error
18
+ with a `[poolse]` prefix so silent failures are debuggable from
19
+ DevTools.
20
+
21
+ ### Added (continued)
22
+
11
23
  - `useMessages.edit(messageId, body)` — optimistic edit with rollback
12
24
  on server error. Server enforces sender-only authorization.
13
25
  - `useMessages.delete(messageId)` — optimistic soft-delete (sets
package/dist/index.cjs CHANGED
@@ -209,6 +209,7 @@ function useMembers(conversationId) {
209
209
  setMembers(data);
210
210
  } catch (err) {
211
211
  if (err?.name === "AbortError") return;
212
+ console.error("[poolse] useMembers fetch failed:", err);
212
213
  setError(err instanceof Error ? err : new Error(String(err)));
213
214
  } finally {
214
215
  setLoading(false);
@@ -299,15 +300,32 @@ function useMessages(conversationId) {
299
300
  });
300
301
  const conv = chat.realtime.conversation(conversationId);
301
302
  const offNew = conv.onMessage((msg) => {
302
- setMessages((prev) => upsertById(prev, msg));
303
+ setMessages((prev) => {
304
+ const next = upsertById(prev, msg);
305
+ if (msg.thread_root_id && msg.thread_root_id !== msg.id) {
306
+ return next.map(
307
+ (m) => m.id === msg.thread_root_id ? { ...m, reply_count: (m.reply_count ?? 0) + 1 } : m
308
+ );
309
+ }
310
+ return next;
311
+ });
303
312
  });
304
313
  const offUpdated = conv.onMessageUpdated((msg) => {
305
314
  setMessages((prev) => prev.map((m) => m.id === msg.id ? msg : m));
306
315
  });
307
316
  const offDeleted = conv.onMessageDeleted((evt) => {
308
- setMessages(
309
- (prev) => prev.map((m) => m.id === evt.id ? { ...m, deleted_at: evt.deleted_at, body: null } : m)
310
- );
317
+ setMessages((prev) => {
318
+ const target = prev.find((m) => m.id === evt.id);
319
+ const updated = prev.map(
320
+ (m) => m.id === evt.id ? { ...m, deleted_at: evt.deleted_at, body: null } : m
321
+ );
322
+ if (target?.thread_root_id) {
323
+ return updated.map(
324
+ (m) => m.id === target.thread_root_id ? { ...m, reply_count: Math.max(0, (m.reply_count ?? 0) - 1) } : m
325
+ );
326
+ }
327
+ return updated;
328
+ });
311
329
  });
312
330
  return () => {
313
331
  cancelled = true;
@@ -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"],"names":["createContext","useRef","useMemo","Poolse","useEffect","jsx","useContext","useState","useCallback","PAGE_SIZE","upsertById"],"mappings":"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","file":"index.cjs","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 });\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>:conversation:created` once we\n // know who \"me\" is. Re-subscribes if `me.id` changes (rare — only on\n // sign-in/sign-out within the same provider, which is itself rare).\n useEffect(() => {\n if (!me) return;\n const userChan = chat.realtime.user(me.id);\n const off = userChan.onConversationCreated((conv) => {\n setConversations((prev) => prepend(prev, conv));\n });\n return off;\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","import type { AddMemberOptions, 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. The returned memberships\n * are appended to local state on success.\n */\n addMembers: (externalIds: string[], opts?: { role?: MemberRole }) => Promise<Membership[]>;\n /**\n * Remove a member by user_id. Optimistically removes from state;\n * rolls back on server error.\n */\n removeMember: (userId: Uuid) => 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 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 setMembers(data);\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 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 setMembers((prev) =>\n prev.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 });\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 (userId: Uuid) => {\n const snapshot = membersRef.current;\n setMembers((prev) => prev.filter((m) => m.user_id !== userId));\n try {\n await chat.conversations.one(conversationId).removeMember(userId);\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 { 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\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\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\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 // Realtime listeners.\n const conv = chat.realtime.conversation(conversationId);\n\n const offNew = conv.onMessage((msg) => {\n // Simple by-id upsert. Covers three cases with one expression:\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 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 // 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 ?? crypto.randomUUID();\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 type: attrs.type ?? 'text',\n body: attrs.body ?? null,\n reply_to_id: attrs.reply_to_id ?? null,\n thread_root_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 return {\n messages,\n loading,\n error,\n hasMore,\n loadMore,\n send,\n edit,\n delete: deleteMessage,\n markReadUpTo,\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 { 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\nconst PAGE_SIZE = 50;\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 ?? crypto.randomUUID();\n const tempMsg: Message = {\n id,\n tenant_id: '',\n conversation_id: conversationId,\n sender_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 type { Uuid } from '@poolse/sdk';\nimport { useCallback, useEffect, useRef, useState } from 'react';\nimport { usePoolse } from './provider.js';\nimport { useMe } from './use-me.js';\n\ninterface UseTypingState {\n /** Set of user_ids currently typing. */\n typing: Set<Uuid>;\n /**\n * Send a typing ping to the server. Debounced inside the SDK — the\n * server squashes `typing:start` to one push per (user, conversation,\n * window). Call as often as you want from input handlers.\n */\n signalTyping: () => void;\n}\n\n/**\n * Tracks who's typing in `conversationId`. Subscribes to the\n * `typing:start` / `typing:stop` broadcasts; auto-cleans up entries\n * when stop fires.\n *\n * `signalTyping` debounces on the client side to once per 500 ms so a\n * fast-typing user doesn't flood the channel — poolse does its own\n * server-side debounce too, so both layers are safe.\n */\nexport function useTyping(conversationId: string): UseTypingState {\n const chat = usePoolse();\n const { me } = useMe();\n const [typing, setTyping] = useState<Set<Uuid>>(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 meIdRef = useRef<Uuid | null>(me?.id ?? null);\n meIdRef.current = me?.id ?? null;\n\n useEffect(() => {\n setTyping(new Set());\n\n const conv = chat.realtime.conversation(conversationId);\n\n const offStart = conv.onTypingStart((evt) => {\n // Don't render the current user's own typing — they know they're typing.\n if (meIdRef.current && evt.user_id === meIdRef.current) return;\n setTyping((prev) => {\n if (prev.has(evt.user_id)) return prev;\n const next = new Set(prev);\n next.add(evt.user_id);\n return next;\n });\n });\n\n const offStop = conv.onTypingStop((evt) => {\n if (meIdRef.current && evt.user_id === meIdRef.current) return;\n setTyping((prev) => {\n if (!prev.has(evt.user_id)) return prev;\n const next = new Set(prev);\n next.delete(evt.user_id);\n return next;\n });\n });\n\n return () => {\n offStart();\n offStop();\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, Uuid } from '@poolse/sdk';\nimport { useEffect, useState } from 'react';\nimport { usePoolse } from './provider.js';\n\ninterface UsePresenceState {\n /** Set of user_ids currently online in this conversation. */\n online: Set<Uuid>;\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<Uuid>>(new Set());\n\n useEffect(() => {\n setOnline(new Set());\n\n const conv = chat.realtime.conversation(conversationId);\n\n const applyState = (state: PresenceSnapshot) => {\n setOnline(new Set(Object.keys(state)));\n };\n\n const applyDiff = (diff: { joins?: PresenceSnapshot; leaves?: PresenceSnapshot }) => {\n setOnline((prev) => {\n const next = new Set(prev);\n if (diff.joins) Object.keys(diff.joins).forEach((id) => next.add(id));\n if (diff.leaves) Object.keys(diff.leaves).forEach((id) => next.delete(id));\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 { useCallback, useRef, useState } from 'react';\nimport { usePoolse } from './provider.js';\n\ninterface UseAttachmentUploadState {\n /** Last successfully uploaded attachment, or null. */\n attachment: Attachment | null;\n uploading: boolean;\n error: Error | null;\n /**\n * Run the upload pipeline (presigned-URL request + PUT). Updates\n * local state with the resolved attachment on success; sets `error`\n * and rethrows on failure so callers can surface a toast.\n */\n upload: (input: AttachmentUploadInput) => Promise<Attachment>;\n /** Reset state (clears `attachment`, `error`). */\n reset: () => void;\n}\n\n/**\n * Stateful wrapper around `chat.attachments.upload`. Provides\n * `uploading` + `error` flags for the common \"show a spinner while\n * the PUT is in flight\" UI, plus retention of the last attachment\n * so the caller can reference its id when sending a message.\n *\n * ```tsx\n * const { upload, uploading, attachment } = useAttachmentUpload();\n * const onPick = async (file: File) => {\n * const att = await upload({\n * body: file, contentType: file.type, byteSize: file.size, filename: file.name\n * });\n * await chat.conversations.one(convId).messages.send({\n * body: 'attached',\n * custom_data: { attachment_id: att.id },\n * });\n * };\n * ```\n */\nexport function useAttachmentUpload(): UseAttachmentUploadState {\n const chat = usePoolse();\n const [attachment, setAttachment] = useState<Attachment | null>(null);\n const [uploading, setUploading] = useState(false);\n const [error, setError] = useState<Error | null>(null);\n // Track an in-flight upload's AbortController so unmount cancels it.\n const inFlightRef = useRef<AbortController | null>(null);\n\n const upload = useCallback(\n async (input: AttachmentUploadInput): Promise<Attachment> => {\n // Cancel any prior in-flight upload — last-write-wins on intent.\n inFlightRef.current?.abort();\n const controller = new AbortController();\n inFlightRef.current = controller;\n\n setUploading(true);\n setError(null);\n try {\n const att = await chat.attachments.upload(input, { signal: controller.signal });\n if (inFlightRef.current === controller) {\n setAttachment(att);\n }\n return att;\n } catch (err) {\n if ((err as DOMException)?.name === 'AbortError') throw err;\n const e = err instanceof Error ? err : new Error(String(err));\n setError(e);\n throw e;\n } finally {\n if (inFlightRef.current === controller) {\n setUploading(false);\n inFlightRef.current = null;\n }\n }\n },\n [chat],\n );\n\n const reset = useCallback(() => {\n inFlightRef.current?.abort();\n inFlightRef.current = null;\n setAttachment(null);\n setError(null);\n setUploading(false);\n }, []);\n\n return { attachment, uploading, error, upload, reset };\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"]}
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"],"names":["createContext","useRef","useMemo","Poolse","useEffect","jsx","useContext","useState","useCallback","PAGE_SIZE","upsertById"],"mappings":"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","file":"index.cjs","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 });\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>:conversation:created` once we\n // know who \"me\" is. Re-subscribes if `me.id` changes (rare — only on\n // sign-in/sign-out within the same provider, which is itself rare).\n useEffect(() => {\n if (!me) return;\n const userChan = chat.realtime.user(me.id);\n const off = userChan.onConversationCreated((conv) => {\n setConversations((prev) => prepend(prev, conv));\n });\n return off;\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","import type { AddMemberOptions, 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. The returned memberships\n * are appended to local state on success.\n */\n addMembers: (externalIds: string[], opts?: { role?: MemberRole }) => Promise<Membership[]>;\n /**\n * Remove a member by user_id. Optimistically removes from state;\n * rolls back on server error.\n */\n removeMember: (userId: Uuid) => 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 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 setMembers(data);\n } catch (err) {\n if ((err as DOMException)?.name === 'AbortError') return;\n // Surface to console with a recognisable prefix so callers can\n // grep for it in production logs / DevTools. Without this the\n // hook silently sets `error` state and the UI just shows a\n // generic placeholder.\n console.error('[poolse] useMembers fetch failed:', err);\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 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 setMembers((prev) =>\n prev.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 });\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 (userId: Uuid) => {\n const snapshot = membersRef.current;\n setMembers((prev) => prev.filter((m) => m.user_id !== userId));\n try {\n await chat.conversations.one(conversationId).removeMember(userId);\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 { 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\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\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\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 // Realtime listeners.\n const conv = chat.realtime.conversation(conversationId);\n\n const offNew = conv.onMessage((msg) => {\n // Simple by-id upsert. Covers three cases with one expression:\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) => {\n const next = upsertById(prev, msg);\n // If this is a thread reply, bump the root's reply_count so the\n // thread pill (\"💬 N replies\") updates live without a refetch.\n // Skip when the broadcast IS the root being upserted (msg.id ===\n // thread_root_id is impossible by construction — a root has no\n // thread_root_id — but cheap to guard).\n if (msg.thread_root_id && msg.thread_root_id !== msg.id) {\n return next.map((m) =>\n m.id === msg.thread_root_id ? { ...m, reply_count: (m.reply_count ?? 0) + 1 } : m,\n );\n }\n return next;\n });\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 ?? crypto.randomUUID();\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 type: attrs.type ?? 'text',\n body: attrs.body ?? null,\n reply_to_id: attrs.reply_to_id ?? null,\n thread_root_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 return {\n messages,\n loading,\n error,\n hasMore,\n loadMore,\n send,\n edit,\n delete: deleteMessage,\n markReadUpTo,\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 { 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\nconst PAGE_SIZE = 50;\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 ?? crypto.randomUUID();\n const tempMsg: Message = {\n id,\n tenant_id: '',\n conversation_id: conversationId,\n sender_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 type { Uuid } from '@poolse/sdk';\nimport { useCallback, useEffect, useRef, useState } from 'react';\nimport { usePoolse } from './provider.js';\nimport { useMe } from './use-me.js';\n\ninterface UseTypingState {\n /** Set of user_ids currently typing. */\n typing: Set<Uuid>;\n /**\n * Send a typing ping to the server. Debounced inside the SDK — the\n * server squashes `typing:start` to one push per (user, conversation,\n * window). Call as often as you want from input handlers.\n */\n signalTyping: () => void;\n}\n\n/**\n * Tracks who's typing in `conversationId`. Subscribes to the\n * `typing:start` / `typing:stop` broadcasts; auto-cleans up entries\n * when stop fires.\n *\n * `signalTyping` debounces on the client side to once per 500 ms so a\n * fast-typing user doesn't flood the channel — poolse does its own\n * server-side debounce too, so both layers are safe.\n */\nexport function useTyping(conversationId: string): UseTypingState {\n const chat = usePoolse();\n const { me } = useMe();\n const [typing, setTyping] = useState<Set<Uuid>>(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 meIdRef = useRef<Uuid | null>(me?.id ?? null);\n meIdRef.current = me?.id ?? null;\n\n useEffect(() => {\n setTyping(new Set());\n\n const conv = chat.realtime.conversation(conversationId);\n\n const offStart = conv.onTypingStart((evt) => {\n // Don't render the current user's own typing — they know they're typing.\n if (meIdRef.current && evt.user_id === meIdRef.current) return;\n setTyping((prev) => {\n if (prev.has(evt.user_id)) return prev;\n const next = new Set(prev);\n next.add(evt.user_id);\n return next;\n });\n });\n\n const offStop = conv.onTypingStop((evt) => {\n if (meIdRef.current && evt.user_id === meIdRef.current) return;\n setTyping((prev) => {\n if (!prev.has(evt.user_id)) return prev;\n const next = new Set(prev);\n next.delete(evt.user_id);\n return next;\n });\n });\n\n return () => {\n offStart();\n offStop();\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, Uuid } from '@poolse/sdk';\nimport { useEffect, useState } from 'react';\nimport { usePoolse } from './provider.js';\n\ninterface UsePresenceState {\n /** Set of user_ids currently online in this conversation. */\n online: Set<Uuid>;\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<Uuid>>(new Set());\n\n useEffect(() => {\n setOnline(new Set());\n\n const conv = chat.realtime.conversation(conversationId);\n\n const applyState = (state: PresenceSnapshot) => {\n setOnline(new Set(Object.keys(state)));\n };\n\n const applyDiff = (diff: { joins?: PresenceSnapshot; leaves?: PresenceSnapshot }) => {\n setOnline((prev) => {\n const next = new Set(prev);\n if (diff.joins) Object.keys(diff.joins).forEach((id) => next.add(id));\n if (diff.leaves) Object.keys(diff.leaves).forEach((id) => next.delete(id));\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 { useCallback, useRef, useState } from 'react';\nimport { usePoolse } from './provider.js';\n\ninterface UseAttachmentUploadState {\n /** Last successfully uploaded attachment, or null. */\n attachment: Attachment | null;\n uploading: boolean;\n error: Error | null;\n /**\n * Run the upload pipeline (presigned-URL request + PUT). Updates\n * local state with the resolved attachment on success; sets `error`\n * and rethrows on failure so callers can surface a toast.\n */\n upload: (input: AttachmentUploadInput) => Promise<Attachment>;\n /** Reset state (clears `attachment`, `error`). */\n reset: () => void;\n}\n\n/**\n * Stateful wrapper around `chat.attachments.upload`. Provides\n * `uploading` + `error` flags for the common \"show a spinner while\n * the PUT is in flight\" UI, plus retention of the last attachment\n * so the caller can reference its id when sending a message.\n *\n * ```tsx\n * const { upload, uploading, attachment } = useAttachmentUpload();\n * const onPick = async (file: File) => {\n * const att = await upload({\n * body: file, contentType: file.type, byteSize: file.size, filename: file.name\n * });\n * await chat.conversations.one(convId).messages.send({\n * body: 'attached',\n * custom_data: { attachment_id: att.id },\n * });\n * };\n * ```\n */\nexport function useAttachmentUpload(): UseAttachmentUploadState {\n const chat = usePoolse();\n const [attachment, setAttachment] = useState<Attachment | null>(null);\n const [uploading, setUploading] = useState(false);\n const [error, setError] = useState<Error | null>(null);\n // Track an in-flight upload's AbortController so unmount cancels it.\n const inFlightRef = useRef<AbortController | null>(null);\n\n const upload = useCallback(\n async (input: AttachmentUploadInput): Promise<Attachment> => {\n // Cancel any prior in-flight upload — last-write-wins on intent.\n inFlightRef.current?.abort();\n const controller = new AbortController();\n inFlightRef.current = controller;\n\n setUploading(true);\n setError(null);\n try {\n const att = await chat.attachments.upload(input, { signal: controller.signal });\n if (inFlightRef.current === controller) {\n setAttachment(att);\n }\n return att;\n } catch (err) {\n if ((err as DOMException)?.name === 'AbortError') throw err;\n const e = err instanceof Error ? err : new Error(String(err));\n setError(e);\n throw e;\n } finally {\n if (inFlightRef.current === controller) {\n setUploading(false);\n inFlightRef.current = null;\n }\n }\n },\n [chat],\n );\n\n const reset = useCallback(() => {\n inFlightRef.current?.abort();\n inFlightRef.current = null;\n setAttachment(null);\n setError(null);\n setUploading(false);\n }, []);\n\n return { attachment, uploading, error, upload, reset };\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"]}
package/dist/index.js CHANGED
@@ -208,6 +208,7 @@ function useMembers(conversationId) {
208
208
  setMembers(data);
209
209
  } catch (err) {
210
210
  if (err?.name === "AbortError") return;
211
+ console.error("[poolse] useMembers fetch failed:", err);
211
212
  setError(err instanceof Error ? err : new Error(String(err)));
212
213
  } finally {
213
214
  setLoading(false);
@@ -298,15 +299,32 @@ function useMessages(conversationId) {
298
299
  });
299
300
  const conv = chat.realtime.conversation(conversationId);
300
301
  const offNew = conv.onMessage((msg) => {
301
- setMessages((prev) => upsertById(prev, msg));
302
+ setMessages((prev) => {
303
+ const next = upsertById(prev, msg);
304
+ if (msg.thread_root_id && msg.thread_root_id !== msg.id) {
305
+ return next.map(
306
+ (m) => m.id === msg.thread_root_id ? { ...m, reply_count: (m.reply_count ?? 0) + 1 } : m
307
+ );
308
+ }
309
+ return next;
310
+ });
302
311
  });
303
312
  const offUpdated = conv.onMessageUpdated((msg) => {
304
313
  setMessages((prev) => prev.map((m) => m.id === msg.id ? msg : m));
305
314
  });
306
315
  const offDeleted = conv.onMessageDeleted((evt) => {
307
- setMessages(
308
- (prev) => prev.map((m) => m.id === evt.id ? { ...m, deleted_at: evt.deleted_at, body: null } : m)
309
- );
316
+ setMessages((prev) => {
317
+ const target = prev.find((m) => m.id === evt.id);
318
+ const updated = prev.map(
319
+ (m) => m.id === evt.id ? { ...m, deleted_at: evt.deleted_at, body: null } : m
320
+ );
321
+ if (target?.thread_root_id) {
322
+ return updated.map(
323
+ (m) => m.id === target.thread_root_id ? { ...m, reply_count: Math.max(0, (m.reply_count ?? 0) - 1) } : m
324
+ );
325
+ }
326
+ return updated;
327
+ });
310
328
  });
311
329
  return () => {
312
330
  cancelled = true;
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"],"names":["useEffect","useState","useCallback","useMemo","useRef","PAGE_SIZE","upsertById"],"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 });\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>:conversation:created` once we\n // know who \"me\" is. Re-subscribes if `me.id` changes (rare — only on\n // sign-in/sign-out within the same provider, which is itself rare).\n useEffect(() => {\n if (!me) return;\n const userChan = chat.realtime.user(me.id);\n const off = userChan.onConversationCreated((conv) => {\n setConversations((prev) => prepend(prev, conv));\n });\n return off;\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","import type { AddMemberOptions, 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. The returned memberships\n * are appended to local state on success.\n */\n addMembers: (externalIds: string[], opts?: { role?: MemberRole }) => Promise<Membership[]>;\n /**\n * Remove a member by user_id. Optimistically removes from state;\n * rolls back on server error.\n */\n removeMember: (userId: Uuid) => 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 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 setMembers(data);\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 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 setMembers((prev) =>\n prev.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 });\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 (userId: Uuid) => {\n const snapshot = membersRef.current;\n setMembers((prev) => prev.filter((m) => m.user_id !== userId));\n try {\n await chat.conversations.one(conversationId).removeMember(userId);\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 { 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\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\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\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 // Realtime listeners.\n const conv = chat.realtime.conversation(conversationId);\n\n const offNew = conv.onMessage((msg) => {\n // Simple by-id upsert. Covers three cases with one expression:\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 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 // 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 ?? crypto.randomUUID();\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 type: attrs.type ?? 'text',\n body: attrs.body ?? null,\n reply_to_id: attrs.reply_to_id ?? null,\n thread_root_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 return {\n messages,\n loading,\n error,\n hasMore,\n loadMore,\n send,\n edit,\n delete: deleteMessage,\n markReadUpTo,\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 { 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\nconst PAGE_SIZE = 50;\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 ?? crypto.randomUUID();\n const tempMsg: Message = {\n id,\n tenant_id: '',\n conversation_id: conversationId,\n sender_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 type { Uuid } from '@poolse/sdk';\nimport { useCallback, useEffect, useRef, useState } from 'react';\nimport { usePoolse } from './provider.js';\nimport { useMe } from './use-me.js';\n\ninterface UseTypingState {\n /** Set of user_ids currently typing. */\n typing: Set<Uuid>;\n /**\n * Send a typing ping to the server. Debounced inside the SDK — the\n * server squashes `typing:start` to one push per (user, conversation,\n * window). Call as often as you want from input handlers.\n */\n signalTyping: () => void;\n}\n\n/**\n * Tracks who's typing in `conversationId`. Subscribes to the\n * `typing:start` / `typing:stop` broadcasts; auto-cleans up entries\n * when stop fires.\n *\n * `signalTyping` debounces on the client side to once per 500 ms so a\n * fast-typing user doesn't flood the channel — poolse does its own\n * server-side debounce too, so both layers are safe.\n */\nexport function useTyping(conversationId: string): UseTypingState {\n const chat = usePoolse();\n const { me } = useMe();\n const [typing, setTyping] = useState<Set<Uuid>>(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 meIdRef = useRef<Uuid | null>(me?.id ?? null);\n meIdRef.current = me?.id ?? null;\n\n useEffect(() => {\n setTyping(new Set());\n\n const conv = chat.realtime.conversation(conversationId);\n\n const offStart = conv.onTypingStart((evt) => {\n // Don't render the current user's own typing — they know they're typing.\n if (meIdRef.current && evt.user_id === meIdRef.current) return;\n setTyping((prev) => {\n if (prev.has(evt.user_id)) return prev;\n const next = new Set(prev);\n next.add(evt.user_id);\n return next;\n });\n });\n\n const offStop = conv.onTypingStop((evt) => {\n if (meIdRef.current && evt.user_id === meIdRef.current) return;\n setTyping((prev) => {\n if (!prev.has(evt.user_id)) return prev;\n const next = new Set(prev);\n next.delete(evt.user_id);\n return next;\n });\n });\n\n return () => {\n offStart();\n offStop();\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, Uuid } from '@poolse/sdk';\nimport { useEffect, useState } from 'react';\nimport { usePoolse } from './provider.js';\n\ninterface UsePresenceState {\n /** Set of user_ids currently online in this conversation. */\n online: Set<Uuid>;\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<Uuid>>(new Set());\n\n useEffect(() => {\n setOnline(new Set());\n\n const conv = chat.realtime.conversation(conversationId);\n\n const applyState = (state: PresenceSnapshot) => {\n setOnline(new Set(Object.keys(state)));\n };\n\n const applyDiff = (diff: { joins?: PresenceSnapshot; leaves?: PresenceSnapshot }) => {\n setOnline((prev) => {\n const next = new Set(prev);\n if (diff.joins) Object.keys(diff.joins).forEach((id) => next.add(id));\n if (diff.leaves) Object.keys(diff.leaves).forEach((id) => next.delete(id));\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 { useCallback, useRef, useState } from 'react';\nimport { usePoolse } from './provider.js';\n\ninterface UseAttachmentUploadState {\n /** Last successfully uploaded attachment, or null. */\n attachment: Attachment | null;\n uploading: boolean;\n error: Error | null;\n /**\n * Run the upload pipeline (presigned-URL request + PUT). Updates\n * local state with the resolved attachment on success; sets `error`\n * and rethrows on failure so callers can surface a toast.\n */\n upload: (input: AttachmentUploadInput) => Promise<Attachment>;\n /** Reset state (clears `attachment`, `error`). */\n reset: () => void;\n}\n\n/**\n * Stateful wrapper around `chat.attachments.upload`. Provides\n * `uploading` + `error` flags for the common \"show a spinner while\n * the PUT is in flight\" UI, plus retention of the last attachment\n * so the caller can reference its id when sending a message.\n *\n * ```tsx\n * const { upload, uploading, attachment } = useAttachmentUpload();\n * const onPick = async (file: File) => {\n * const att = await upload({\n * body: file, contentType: file.type, byteSize: file.size, filename: file.name\n * });\n * await chat.conversations.one(convId).messages.send({\n * body: 'attached',\n * custom_data: { attachment_id: att.id },\n * });\n * };\n * ```\n */\nexport function useAttachmentUpload(): UseAttachmentUploadState {\n const chat = usePoolse();\n const [attachment, setAttachment] = useState<Attachment | null>(null);\n const [uploading, setUploading] = useState(false);\n const [error, setError] = useState<Error | null>(null);\n // Track an in-flight upload's AbortController so unmount cancels it.\n const inFlightRef = useRef<AbortController | null>(null);\n\n const upload = useCallback(\n async (input: AttachmentUploadInput): Promise<Attachment> => {\n // Cancel any prior in-flight upload — last-write-wins on intent.\n inFlightRef.current?.abort();\n const controller = new AbortController();\n inFlightRef.current = controller;\n\n setUploading(true);\n setError(null);\n try {\n const att = await chat.attachments.upload(input, { signal: controller.signal });\n if (inFlightRef.current === controller) {\n setAttachment(att);\n }\n return att;\n } catch (err) {\n if ((err as DOMException)?.name === 'AbortError') throw err;\n const e = err instanceof Error ? err : new Error(String(err));\n setError(e);\n throw e;\n } finally {\n if (inFlightRef.current === controller) {\n setUploading(false);\n inFlightRef.current = null;\n }\n }\n },\n [chat],\n );\n\n const reset = useCallback(() => {\n inFlightRef.current?.abort();\n inFlightRef.current = null;\n setAttachment(null);\n setError(null);\n setUploading(false);\n }, []);\n\n return { attachment, uploading, error, upload, reset };\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"]}
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"],"names":["useEffect","useState","useCallback","useMemo","useRef","PAGE_SIZE","upsertById"],"mappings":";;;;;;AAOA,IAAM,aAAA,GAAgB,cAAyC,IAAI,CAAA;AAgC5D,SAAS,cAAA,CAAe,EAAE,MAAA,EAAQ,QAAA,EAAS,EAAwB;AAQxE,EAAA,MAAM,SAAA,GAAY,OAAO,MAAM,CAAA;AAC/B,EAAA,SAAA,CAAU,OAAA,GAAU,MAAA;AAGpB,EAAA,MAAM,oBAAA,GAAuB,OAInB,IAAI,CAAA;AAEd,EAAA,MAAM,IAAA,GAAO,QAAQ,MAAM;AACzB,IAAA,MAAM,UAAU,SAAA,CAAU,OAAA;AAC1B,IAAA,oBAAA,CAAqB,OAAA,GAAU;AAAA,MAC7B,QAAQ,OAAA,CAAQ,MAAA;AAAA,MAChB,OAAO,OAAA,CAAQ,KAAA;AAAA,MACf,YAAY,OAAA,CAAQ;AAAA,KACtB;AACA,IAAA,OAAO,IAAI,MAAA,CAAO;AAAA;AAAA;AAAA,MAGhB,GAAI,QAAQ,MAAA,KAAW,MAAA,GAAY,EAAE,MAAA,EAAQ,OAAA,CAAQ,MAAA,EAAO,GAAI,EAAC;AAAA;AAAA;AAAA,MAGjE,QAAA,EAAU,MAAM,SAAA,CAAU,OAAA,CAAQ,QAAA,EAAS;AAAA,MAC3C,GAAI,OAAA,CAAQ,KAAA,GACR,EAAE,QAAQ,CAAA,GAAI,IAAA,KAAS,SAAA,CAAU,OAAA,CAAQ,KAAA,CAAO,GAAG,IAAI,CAAA,CAAA,KACvD,EAAC;AAAA,MACL,GAAI,QAAQ,UAAA,KAAe,MAAA,GAAY,EAAE,UAAA,EAAY,OAAA,CAAQ,UAAA,EAAW,GAAI,EAAC;AAAA,MAC7E,GAAI,QAAQ,aAAA,KAAkB,MAAA,GAAY,EAAE,aAAA,EAAe,OAAA,CAAQ,aAAA,EAAc,GAAI,EAAC;AAAA,MACtF,GAAI,QAAQ,YAAA,KAAiB,MAAA,GAAY,EAAE,YAAA,EAAc,OAAA,CAAQ,YAAA,EAAa,GAAI,EAAC;AAAA,MACnF,GAAI,OAAA,CAAQ,sBAAA,GACR,EAAE,sBAAA,EAAwB,MAAM,SAAA,CAAU,OAAA,CAAQ,sBAAA,EAAwB,EAAE,GAC5E,EAAC;AAAA,MACL,GAAI,QAAQ,KAAA,KAAU,MAAA,GAAY,EAAE,KAAA,EAAO,OAAA,CAAQ,KAAA,EAAM,GAAI,EAAC;AAAA,MAC9D,GAAI,QAAQ,UAAA,KAAe,MAAA,GAAY,EAAE,UAAA,EAAY,OAAA,CAAQ,UAAA,EAAW,GAAI,EAAC;AAAA,MAC7E,GAAI,OAAA,CAAQ,aAAA,GACR,EAAE,aAAA,EAAe,CAAC,GAAA,KAAQ,SAAA,CAAU,OAAA,CAAQ,aAAA,CAAe,GAAG,CAAA,KAC9D;AAAC,KACN,CAAA;AAAA,EAIH,CAAA,EAAG,EAAE,CAAA;AAKL,EAAA,IAAI,OAAA,CAAQ,GAAA,CAAI,QAAA,KAAa,YAAA,EAAc;AAEzC,IAAA,SAAA,CAAU,MAAM;AACd,MAAA,MAAM,UAAU,oBAAA,CAAqB,OAAA;AACrC,MAAA,IAAI,CAAC,OAAA,EAAS;AACd,MAAA,IACE,OAAA,CAAQ,MAAA,KAAW,MAAA,CAAO,MAAA,IAC1B,OAAA,CAAQ,KAAA,KAAU,MAAA,CAAO,KAAA,IACzB,OAAA,CAAQ,UAAA,KAAe,MAAA,CAAO,UAAA,EAC9B;AACA,QAAA,OAAA,CAAQ,IAAA;AAAA,UACN;AAAA,SAIF;AAAA,MACF;AAAA,IACF,CAAA,EAAG,CAAC,MAAA,CAAO,MAAA,EAAQ,OAAO,KAAA,EAAO,MAAA,CAAO,UAAU,CAAC,CAAA;AAAA,EACrD;AAEA,EAAA,SAAA,CAAU,MAAM;AACd,IAAA,OAAO,MAAM;AACX,MAAA,IAAA,CAAK,OAAA,EAAQ;AAAA,IACf,CAAA;AAAA,EACF,CAAA,EAAG,CAAC,IAAI,CAAC,CAAA;AAET,EAAA,MAAM,KAAA,GAAQ,QAAQ,OAAO,EAAE,MAAK,CAAA,EAAI,CAAC,IAAI,CAAC,CAAA;AAE9C,EAAA,uBAAO,GAAA,CAAC,aAAA,CAAc,QAAA,EAAd,EAAuB,OAAe,QAAA,EAAS,CAAA;AACzD;AAQO,SAAS,SAAA,GAAoB;AAClC,EAAA,MAAM,KAAA,GAAQ,WAAW,aAAa,CAAA;AAEtC,EAAA,IAAI,CAAC,KAAA,EAAO;AACV,IAAA,MAAM,IAAI,KAAA;AAAA,MACR;AAAA,KAEF;AAAA,EACF;AAEA,EAAA,OAAO,KAAA,CAAM,IAAA;AACf;AC3HO,SAAS,KAAA,GAAoB;AAClC,EAAA,MAAM,OAAO,SAAA,EAAU;AACvB,EAAA,MAAM,CAAC,KAAA,EAAO,QAAQ,CAAA,GAAI,QAAA,CAAqB;AAAA,IAC7C,EAAA,EAAI,IAAA;AAAA,IACJ,OAAA,EAAS,IAAA;AAAA,IACT,KAAA,EAAO;AAAA,GACR,CAAA;AAED,EAAAA,UAAU,MAAM;AACd,IAAA,IAAI,SAAA,GAAY,KAAA;AAChB,IAAA,MAAM,UAAA,GAAa,IAAI,eAAA,EAAgB;AAEvC,IAAA,IAAA,CAAK,GACF,IAAA,CAAK,UAAA,CAAW,MAAM,CAAA,CACtB,IAAA,CAAK,CAAC,EAAA,KAAO;AACZ,MAAA,IAAI,CAAC,WAAW,QAAA,CAAS,EAAE,IAAI,OAAA,EAAS,KAAA,EAAO,KAAA,EAAO,IAAA,EAAM,CAAA;AAAA,IAC9D,CAAC,CAAA,CACA,KAAA,CAAM,CAAC,GAAA,KAAiB;AACvB,MAAA,IAAI,CAAC,SAAA,EAAW;AACd,QAAA,QAAA,CAAS;AAAA,UACP,EAAA,EAAI,IAAA;AAAA,UACJ,OAAA,EAAS,KAAA;AAAA,UACT,KAAA,EAAO,eAAe,KAAA,GAAQ,GAAA,GAAM,IAAI,KAAA,CAAM,MAAA,CAAO,GAAG,CAAC;AAAA,SAC1D,CAAA;AAAA,MACH;AAAA,IACF,CAAC,CAAA;AAEH,IAAA,OAAO,MAAM;AACX,MAAA,SAAA,GAAY,IAAA;AACZ,MAAA,UAAA,CAAW,KAAA,EAAM;AAAA,IACnB,CAAA;AAAA,EACF,CAAA,EAAG,CAAC,IAAI,CAAC,CAAA;AAET,EAAA,OAAO,KAAA;AACT;ACzBO,SAAS,gBAAgB,EAAA,EAAuC;AACrE,EAAA,MAAM,OAAO,SAAA,EAAU;AACvB,EAAA,MAAM,CAAC,YAAA,EAAc,eAAe,CAAA,GAAIC,SAA8B,IAAI,CAAA;AAC1E,EAAA,MAAM,CAAC,OAAA,EAAS,UAAU,CAAA,GAAIA,QAAAA,CAAS,OAAO,IAAI,CAAA;AAClD,EAAA,MAAM,CAAC,KAAA,EAAO,QAAQ,CAAA,GAAIA,SAAuB,IAAI,CAAA;AAKrD,EAAA,MAAM,OAAA,GAAU,WAAA;AAAA,IACd,OAAO,MAAA,KAAwC;AAC7C,MAAA,IAAI,OAAO,IAAA,EAAM;AACjB,MAAA,UAAA,CAAW,IAAI,CAAA;AACf,MAAA,QAAA,CAAS,IAAI,CAAA;AACb,MAAA,IAAI;AACF,QAAA,MAAM,IAAA,GAAO,MAAM,IAAA,CAAK,aAAA,CAAc,IAAI,EAAE,CAAA,CAAE,KAAK,MAAM,CAAA;AACzD,QAAA,eAAA,CAAgB,IAAI,CAAA;AAAA,MACtB,SAAS,GAAA,EAAK;AAEZ,QAAA,IAAK,GAAA,EAAsB,SAAS,YAAA,EAAc;AAClD,QAAA,QAAA,CAAS,GAAA,YAAe,QAAQ,GAAA,GAAM,IAAI,MAAM,MAAA,CAAO,GAAG,CAAC,CAAC,CAAA;AAAA,MAC9D,CAAA,SAAE;AACA,QAAA,UAAA,CAAW,KAAK,CAAA;AAAA,MAClB;AAAA,IACF,CAAA;AAAA,IACA,CAAC,MAAM,EAAE;AAAA,GACX;AAEA,EAAAD,UAAU,MAAM;AACd,IAAA,IAAI,OAAO,IAAA,EAAM;AACf,MAAA,eAAA,CAAgB,IAAI,CAAA;AACpB,MAAA,UAAA,CAAW,KAAK,CAAA;AAChB,MAAA,QAAA,CAAS,IAAI,CAAA;AACb,MAAA;AAAA,IACF;AACA,IAAA,MAAM,UAAA,GAAa,IAAI,eAAA,EAAgB;AACvC,IAAA,KAAK,OAAA,CAAQ,WAAW,MAAM,CAAA;AAC9B,IAAA,OAAO,MAAM,WAAW,KAAA,EAAM;AAAA,EAChC,CAAA,EAAG,CAAC,OAAA,EAAS,EAAE,CAAC,CAAA;AAEhB,EAAA,MAAM,UAAU,WAAA,CAAY,MAAM,SAAQ,EAAG,CAAC,OAAO,CAAC,CAAA;AAEtD,EAAA,OAAO,EAAE,YAAA,EAAc,OAAA,EAAS,KAAA,EAAO,OAAA,EAAQ;AACjD;AC9BO,SAAS,gBAAA,GAA0C;AACxD,EAAA,MAAM,OAAO,SAAA,EAAU;AACvB,EAAA,MAAM,EAAE,EAAA,EAAG,GAAI,KAAA,EAAM;AACrB,EAAA,MAAM,CAAC,aAAA,EAAe,gBAAgB,CAAA,GAAIC,QAAAA,CAAyB,EAAE,CAAA;AACrE,EAAA,MAAM,CAAC,OAAA,EAAS,UAAU,CAAA,GAAIA,SAAS,IAAI,CAAA;AAC3C,EAAA,MAAM,CAAC,KAAA,EAAO,QAAQ,CAAA,GAAIA,SAAuB,IAAI,CAAA;AAErD,EAAA,MAAM,OAAA,GAAUC,YAAY,YAAY;AACtC,IAAA,UAAA,CAAW,IAAI,CAAA;AACf,IAAA,IAAI;AACF,MAAA,MAAM,IAAA,GAAO,MAAM,IAAA,CAAK,aAAA,CAAc,IAAA,EAAK;AAC3C,MAAA,gBAAA,CAAiB,KAAK,IAAI,CAAA;AAC1B,MAAA,QAAA,CAAS,IAAI,CAAA;AAAA,IACf,SAAS,GAAA,EAAK;AACZ,MAAA,QAAA,CAAS,GAAA,YAAe,QAAQ,GAAA,GAAM,IAAI,MAAM,MAAA,CAAO,GAAG,CAAC,CAAC,CAAA;AAAA,IAC9D,CAAA,SAAE;AACA,MAAA,UAAA,CAAW,KAAK,CAAA;AAAA,IAClB;AAAA,EACF,CAAA,EAAG,CAAC,IAAI,CAAC,CAAA;AAET,EAAA,MAAM,MAAA,GAASA,WAAAA;AAAA,IACb,OAAO,KAAA,KAAqC;AAC1C,MAAA,MAAM,IAAA,GAAO,MAAM,IAAA,CAAK,aAAA,CAAc,OAAO,KAAK,CAAA;AAKlD,MAAA,gBAAA,CAAiB,CAAC,IAAA,KAAS,OAAA,CAAQ,IAAA,EAAM,IAAI,CAAC,CAAA;AAC9C,MAAA,OAAO,IAAA;AAAA,IACT,CAAA;AAAA,IACA,CAAC,IAAI;AAAA,GACP;AAEA,EAAAF,UAAU,MAAM;AACd,IAAA,KAAK,OAAA,EAAQ;AAAA,EACf,CAAA,EAAG,CAAC,OAAO,CAAC,CAAA;AAKZ,EAAAA,UAAU,MAAM;AACd,IAAA,IAAI,CAAC,EAAA,EAAI;AACT,IAAA,MAAM,QAAA,GAAW,IAAA,CAAK,QAAA,CAAS,IAAA,CAAK,GAAG,EAAE,CAAA;AACzC,IAAA,MAAM,GAAA,GAAM,QAAA,CAAS,qBAAA,CAAsB,CAAC,IAAA,KAAS;AACnD,MAAA,gBAAA,CAAiB,CAAC,IAAA,KAAS,OAAA,CAAQ,IAAA,EAAM,IAAI,CAAC,CAAA;AAAA,IAChD,CAAC,CAAA;AACD,IAAA,OAAO,GAAA;AAAA,EACT,CAAA,EAAG,CAAC,IAAA,EAAM,EAAE,CAAC,CAAA;AAMb,EAAA,MAAM,oBAAA,GAAuBE,WAAAA,CAAY,CAAC,cAAA,KAAyB;AACjE,IAAA,gBAAA;AAAA,MAAiB,CAAC,IAAA,KAChB,IAAA,CAAK,GAAA,CAAI,CAAC,CAAA,KAAO,CAAA,CAAE,EAAA,KAAO,cAAA,GAAiB,EAAE,GAAG,CAAA,EAAG,YAAA,EAAc,CAAA,KAAM,CAAE;AAAA,KAC3E;AAAA,EACF,CAAA,EAAG,EAAE,CAAA;AAEL,EAAA,MAAM,YAAA,GAAeC,QAA8B,MAAM;AACvD,IAAA,MAAM,MAA4B,EAAC;AACnC,IAAA,KAAA,MAAW,KAAK,aAAA,EAAe;AAC7B,MAAA,IAAI,OAAO,CAAA,CAAE,YAAA,KAAiB,QAAA,IAAY,CAAA,CAAE,eAAe,CAAA,EAAG;AAC5D,QAAA,GAAA,CAAI,CAAA,CAAE,EAAE,CAAA,GAAI,CAAA,CAAE,YAAA;AAAA,MAChB;AAAA,IACF;AACA,IAAA,OAAO,GAAA;AAAA,EACT,CAAA,EAAG,CAAC,aAAa,CAAC,CAAA;AAElB,EAAA,OAAO,EAAE,aAAA,EAAe,OAAA,EAAS,OAAO,OAAA,EAAS,MAAA,EAAQ,cAAc,oBAAA,EAAqB;AAC9F;AAOA,SAAS,OAAA,CAAQ,MAAsB,IAAA,EAAoC;AACzE,EAAA,MAAM,GAAA,GAAM,KAAK,SAAA,CAAU,CAAC,MAAM,CAAA,CAAE,EAAA,KAAO,KAAK,EAAE,CAAA;AAClD,EAAA,IAAI,QAAQ,EAAA,EAAI,OAAO,CAAC,IAAA,EAAM,GAAG,IAAI,CAAA;AACrC,EAAA,MAAM,IAAA,GAAO,KAAK,KAAA,EAAM;AACxB,EAAA,IAAA,CAAK,GAAG,CAAA,GAAI,IAAA;AACZ,EAAA,OAAO,IAAA;AACT;AC7FO,SAAS,WAAW,cAAA,EAAuC;AAChE,EAAA,MAAM,OAAO,SAAA,EAAU;AACvB,EAAA,MAAM,CAAC,OAAA,EAAS,UAAU,CAAA,GAAIF,QAAAA,CAAuB,EAAE,CAAA;AACvD,EAAA,MAAM,CAAC,OAAA,EAAS,UAAU,CAAA,GAAIA,SAAS,IAAI,CAAA;AAC3C,EAAA,MAAM,CAAC,KAAA,EAAO,QAAQ,CAAA,GAAIA,SAAuB,IAAI,CAAA;AAKrD,EAAA,MAAM,UAAA,GAAaG,MAAAA,CAAqB,EAAE,CAAA;AAC1C,EAAA,UAAA,CAAW,OAAA,GAAU,OAAA;AAErB,EAAA,MAAM,OAAA,GAAUF,WAAAA;AAAA,IACd,OAAO,MAAA,KAAwC;AAK7C,MAAA,IAAI,CAAC,cAAA,EAAgB;AACnB,QAAA,UAAA,CAAW,KAAK,CAAA;AAChB,QAAA,UAAA,CAAW,EAAE,CAAA;AACb,QAAA,QAAA,CAAS,IAAI,CAAA;AACb,QAAA;AAAA,MACF;AACA,MAAA,UAAA,CAAW,IAAI,CAAA;AACf,MAAA,QAAA,CAAS,IAAI,CAAA;AACb,MAAA,IAAI;AACF,QAAA,MAAM,EAAE,IAAA,EAAK,GAAI,MAAM,IAAA,CAAK,cAAc,GAAA,CAAI,cAAc,CAAA,CAAE,WAAA,CAAY,MAAM,CAAA;AAChF,QAAA,UAAA,CAAW,IAAI,CAAA;AAAA,MACjB,SAAS,GAAA,EAAK;AACZ,QAAA,IAAK,GAAA,EAAsB,SAAS,YAAA,EAAc;AAKlD,QAAA,OAAA,CAAQ,KAAA,CAAM,qCAAqC,GAAG,CAAA;AACtD,QAAA,QAAA,CAAS,GAAA,YAAe,QAAQ,GAAA,GAAM,IAAI,MAAM,MAAA,CAAO,GAAG,CAAC,CAAC,CAAA;AAAA,MAC9D,CAAA,SAAE;AACA,QAAA,UAAA,CAAW,KAAK,CAAA;AAAA,MAClB;AAAA,IACF,CAAA;AAAA,IACA,CAAC,MAAM,cAAc;AAAA,GACvB;AAEA,EAAAF,UAAU,MAAM;AACd,IAAA,MAAM,UAAA,GAAa,IAAI,eAAA,EAAgB;AACvC,IAAA,KAAK,OAAA,CAAQ,WAAW,MAAM,CAAA;AAC9B,IAAA,OAAO,MAAM,WAAW,KAAA,EAAM;AAAA,EAChC,CAAA,EAAG,CAAC,OAAO,CAAC,CAAA;AAOZ,EAAAA,UAAU,MAAM;AACd,IAAA,IAAI,CAAC,cAAA,EAAgB;AACrB,IAAA,MAAM,OAAA,GAAU,IAAA,CAAK,QAAA,CAAS,YAAA,CAAa,cAAc,CAAA;AACzD,IAAA,MAAM,GAAA,GAAM,OAAA,CAAQ,YAAA,CAAa,CAAC,GAAA,KAAQ;AACxC,MAAA,UAAA;AAAA,QAAW,CAAC,SACV,IAAA,CAAK,GAAA;AAAA,UAAI,CAAC,CAAA,KACR,CAAA,CAAE,OAAA,KAAY,IAAI,OAAA,GACd;AAAA,YACE,GAAG,CAAA;AAAA,YACH,sBAAsB,GAAA,CAAI,oBAAA;AAAA,YAC1B,cAAc,GAAA,CAAI;AAAA,WACpB,GACA;AAAA;AACN,OACF;AAAA,IACF,CAAC,CAAA;AACD,IAAA,OAAO,MAAM,GAAA,EAAI;AAAA,EACnB,CAAA,EAAG,CAAC,IAAA,EAAM,cAAc,CAAC,CAAA;AAEzB,EAAA,MAAM,UAAUE,WAAAA,CAAY,MAAM,SAAQ,EAAG,CAAC,OAAO,CAAC,CAAA;AAEtD,EAAA,MAAM,UAAA,GAAaA,WAAAA;AAAA,IACjB,OAAO,WAAA,EAAuB,IAAA,GAA8B,EAAC,KAAM;AACjE,MAAA,MAAM,OAAA,GAA4B,KAAK,IAAA,KAAS,MAAA,GAAY,EAAE,IAAA,EAAM,IAAA,CAAK,IAAA,EAAK,GAAI,EAAC;AACnF,MAAA,MAAM,EAAE,IAAA,EAAK,GAAI,MAAM,IAAA,CAAK,aAAA,CACzB,GAAA,CAAI,cAAc,CAAA,CAClB,UAAA,CAAW,WAAA,EAAa,OAAO,CAAA;AAGlC,MAAA,UAAA,CAAW,CAAC,IAAA,KAAS;AACnB,QAAA,MAAM,IAAA,GAAO,IAAI,GAAA,CAAI,IAAA,CAAK,GAAA,CAAI,CAAC,CAAA,KAAM,CAAC,CAAA,CAAE,EAAA,EAAI,CAAC,CAAC,CAAC,CAAA;AAC/C,QAAA,KAAA,MAAW,KAAK,IAAA,EAAM,IAAA,CAAK,GAAA,CAAI,CAAA,CAAE,IAAI,CAAC,CAAA;AACtC,QAAA,OAAO,KAAA,CAAM,IAAA,CAAK,IAAA,CAAK,MAAA,EAAQ,CAAA;AAAA,MACjC,CAAC,CAAA;AACD,MAAA,OAAO,IAAA;AAAA,IACT,CAAA;AAAA,IACA,CAAC,MAAM,cAAc;AAAA,GACvB;AAEA,EAAA,MAAM,YAAA,GAAeA,WAAAA;AAAA,IACnB,OAAO,MAAA,KAAiB;AACtB,MAAA,MAAM,WAAW,UAAA,CAAW,OAAA;AAC5B,MAAA,UAAA,CAAW,CAAC,SAAS,IAAA,CAAK,MAAA,CAAO,CAAC,CAAA,KAAM,CAAA,CAAE,OAAA,KAAY,MAAM,CAAC,CAAA;AAC7D,MAAA,IAAI;AACF,QAAA,MAAM,KAAK,aAAA,CAAc,GAAA,CAAI,cAAc,CAAA,CAAE,aAAa,MAAM,CAAA;AAAA,MAClE,SAAS,GAAA,EAAK;AACZ,QAAA,UAAA,CAAW,QAAQ,CAAA;AACnB,QAAA,MAAM,GAAA;AAAA,MACR;AAAA,IACF,CAAA;AAAA,IACA,CAAC,MAAM,cAAc;AAAA,GACvB;AAEA,EAAA,OAAO,EAAE,OAAA,EAAS,OAAA,EAAS,KAAA,EAAO,OAAA,EAAS,YAAY,YAAA,EAAa;AACtE;ACvGA,IAAM,SAAA,GAAY,EAAA;AAiBX,SAAS,YAAY,cAAA,EAA0C;AACpE,EAAA,MAAM,OAAO,SAAA,EAAU;AACvB,EAAA,MAAM,EAAE,EAAA,EAAG,GAAI,KAAA,EAAM;AACrB,EAAA,MAAM,CAAC,QAAA,EAAU,WAAW,CAAA,GAAID,QAAAA,CAAoB,EAAE,CAAA;AACtD,EAAA,MAAM,CAAC,OAAA,EAAS,UAAU,CAAA,GAAIA,SAAS,IAAI,CAAA;AAC3C,EAAA,MAAM,CAAC,KAAA,EAAO,QAAQ,CAAA,GAAIA,SAAuB,IAAI,CAAA;AACrD,EAAA,MAAM,CAAC,OAAA,EAAS,UAAU,CAAA,GAAIA,SAAS,IAAI,CAAA;AAG3C,EAAA,MAAM,iBAAA,GAAoBG,OAAsB,IAAI,CAAA;AAKpD,EAAA,MAAM,OAAA,GAAUA,MAAAA,CAAsB,EAAA,EAAI,EAAA,IAAM,IAAI,CAAA;AACpD,EAAA,OAAA,CAAQ,OAAA,GAAU,IAAI,EAAA,IAAM,IAAA;AAE5B,EAAAJ,UAAU,MAAM;AACd,IAAA,IAAI,SAAA,GAAY,KAAA;AAChB,IAAA,UAAA,CAAW,IAAI,CAAA;AACf,IAAA,WAAA,CAAY,EAAE,CAAA;AACd,IAAA,QAAA,CAAS,IAAI,CAAA;AACb,IAAA,UAAA,CAAW,IAAI,CAAA;AACf,IAAA,iBAAA,CAAkB,OAAA,GAAU,IAAA;AAE5B,IAAA,MAAM,MAAA,GAAS,IAAA,CAAK,aAAA,CAAc,GAAA,CAAI,cAAc,CAAA,CAAE,QAAA;AAEtD,IAAA,MAAA,CACG,IAAA,CAAK,EAAE,KAAA,EAAO,SAAA,EAAW,CAAA,CACzB,IAAA,CAAK,CAAC,IAAA,KAAS;AACd,MAAA,IAAI,SAAA,EAAW;AAEf,MAAA,MAAM,UAAU,CAAC,GAAG,IAAA,CAAK,IAAI,EAAE,OAAA,EAAQ;AACvC,MAAA,WAAA,CAAY,OAAO,CAAA;AACnB,MAAA,UAAA,CAAW,IAAA,CAAK,IAAA,CAAK,MAAA,KAAW,SAAS,CAAA;AACzC,MAAA,iBAAA,CAAkB,OAAA,GAAU,OAAA,CAAQ,CAAC,CAAA,EAAG,QAAA,IAAY,IAAA;AACpD,MAAA,UAAA,CAAW,KAAK,CAAA;AAAA,IAClB,CAAC,CAAA,CACA,KAAA,CAAM,CAAC,GAAA,KAAiB;AACvB,MAAA,IAAI,SAAA,EAAW;AACf,MAAA,QAAA,CAAS,GAAA,YAAe,QAAQ,GAAA,GAAM,IAAI,MAAM,MAAA,CAAO,GAAG,CAAC,CAAC,CAAA;AAC5D,MAAA,UAAA,CAAW,KAAK,CAAA;AAAA,IAClB,CAAC,CAAA;AAGH,IAAA,MAAM,IAAA,GAAO,IAAA,CAAK,QAAA,CAAS,YAAA,CAAa,cAAc,CAAA;AAEtD,IAAA,MAAM,MAAA,GAAS,IAAA,CAAK,SAAA,CAAU,CAAC,GAAA,KAAQ;AAMrC,MAAA,WAAA,CAAY,CAAC,IAAA,KAAS;AACpB,QAAA,MAAM,IAAA,GAAO,UAAA,CAAW,IAAA,EAAM,GAAG,CAAA;AAMjC,QAAA,IAAI,GAAA,CAAI,cAAA,IAAkB,GAAA,CAAI,cAAA,KAAmB,IAAI,EAAA,EAAI;AACvD,UAAA,OAAO,IAAA,CAAK,GAAA;AAAA,YAAI,CAAC,CAAA,KACf,CAAA,CAAE,EAAA,KAAO,IAAI,cAAA,GAAiB,EAAE,GAAG,CAAA,EAAG,WAAA,EAAA,CAAc,CAAA,CAAE,WAAA,IAAe,CAAA,IAAK,GAAE,GAAI;AAAA,WAClF;AAAA,QACF;AACA,QAAA,OAAO,IAAA;AAAA,MACT,CAAC,CAAA;AAAA,IACH,CAAC,CAAA;AAED,IAAA,MAAM,UAAA,GAAa,IAAA,CAAK,gBAAA,CAAiB,CAAC,GAAA,KAAQ;AAChD,MAAA,WAAA,CAAY,CAAC,IAAA,KAAS,IAAA,CAAK,GAAA,CAAI,CAAC,CAAA,KAAO,CAAA,CAAE,EAAA,KAAO,GAAA,CAAI,EAAA,GAAK,GAAA,GAAM,CAAE,CAAC,CAAA;AAAA,IACpE,CAAC,CAAA;AAED,IAAA,MAAM,UAAA,GAAa,IAAA,CAAK,gBAAA,CAAiB,CAAC,GAAA,KAAQ;AAChD,MAAA,WAAA,CAAY,CAAC,IAAA,KAAS;AAIpB,QAAA,MAAM,MAAA,GAAS,KAAK,IAAA,CAAK,CAAC,MAAM,CAAA,CAAE,EAAA,KAAO,IAAI,EAAE,CAAA;AAC/C,QAAA,MAAM,UAAU,IAAA,CAAK,GAAA;AAAA,UAAI,CAAC,CAAA,KACxB,CAAA,CAAE,EAAA,KAAO,IAAI,EAAA,GAAK,EAAE,GAAG,CAAA,EAAG,UAAA,EAAY,GAAA,CAAI,UAAA,EAAY,IAAA,EAAM,MAAK,GAAI;AAAA,SACvE;AACA,QAAA,IAAI,QAAQ,cAAA,EAAgB;AAC1B,UAAA,OAAO,OAAA,CAAQ,GAAA;AAAA,YAAI,CAAC,CAAA,KAClB,CAAA,CAAE,OAAO,MAAA,CAAO,cAAA,GACZ,EAAE,GAAG,CAAA,EAAG,WAAA,EAAa,IAAA,CAAK,IAAI,CAAA,EAAA,CAAI,CAAA,CAAE,eAAe,CAAA,IAAK,CAAC,GAAE,GAC3D;AAAA,WACN;AAAA,QACF;AACA,QAAA,OAAO,OAAA;AAAA,MACT,CAAC,CAAA;AAAA,IACH,CAAC,CAAA;AAED,IAAA,OAAO,MAAM;AACX,MAAA,SAAA,GAAY,IAAA;AACZ,MAAA,MAAA,EAAO;AACP,MAAA,UAAA,EAAW;AACX,MAAA,UAAA,EAAW;AAAA,IAIb,CAAA;AAAA,EACF,CAAA,EAAG,CAAC,IAAA,EAAM,cAAc,CAAC,CAAA;AAEzB,EAAA,MAAM,QAAA,GAAWE,YAAY,YAAY;AACvC,IAAA,IAAI,CAAC,WAAW,OAAA,EAAS;AACzB,IAAA,MAAM,SAAS,iBAAA,CAAkB,OAAA;AACjC,IAAA,IAAI,CAAC,MAAA,EAAQ;AAEb,IAAA,MAAM,IAAA,GAA2C,EAAE,KAAA,EAAO,SAAA,EAAU;AACpE,IAAA,IAAI,MAAA,KAAW,IAAA,EAAM,IAAA,CAAK,MAAA,GAAS,MAAA;AAEnC,IAAA,MAAM,IAAA,GAAO,MAAM,IAAA,CAAK,aAAA,CAAc,IAAI,cAAc,CAAA,CAAE,QAAA,CAAS,IAAA,CAAK,IAAI,CAAA;AAC5E,IAAA,IAAI,IAAA,CAAK,IAAA,CAAK,MAAA,KAAW,CAAA,EAAG;AAC1B,MAAA,UAAA,CAAW,KAAK,CAAA;AAChB,MAAA;AAAA,IACF;AACA,IAAA,MAAM,QAAQ,CAAC,GAAG,IAAA,CAAK,IAAI,EAAE,OAAA,EAAQ;AACrC,IAAA,WAAA,CAAY,CAAC,IAAA,KAAS,CAAC,GAAG,KAAA,EAAO,GAAG,IAAI,CAAC,CAAA;AACzC,IAAA,UAAA,CAAW,IAAA,CAAK,IAAA,CAAK,MAAA,KAAW,SAAS,CAAA;AACzC,IAAA,iBAAA,CAAkB,OAAA,GAAU,KAAA,CAAM,CAAC,CAAA,EAAG,YAAY,iBAAA,CAAkB,OAAA;AAAA,EACtE,GAAG,CAAC,IAAA,EAAM,cAAA,EAAgB,OAAA,EAAS,OAAO,CAAC,CAAA;AAE3C,EAAA,MAAM,IAAA,GAAOA,WAAAA;AAAA,IACX,OAAO,KAAA,KAAgC;AAIrC,MAAA,MAAM,EAAA,GAAK,KAAA,CAAM,EAAA,IAAM,MAAA,CAAO,UAAA,EAAW;AACzC,MAAA,MAAM,OAAA,GAAmB;AAAA,QACvB,EAAA;AAAA,QACA,SAAA,EAAW,EAAA;AAAA,QACX,eAAA,EAAiB,cAAA;AAAA;AAAA;AAAA;AAAA;AAAA,QAKjB,WAAW,OAAA,CAAQ,OAAA;AAAA,QACnB,IAAA,EAAM,MAAM,IAAA,IAAQ,MAAA;AAAA,QACpB,IAAA,EAAM,MAAM,IAAA,IAAQ,IAAA;AAAA,QACpB,WAAA,EAAa,MAAM,WAAA,IAAe,IAAA;AAAA,QAClC,cAAA,EAAgB,IAAA;AAAA,QAChB,QAAA,EAAU,KAAA,CAAM,QAAA,IAAY,EAAC;AAAA,QAC7B,WAAW,EAAC;AAAA,QACZ,SAAA,EAAW,IAAA;AAAA,QACX,UAAA,EAAY,IAAA;AAAA;AAAA;AAAA,QAGZ,UAAU,MAAA,CAAO,gBAAA;AAAA,QACjB,WAAA,EAAA,iBAAa,IAAI,IAAA,EAAK,EAAE,WAAA,EAAY;AAAA,QACpC,UAAA,EAAA,iBAAY,IAAI,IAAA,EAAK,EAAE,WAAA;AAAY,OACrC;AAEA,MAAA,WAAA,CAAY,CAAC,IAAA,KAAS,CAAC,GAAG,IAAA,EAAM,OAAO,CAAC,CAAA;AAExC,MAAA,IAAI;AACF,QAAA,MAAM,IAAA,GAAO,MAAM,IAAA,CAAK,aAAA,CAAc,GAAA,CAAI,cAAc,CAAA,CAAE,QAAA,CAAS,IAAA,CAAK,EAAE,GAAG,KAAA,EAAO,IAAI,CAAA;AAGxF,QAAA,WAAA,CAAY,CAAC,IAAA,KAAS,UAAA,CAAW,IAAA,EAAM,IAAI,CAAC,CAAA;AAC5C,QAAA,OAAO,IAAA;AAAA,MACT,SAAS,GAAA,EAAK;AACZ,QAAA,WAAA,CAAY,CAAC,SAAS,IAAA,CAAK,MAAA,CAAO,CAAC,CAAA,KAAM,CAAA,CAAE,EAAA,KAAO,EAAE,CAAC,CAAA;AACrD,QAAA,MAAM,GAAA;AAAA,MACR;AAAA,IACF,CAAA;AAAA,IACA,CAAC,MAAM,cAAc;AAAA,GACvB;AAEA,EAAA,MAAM,IAAA,GAAOA,WAAAA;AAAA,IACX,OAAO,WAAiB,IAAA,KAAmC;AAKzD,MAAA,IAAI,QAAA;AACJ,MAAA,WAAA;AAAA,QAAY,CAAC,IAAA,KACX,IAAA,CAAK,GAAA,CAAI,CAAC,CAAA,KAAM;AACd,UAAA,IAAI,CAAA,CAAE,EAAA,KAAO,SAAA,EAAW,OAAO,CAAA;AAC/B,UAAA,QAAA,GAAW,CAAA;AACX,UAAA,OAAO,EAAE,GAAG,CAAA,EAAG,IAAA,EAAM,4BAAW,IAAI,IAAA,EAAK,EAAE,WAAA,EAAY,EAAE;AAAA,QAC3D,CAAC;AAAA,OACH;AAEA,MAAA,IAAI;AACF,QAAA,MAAM,OAAA,GAAU,MAAM,IAAA,CAAK,QAAA,CAAS,GAAA,CAAI,SAAS,CAAA,CAAE,MAAA,CAAO,EAAE,IAAA,EAAM,CAAA;AAElE,QAAA,WAAA,CAAY,CAAC,IAAA,KAAS,IAAA,CAAK,GAAA,CAAI,CAAC,CAAA,KAAO,CAAA,CAAE,EAAA,KAAO,SAAA,GAAY,OAAA,GAAU,CAAE,CAAC,CAAA;AACzE,QAAA,OAAO,OAAA;AAAA,MACT,SAAS,GAAA,EAAK;AACZ,QAAA,IAAI,QAAA,EAAU;AACZ,UAAA,MAAM,OAAA,GAAU,QAAA;AAChB,UAAA,WAAA,CAAY,CAAC,IAAA,KAAS,IAAA,CAAK,GAAA,CAAI,CAAC,CAAA,KAAO,CAAA,CAAE,EAAA,KAAO,SAAA,GAAY,OAAA,GAAU,CAAE,CAAC,CAAA;AAAA,QAC3E;AACA,QAAA,MAAM,GAAA;AAAA,MACR;AAAA,IACF,CAAA;AAAA,IACA,CAAC,IAAI;AAAA,GACP;AAEA,EAAA,MAAM,aAAA,GAAgBA,WAAAA;AAAA,IACpB,OAAO,SAAA,KAAmC;AAIxC,MAAA,IAAI,QAAA;AACJ,MAAA,WAAA;AAAA,QAAY,CAAC,IAAA,KACX,IAAA,CAAK,GAAA,CAAI,CAAC,CAAA,KAAM;AACd,UAAA,IAAI,CAAA,CAAE,EAAA,KAAO,SAAA,EAAW,OAAO,CAAA;AAC/B,UAAA,QAAA,GAAW,CAAA;AACX,UAAA,OAAO,EAAE,GAAG,CAAA,EAAG,IAAA,EAAM,IAAA,EAAM,6BAAY,IAAI,IAAA,EAAK,EAAE,WAAA,EAAY,EAAE;AAAA,QAClE,CAAC;AAAA,OACH;AAEA,MAAA,IAAI;AACF,QAAA,MAAM,IAAA,CAAK,QAAA,CAAS,GAAA,CAAI,SAAS,EAAE,MAAA,EAAO;AAAA,MAC5C,SAAS,GAAA,EAAK;AACZ,QAAA,IAAI,QAAA,EAAU;AACZ,UAAA,MAAM,OAAA,GAAU,QAAA;AAChB,UAAA,WAAA,CAAY,CAAC,IAAA,KAAS,IAAA,CAAK,GAAA,CAAI,CAAC,CAAA,KAAO,CAAA,CAAE,EAAA,KAAO,SAAA,GAAY,OAAA,GAAU,CAAE,CAAC,CAAA;AAAA,QAC3E;AACA,QAAA,MAAM,GAAA;AAAA,MACR;AAAA,IACF,CAAA;AAAA,IACA,CAAC,IAAI;AAAA,GACP;AAEA,EAAA,MAAM,YAAA,GAAeA,WAAAA;AAAA,IACnB,OAAO,SAAA,KAAmC;AAIxC,MAAA,MAAM,KAAK,aAAA,CAAc,GAAA,CAAI,cAAc,CAAA,CAAE,QAAA,CAAS,SAAS,SAAS,CAAA;AAAA,IAC1E,CAAA;AAAA,IACA,CAAC,MAAM,cAAc;AAAA,GACvB;AAEA,EAAA,OAAO;AAAA,IACL,QAAA;AAAA,IACA,OAAA;AAAA,IACA,KAAA;AAAA,IACA,OAAA;AAAA,IACA,QAAA;AAAA,IACA,IAAA;AAAA,IACA,IAAA;AAAA,IACA,MAAA,EAAQ,aAAA;AAAA,IACR;AAAA,GACF;AACF;AAEA,SAAS,UAAA,CAAW,MAAiB,GAAA,EAAyB;AAC5D,EAAA,MAAM,GAAA,GAAM,KAAK,SAAA,CAAU,CAAC,MAAM,CAAA,CAAE,EAAA,KAAO,IAAI,EAAE,CAAA;AACjD,EAAA,IAAI,QAAQ,EAAA,EAAI,OAAO,CAAC,GAAG,MAAM,GAAG,CAAA;AACpC,EAAA,MAAM,IAAA,GAAO,KAAK,KAAA,EAAM;AACxB,EAAA,IAAA,CAAK,GAAG,CAAA,GAAI,GAAA;AACZ,EAAA,OAAO,IAAA;AACT;AChQO,SAAS,YAAA,CAAa,WAAiB,IAAA,EAA8C;AAC1F,EAAA,MAAM,OAAO,SAAA,EAAU;AACvB,EAAA,MAAM,CAAC,WAAW,YAAY,CAAA,GAAID,SAAsB,IAAA,CAAK,gBAAA,IAAoB,EAAE,CAAA;AAKnF,EAAA,MAAM,gBAAA,GAAmBG,MAAAA,CAAoB,IAAA,CAAK,aAAA,IAAiB,IAAI,CAAA;AACvE,EAAA,gBAAA,CAAiB,OAAA,GAAU,KAAK,aAAA,IAAiB,IAAA;AAKjD,EAAA,MAAM,YAAA,GAAeA,OAAoB,SAAS,CAAA;AAClD,EAAA,YAAA,CAAa,OAAA,GAAU,SAAA;AAEvB,EAAAJ,UAAU,MAAM;AACd,IAAA,MAAM,IAAA,GAAO,IAAA,CAAK,QAAA,CAAS,YAAA,CAAa,KAAK,cAAc,CAAA;AAE3D,IAAA,MAAM,QAAA,GAAW,IAAA,CAAK,eAAA,CAAgB,CAAC,GAAA,KAAQ;AAC7C,MAAA,IAAI,GAAA,CAAI,eAAe,SAAA,EAAW;AAClC,MAAA,YAAA,CAAa,CAAC,SAAS,OAAA,CAAQ,IAAA,EAAM,IAAI,KAAA,EAAO,GAAA,CAAI,OAAO,CAAC,CAAA;AAAA,IAC9D,CAAC,CAAA;AAED,IAAA,MAAM,UAAA,GAAa,IAAA,CAAK,iBAAA,CAAkB,CAAC,GAAA,KAAQ;AACjD,MAAA,IAAI,GAAA,CAAI,eAAe,SAAA,EAAW;AAClC,MAAA,YAAA,CAAa,CAAC,SAAS,UAAA,CAAW,IAAA,EAAM,IAAI,KAAA,EAAO,GAAA,CAAI,OAAO,CAAC,CAAA;AAAA,IACjE,CAAC,CAAA;AAED,IAAA,OAAO,MAAM;AACX,MAAA,QAAA,EAAS;AACT,MAAA,UAAA,EAAW;AAAA,IACb,CAAA;AAAA,EACF,GAAG,CAAC,IAAA,EAAM,IAAA,CAAK,cAAA,EAAgB,SAAS,CAAC,CAAA;AAEzC,EAAA,MAAM,WAAA,GAAcE,WAAAA;AAAA,IAClB,OAAO,KAAA,KAAkB;AACvB,MAAA,MAAM,MAAM,gBAAA,CAAiB,OAAA;AAE7B,MAAA,IAAI,GAAA,eAAkB,CAAC,IAAA,KAAS,QAAQ,IAAA,EAAM,KAAA,EAAO,GAAG,CAAC,CAAA;AACzD,MAAA,IAAI;AACF,QAAA,MAAM,KAAK,QAAA,CAAS,GAAA,CAAI,SAAS,CAAA,CAAE,YAAY,KAAK,CAAA;AAAA,MACtD,SAAS,GAAA,EAAK;AACZ,QAAA,IAAI,GAAA,eAAkB,CAAC,IAAA,KAAS,WAAW,IAAA,EAAM,KAAA,EAAO,GAAG,CAAC,CAAA;AAC5D,QAAA,MAAM,GAAA;AAAA,MACR;AAAA,IACF,CAAA;AAAA,IACA,CAAC,MAAM,SAAS;AAAA,GAClB;AAEA,EAAA,MAAM,cAAA,GAAiBA,WAAAA;AAAA,IACrB,OAAO,KAAA,KAAkB;AACvB,MAAA,MAAM,MAAM,gBAAA,CAAiB,OAAA;AAC7B,MAAA,MAAM,WAAW,YAAA,CAAa,OAAA;AAC9B,MAAA,IAAI,GAAA,eAAkB,CAAC,IAAA,KAAS,WAAW,IAAA,EAAM,KAAA,EAAO,GAAG,CAAC,CAAA;AAC5D,MAAA,IAAI;AACF,QAAA,MAAM,KAAK,QAAA,CAAS,GAAA,CAAI,SAAS,CAAA,CAAE,eAAe,KAAK,CAAA;AAAA,MACzD,SAAS,GAAA,EAAK;AACZ,QAAA,IAAI,GAAA,eAAkB,QAAQ,CAAA;AAC9B,QAAA,MAAM,GAAA;AAAA,MACR;AAAA,IACF,CAAA;AAAA,IACA,CAAC,MAAM,SAAS;AAAA,GAClB;AAEA,EAAA,OAAO,EAAE,SAAA,EAAW,WAAA,EAAa,cAAA,EAAe;AAClD;AAEA,SAAS,OAAA,CAAQ,IAAA,EAAmB,KAAA,EAAe,MAAA,EAA2B;AAC5E,EAAA,MAAM,QAAA,GAAW,IAAA,CAAK,KAAK,CAAA,IAAK,EAAC;AACjC,EAAA,IAAI,QAAA,CAAS,QAAA,CAAS,MAAM,CAAA,EAAG,OAAO,IAAA;AACtC,EAAA,OAAO,EAAE,GAAG,IAAA,EAAM,CAAC,KAAK,GAAG,CAAC,GAAG,QAAA,EAAU,MAAM,CAAA,EAAE;AACnD;AAEA,SAAS,UAAA,CAAW,IAAA,EAAmB,KAAA,EAAe,MAAA,EAA2B;AAC/E,EAAA,MAAM,QAAA,GAAW,KAAK,KAAK,CAAA;AAC3B,EAAA,IAAI,CAAC,QAAA,IAAY,CAAC,SAAS,QAAA,CAAS,MAAM,GAAG,OAAO,IAAA;AACpD,EAAA,MAAM,OAAO,QAAA,CAAS,MAAA,CAAO,CAAC,EAAA,KAAO,OAAO,MAAM,CAAA;AAClD,EAAA,IAAI,IAAA,CAAK,WAAW,CAAA,EAAG;AACrB,IAAA,MAAM,EAAE,CAAC,KAAK,GAAG,CAAA,EAAG,GAAG,MAAK,GAAI,IAAA;AAChC,IAAA,OAAO,IAAA;AAAA,EACT;AACA,EAAA,OAAO,EAAE,GAAG,IAAA,EAAM,CAAC,KAAK,GAAG,IAAA,EAAK;AAClC;AC1GA,IAAMG,UAAAA,GAAY,EAAA;AAaX,SAAS,SAAA,CAAU,gBAAsB,aAAA,EAAqC;AACnF,EAAA,MAAM,OAAO,SAAA,EAAU;AACvB,EAAA,MAAM,CAAC,OAAA,EAAS,UAAU,CAAA,GAAIJ,QAAAA,CAAoB,EAAE,CAAA;AACpD,EAAA,MAAM,CAAC,OAAA,EAAS,UAAU,CAAA,GAAIA,SAAS,IAAI,CAAA;AAC3C,EAAA,MAAM,CAAC,KAAA,EAAO,QAAQ,CAAA,GAAIA,SAAuB,IAAI,CAAA;AACrD,EAAA,MAAM,CAAC,OAAA,EAAS,UAAU,CAAA,GAAIA,SAAS,IAAI,CAAA;AAG3C,EAAA,MAAM,iBAAA,GAAoBG,OAAsB,IAAI,CAAA;AAEpD,EAAAJ,UAAU,MAAM;AACd,IAAA,IAAI,SAAA,GAAY,KAAA;AAChB,IAAA,UAAA,CAAW,IAAI,CAAA;AACf,IAAA,UAAA,CAAW,EAAE,CAAA;AACb,IAAA,QAAA,CAAS,IAAI,CAAA;AACb,IAAA,UAAA,CAAW,IAAI,CAAA;AACf,IAAA,iBAAA,CAAkB,OAAA,GAAU,IAAA;AAE5B,IAAA,IAAA,CAAK,QAAA,CACF,GAAA,CAAI,aAAa,CAAA,CACjB,OAAA,CAAQ,EAAE,KAAA,EAAOK,UAAAA,EAAW,CAAA,CAC5B,IAAA,CAAK,CAAC,IAAA,KAAS;AACd,MAAA,IAAI,SAAA,EAAW;AACf,MAAA,UAAA,CAAW,KAAK,IAAI,CAAA;AACpB,MAAA,UAAA,CAAW,IAAA,CAAK,IAAA,CAAK,MAAA,KAAWA,UAAS,CAAA;AACzC,MAAA,iBAAA,CAAkB,OAAA,GAAU,KAAK,IAAA,CAAK,IAAA,CAAK,KAAK,MAAA,GAAS,CAAC,GAAG,QAAA,IAAY,IAAA;AACzE,MAAA,UAAA,CAAW,KAAK,CAAA;AAAA,IAClB,CAAC,CAAA,CACA,KAAA,CAAM,CAAC,GAAA,KAAiB;AACvB,MAAA,IAAI,SAAA,EAAW;AACf,MAAA,QAAA,CAAS,GAAA,YAAe,QAAQ,GAAA,GAAM,IAAI,MAAM,MAAA,CAAO,GAAG,CAAC,CAAC,CAAA;AAC5D,MAAA,UAAA,CAAW,KAAK,CAAA;AAAA,IAClB,CAAC,CAAA;AAGH,IAAA,MAAM,IAAA,GAAO,IAAA,CAAK,QAAA,CAAS,YAAA,CAAa,cAAc,CAAA;AACtD,IAAA,MAAM,MAAA,GAAS,IAAA,CAAK,SAAA,CAAU,CAAC,GAAA,KAAQ;AACrC,MAAA,IAAI,GAAA,CAAI,mBAAmB,aAAA,EAAe;AAC1C,MAAA,UAAA,CAAW,CAAC,IAAA,KAASC,WAAAA,CAAW,IAAA,EAAM,GAAG,CAAC,CAAA;AAAA,IAC5C,CAAC,CAAA;AACD,IAAA,MAAM,UAAA,GAAa,IAAA,CAAK,gBAAA,CAAiB,CAAC,GAAA,KAAQ;AAChD,MAAA,IAAI,GAAA,CAAI,mBAAmB,aAAA,EAAe;AAC1C,MAAA,UAAA,CAAW,CAAC,IAAA,KAAS,IAAA,CAAK,GAAA,CAAI,CAAC,CAAA,KAAO,CAAA,CAAE,EAAA,KAAO,GAAA,CAAI,EAAA,GAAK,GAAA,GAAM,CAAE,CAAC,CAAA;AAAA,IACnE,CAAC,CAAA;AACD,IAAA,MAAM,UAAA,GAAa,IAAA,CAAK,gBAAA,CAAiB,CAAC,GAAA,KAAQ;AAChD,MAAA,UAAA;AAAA,QAAW,CAAC,IAAA,KACV,IAAA,CAAK,IAAI,CAAC,CAAA,KAAO,EAAE,EAAA,KAAO,GAAA,CAAI,KAAK,EAAE,GAAG,GAAG,UAAA,EAAY,GAAA,CAAI,YAAY,IAAA,EAAM,IAAA,KAAS,CAAE;AAAA,OAC1F;AAAA,IACF,CAAC,CAAA;AAED,IAAA,OAAO,MAAM;AACX,MAAA,SAAA,GAAY,IAAA;AACZ,MAAA,MAAA,EAAO;AACP,MAAA,UAAA,EAAW;AACX,MAAA,UAAA,EAAW;AAAA,IACb,CAAA;AAAA,EACF,CAAA,EAAG,CAAC,IAAA,EAAM,cAAA,EAAgB,aAAa,CAAC,CAAA;AAExC,EAAA,MAAM,QAAA,GAAWJ,YAAY,YAAY;AACvC,IAAA,IAAI,CAAC,WAAW,OAAA,EAAS;AACzB,IAAA,MAAM,QAAQ,iBAAA,CAAkB,OAAA;AAChC,IAAA,IAAI,UAAU,IAAA,EAAM;AACpB,IAAA,MAAM,IAAA,GAAO,MAAM,IAAA,CAAK,QAAA,CAAS,GAAA,CAAI,aAAa,CAAA,CAAE,OAAA,CAAQ,EAAE,KAAA,EAAOG,UAAAA,EAAW,KAAA,EAAO,CAAA;AACvF,IAAA,IAAI,IAAA,CAAK,IAAA,CAAK,MAAA,KAAW,CAAA,EAAG;AAC1B,MAAA,UAAA,CAAW,KAAK,CAAA;AAChB,MAAA;AAAA,IACF;AACA,IAAA,UAAA,CAAW,CAAC,SAAS,CAAC,GAAG,MAAM,GAAG,IAAA,CAAK,IAAI,CAAC,CAAA;AAC5C,IAAA,UAAA,CAAW,IAAA,CAAK,IAAA,CAAK,MAAA,KAAWA,UAAS,CAAA;AACzC,IAAA,iBAAA,CAAkB,OAAA,GAAU,KAAK,IAAA,CAAK,IAAA,CAAK,KAAK,MAAA,GAAS,CAAC,GAAG,QAAA,IAAY,KAAA;AAAA,EAC3E,GAAG,CAAC,IAAA,EAAM,aAAA,EAAe,OAAA,EAAS,OAAO,CAAC,CAAA;AAE1C,EAAA,MAAM,SAAA,GAAYH,WAAAA;AAAA,IAChB,OAAO,KAAA,KAAqD;AAC1D,MAAA,MAAM,EAAA,GAAK,KAAA,CAAM,EAAA,IAAM,MAAA,CAAO,UAAA,EAAW;AACzC,MAAA,MAAM,OAAA,GAAmB;AAAA,QACvB,EAAA;AAAA,QACA,SAAA,EAAW,EAAA;AAAA,QACX,eAAA,EAAiB,cAAA;AAAA,QACjB,SAAA,EAAW,IAAA;AAAA,QACX,IAAA,EAAM,MAAM,IAAA,IAAQ,MAAA;AAAA,QACpB,IAAA,EAAM,MAAM,IAAA,IAAQ,IAAA;AAAA,QACpB,WAAA,EAAa,aAAA;AAAA,QACb,cAAA,EAAgB,aAAA;AAAA,QAChB,QAAA,EAAU,KAAA,CAAM,QAAA,IAAY,EAAC;AAAA,QAC7B,WAAW,EAAC;AAAA,QACZ,SAAA,EAAW,IAAA;AAAA,QACX,UAAA,EAAY,IAAA;AAAA,QACZ,UAAU,MAAA,CAAO,gBAAA;AAAA,QACjB,WAAA,EAAA,iBAAa,IAAI,IAAA,EAAK,EAAE,WAAA,EAAY;AAAA,QACpC,UAAA,EAAA,iBAAY,IAAI,IAAA,EAAK,EAAE,WAAA;AAAY,OACrC;AACA,MAAA,UAAA,CAAW,CAAC,IAAA,KAAS,CAAC,GAAG,IAAA,EAAM,OAAO,CAAC,CAAA;AAEvC,MAAA,IAAI;AACF,QAAA,MAAM,IAAA,GAAO,MAAM,IAAA,CAAK,aAAA,CAAc,IAAI,cAAc,CAAA,CAAE,SAAS,IAAA,CAAK;AAAA,UACtE,GAAG,KAAA;AAAA,UACH,EAAA;AAAA,UACA,WAAA,EAAa;AAAA,SACd,CAAA;AACD,QAAA,UAAA,CAAW,CAAC,IAAA,KAASI,WAAAA,CAAW,IAAA,EAAM,IAAI,CAAC,CAAA;AAC3C,QAAA,OAAO,IAAA;AAAA,MACT,SAAS,GAAA,EAAK;AACZ,QAAA,UAAA,CAAW,CAAC,SAAS,IAAA,CAAK,MAAA,CAAO,CAAC,CAAA,KAAM,CAAA,CAAE,EAAA,KAAO,EAAE,CAAC,CAAA;AACpD,QAAA,MAAM,GAAA;AAAA,MACR;AAAA,IACF,CAAA;AAAA,IACA,CAAC,IAAA,EAAM,cAAA,EAAgB,aAAa;AAAA,GACtC;AAEA,EAAA,MAAM,IAAA,GAAOJ,WAAAA;AAAA,IACX,OAAO,WAAiB,IAAA,KAAmC;AACzD,MAAA,IAAI,QAAA;AACJ,MAAA,UAAA;AAAA,QAAW,CAAC,IAAA,KACV,IAAA,CAAK,GAAA,CAAI,CAAC,CAAA,KAAM;AACd,UAAA,IAAI,CAAA,CAAE,EAAA,KAAO,SAAA,EAAW,OAAO,CAAA;AAC/B,UAAA,QAAA,GAAW,CAAA;AACX,UAAA,OAAO,EAAE,GAAG,CAAA,EAAG,IAAA,EAAM,4BAAW,IAAI,IAAA,EAAK,EAAE,WAAA,EAAY,EAAE;AAAA,QAC3D,CAAC;AAAA,OACH;AAEA,MAAA,IAAI;AACF,QAAA,MAAM,OAAA,GAAU,MAAM,IAAA,CAAK,QAAA,CAAS,GAAA,CAAI,SAAS,CAAA,CAAE,MAAA,CAAO,EAAE,IAAA,EAAM,CAAA;AAClE,QAAA,UAAA,CAAW,CAAC,IAAA,KAAS,IAAA,CAAK,GAAA,CAAI,CAAC,CAAA,KAAO,CAAA,CAAE,EAAA,KAAO,SAAA,GAAY,OAAA,GAAU,CAAE,CAAC,CAAA;AACxE,QAAA,OAAO,OAAA;AAAA,MACT,SAAS,GAAA,EAAK;AACZ,QAAA,IAAI,QAAA,EAAU;AACZ,UAAA,MAAM,OAAA,GAAU,QAAA;AAChB,UAAA,UAAA,CAAW,CAAC,IAAA,KAAS,IAAA,CAAK,GAAA,CAAI,CAAC,CAAA,KAAO,CAAA,CAAE,EAAA,KAAO,SAAA,GAAY,OAAA,GAAU,CAAE,CAAC,CAAA;AAAA,QAC1E;AACA,QAAA,MAAM,GAAA;AAAA,MACR;AAAA,IACF,CAAA;AAAA,IACA,CAAC,IAAI;AAAA,GACP;AAEA,EAAA,MAAM,WAAA,GAAcA,WAAAA;AAAA,IAClB,OAAO,SAAA,KAAmC;AACxC,MAAA,IAAI,QAAA;AACJ,MAAA,UAAA;AAAA,QAAW,CAAC,IAAA,KACV,IAAA,CAAK,GAAA,CAAI,CAAC,CAAA,KAAM;AACd,UAAA,IAAI,CAAA,CAAE,EAAA,KAAO,SAAA,EAAW,OAAO,CAAA;AAC/B,UAAA,QAAA,GAAW,CAAA;AACX,UAAA,OAAO,EAAE,GAAG,CAAA,EAAG,IAAA,EAAM,IAAA,EAAM,6BAAY,IAAI,IAAA,EAAK,EAAE,WAAA,EAAY,EAAE;AAAA,QAClE,CAAC;AAAA,OACH;AAEA,MAAA,IAAI;AACF,QAAA,MAAM,IAAA,CAAK,QAAA,CAAS,GAAA,CAAI,SAAS,EAAE,MAAA,EAAO;AAAA,MAC5C,SAAS,GAAA,EAAK;AACZ,QAAA,IAAI,QAAA,EAAU;AACZ,UAAA,MAAM,OAAA,GAAU,QAAA;AAChB,UAAA,UAAA,CAAW,CAAC,IAAA,KAAS,IAAA,CAAK,GAAA,CAAI,CAAC,CAAA,KAAO,CAAA,CAAE,EAAA,KAAO,SAAA,GAAY,OAAA,GAAU,CAAE,CAAC,CAAA;AAAA,QAC1E;AACA,QAAA,MAAM,GAAA;AAAA,MACR;AAAA,IACF,CAAA;AAAA,IACA,CAAC,IAAI;AAAA,GACP;AAEA,EAAA,OAAO;AAAA,IACL,OAAA;AAAA,IACA,OAAA;AAAA,IACA,KAAA;AAAA,IACA,OAAA;AAAA,IACA,QAAA;AAAA,IACA,SAAA;AAAA,IACA,IAAA;AAAA,IACA,MAAA,EAAQ;AAAA,GACV;AACF;AAEA,SAASI,WAAAA,CAAW,MAAiB,GAAA,EAAyB;AAC5D,EAAA,MAAM,GAAA,GAAM,KAAK,SAAA,CAAU,CAAC,MAAM,CAAA,CAAE,EAAA,KAAO,IAAI,EAAE,CAAA;AACjD,EAAA,IAAI,QAAQ,EAAA,EAAI,OAAO,CAAC,GAAG,MAAM,GAAG,CAAA;AACpC,EAAA,MAAM,IAAA,GAAO,KAAK,KAAA,EAAM;AACxB,EAAA,IAAA,CAAK,GAAG,CAAA,GAAI,GAAA;AACZ,EAAA,OAAO,IAAA;AACT;ACrMO,SAAS,UAAU,cAAA,EAAwC;AAChE,EAAA,MAAM,OAAO,SAAA,EAAU;AACvB,EAAA,MAAM,EAAE,EAAA,EAAG,GAAI,KAAA,EAAM;AACrB,EAAA,MAAM,CAAC,MAAA,EAAQ,SAAS,IAAIL,QAAAA,iBAAoB,IAAI,KAAK,CAAA;AACzD,EAAA,MAAM,WAAA,GAAcG,OAAO,CAAC,CAAA;AAM5B,EAAA,MAAM,OAAA,GAAUA,MAAAA,CAAoB,EAAA,EAAI,EAAA,IAAM,IAAI,CAAA;AAClD,EAAA,OAAA,CAAQ,OAAA,GAAU,IAAI,EAAA,IAAM,IAAA;AAE5B,EAAAJ,UAAU,MAAM;AACd,IAAA,SAAA,iBAAU,IAAI,KAAK,CAAA;AAEnB,IAAA,MAAM,IAAA,GAAO,IAAA,CAAK,QAAA,CAAS,YAAA,CAAa,cAAc,CAAA;AAEtD,IAAA,MAAM,QAAA,GAAW,IAAA,CAAK,aAAA,CAAc,CAAC,GAAA,KAAQ;AAE3C,MAAA,IAAI,OAAA,CAAQ,OAAA,IAAW,GAAA,CAAI,OAAA,KAAY,QAAQ,OAAA,EAAS;AACxD,MAAA,SAAA,CAAU,CAAC,IAAA,KAAS;AAClB,QAAA,IAAI,IAAA,CAAK,GAAA,CAAI,GAAA,CAAI,OAAO,GAAG,OAAO,IAAA;AAClC,QAAA,MAAM,IAAA,GAAO,IAAI,GAAA,CAAI,IAAI,CAAA;AACzB,QAAA,IAAA,CAAK,GAAA,CAAI,IAAI,OAAO,CAAA;AACpB,QAAA,OAAO,IAAA;AAAA,MACT,CAAC,CAAA;AAAA,IACH,CAAC,CAAA;AAED,IAAA,MAAM,OAAA,GAAU,IAAA,CAAK,YAAA,CAAa,CAAC,GAAA,KAAQ;AACzC,MAAA,IAAI,OAAA,CAAQ,OAAA,IAAW,GAAA,CAAI,OAAA,KAAY,QAAQ,OAAA,EAAS;AACxD,MAAA,SAAA,CAAU,CAAC,IAAA,KAAS;AAClB,QAAA,IAAI,CAAC,IAAA,CAAK,GAAA,CAAI,GAAA,CAAI,OAAO,GAAG,OAAO,IAAA;AACnC,QAAA,MAAM,IAAA,GAAO,IAAI,GAAA,CAAI,IAAI,CAAA;AACzB,QAAA,IAAA,CAAK,MAAA,CAAO,IAAI,OAAO,CAAA;AACvB,QAAA,OAAO,IAAA;AAAA,MACT,CAAC,CAAA;AAAA,IACH,CAAC,CAAA;AAED,IAAA,OAAO,MAAM;AACX,MAAA,QAAA,EAAS;AACT,MAAA,OAAA,EAAQ;AAAA,IACV,CAAA;AAAA,EACF,CAAA,EAAG,CAAC,IAAA,EAAM,cAAc,CAAC,CAAA;AAEzB,EAAA,MAAM,YAAA,GAAeE,YAAY,MAAM;AACrC,IAAA,MAAM,GAAA,GAAM,KAAK,GAAA,EAAI;AACrB,IAAA,IAAI,GAAA,GAAM,WAAA,CAAY,OAAA,GAAU,GAAA,EAAK;AACrC,IAAA,WAAA,CAAY,OAAA,GAAU,GAAA;AACtB,IAAA,IAAA,CAAK,QAAA,CAAS,YAAA,CAAa,cAAc,CAAA,CAAE,UAAA,EAAW;AAAA,EACxD,CAAA,EAAG,CAAC,IAAA,EAAM,cAAc,CAAC,CAAA;AAEzB,EAAA,OAAO,EAAE,QAAQ,YAAA,EAAa;AAChC;AChEO,SAAS,YAAY,cAAA,EAA0C;AACpE,EAAA,MAAM,OAAO,SAAA,EAAU;AACvB,EAAA,MAAM,CAAC,MAAA,EAAQ,SAAS,IAAID,QAAAA,iBAAoB,IAAI,KAAK,CAAA;AAEzD,EAAAD,UAAU,MAAM;AACd,IAAA,SAAA,iBAAU,IAAI,KAAK,CAAA;AAEnB,IAAA,MAAM,IAAA,GAAO,IAAA,CAAK,QAAA,CAAS,YAAA,CAAa,cAAc,CAAA;AAEtD,IAAA,MAAM,UAAA,GAAa,CAAC,KAAA,KAA4B;AAC9C,MAAA,SAAA,CAAU,IAAI,GAAA,CAAI,MAAA,CAAO,IAAA,CAAK,KAAK,CAAC,CAAC,CAAA;AAAA,IACvC,CAAA;AAEA,IAAA,MAAM,SAAA,GAAY,CAAC,IAAA,KAAkE;AACnF,MAAA,SAAA,CAAU,CAAC,IAAA,KAAS;AAClB,QAAA,MAAM,IAAA,GAAO,IAAI,GAAA,CAAI,IAAI,CAAA;AACzB,QAAA,IAAI,IAAA,CAAK,KAAA,EAAO,MAAA,CAAO,IAAA,CAAK,IAAA,CAAK,KAAK,CAAA,CAAE,OAAA,CAAQ,CAAC,EAAA,KAAO,IAAA,CAAK,GAAA,CAAI,EAAE,CAAC,CAAA;AACpE,QAAA,IAAI,IAAA,CAAK,MAAA,EAAQ,MAAA,CAAO,IAAA,CAAK,IAAA,CAAK,MAAM,CAAA,CAAE,OAAA,CAAQ,CAAC,EAAA,KAAO,IAAA,CAAK,MAAA,CAAO,EAAE,CAAC,CAAA;AACzE,QAAA,OAAO,IAAA;AAAA,MACT,CAAC,CAAA;AAAA,IACH,CAAA;AAEA,IAAA,MAAM,QAAA,GAAW,IAAA,CAAK,eAAA,CAAgB,UAAU,CAAA;AAChD,IAAA,MAAM,OAAA,GAAU,IAAA,CAAK,cAAA,CAAe,SAA0C,CAAA;AAE9E,IAAA,OAAO,MAAM;AACX,MAAA,QAAA,EAAS;AACT,MAAA,OAAA,EAAQ;AAAA,IACV,CAAA;AAAA,EACF,CAAA,EAAG,CAAC,IAAA,EAAM,cAAc,CAAC,CAAA;AAEzB,EAAA,OAAO,EAAE,MAAA,EAAO;AAClB;ACpCO,SAAS,iBAAA,GAAoC;AAClD,EAAA,MAAM,OAAO,SAAA,EAAU;AACvB,EAAA,MAAM,CAAC,QAAQ,SAAS,CAAA,GAAIC,SAAyB,IAAA,CAAK,QAAA,CAAS,WAAW,CAAA;AAE9E,EAAAD,UAAU,MAAM;AACd,IAAA,SAAA,CAAU,IAAA,CAAK,QAAA,CAAS,SAAA,EAAW,CAAA;AACnC,IAAA,OAAO,IAAA,CAAK,QAAA,CAAS,QAAA,CAAS,SAAS,CAAA;AAAA,EACzC,CAAA,EAAG,CAAC,IAAI,CAAC,CAAA;AAET,EAAA,OAAO,MAAA;AACT;ACkBO,SAAS,mBAAA,GAAgD;AAC9D,EAAA,MAAM,OAAO,SAAA,EAAU;AACvB,EAAA,MAAM,CAAC,UAAA,EAAY,aAAa,CAAA,GAAIC,SAA4B,IAAI,CAAA;AACpE,EAAA,MAAM,CAAC,SAAA,EAAW,YAAY,CAAA,GAAIA,SAAS,KAAK,CAAA;AAChD,EAAA,MAAM,CAAC,KAAA,EAAO,QAAQ,CAAA,GAAIA,SAAuB,IAAI,CAAA;AAErD,EAAA,MAAM,WAAA,GAAcG,OAA+B,IAAI,CAAA;AAEvD,EAAA,MAAM,MAAA,GAASF,WAAAA;AAAA,IACb,OAAO,KAAA,KAAsD;AAE3D,MAAA,WAAA,CAAY,SAAS,KAAA,EAAM;AAC3B,MAAA,MAAM,UAAA,GAAa,IAAI,eAAA,EAAgB;AACvC,MAAA,WAAA,CAAY,OAAA,GAAU,UAAA;AAEtB,MAAA,YAAA,CAAa,IAAI,CAAA;AACjB,MAAA,QAAA,CAAS,IAAI,CAAA;AACb,MAAA,IAAI;AACF,QAAA,MAAM,GAAA,GAAM,MAAM,IAAA,CAAK,WAAA,CAAY,MAAA,CAAO,OAAO,EAAE,MAAA,EAAQ,UAAA,CAAW,MAAA,EAAQ,CAAA;AAC9E,QAAA,IAAI,WAAA,CAAY,YAAY,UAAA,EAAY;AACtC,UAAA,aAAA,CAAc,GAAG,CAAA;AAAA,QACnB;AACA,QAAA,OAAO,GAAA;AAAA,MACT,SAAS,GAAA,EAAK;AACZ,QAAA,IAAK,GAAA,EAAsB,IAAA,KAAS,YAAA,EAAc,MAAM,GAAA;AACxD,QAAA,MAAM,CAAA,GAAI,eAAe,KAAA,GAAQ,GAAA,GAAM,IAAI,KAAA,CAAM,MAAA,CAAO,GAAG,CAAC,CAAA;AAC5D,QAAA,QAAA,CAAS,CAAC,CAAA;AACV,QAAA,MAAM,CAAA;AAAA,MACR,CAAA,SAAE;AACA,QAAA,IAAI,WAAA,CAAY,YAAY,UAAA,EAAY;AACtC,UAAA,YAAA,CAAa,KAAK,CAAA;AAClB,UAAA,WAAA,CAAY,OAAA,GAAU,IAAA;AAAA,QACxB;AAAA,MACF;AAAA,IACF,CAAA;AAAA,IACA,CAAC,IAAI;AAAA,GACP;AAEA,EAAA,MAAM,KAAA,GAAQA,YAAY,MAAM;AAC9B,IAAA,WAAA,CAAY,SAAS,KAAA,EAAM;AAC3B,IAAA,WAAA,CAAY,OAAA,GAAU,IAAA;AACtB,IAAA,aAAA,CAAc,IAAI,CAAA;AAClB,IAAA,QAAA,CAAS,IAAI,CAAA;AACb,IAAA,YAAA,CAAa,KAAK,CAAA;AAAA,EACpB,CAAA,EAAG,EAAE,CAAA;AAEL,EAAA,OAAO,EAAE,UAAA,EAAY,SAAA,EAAW,KAAA,EAAO,QAAQ,KAAA,EAAM;AACvD;AC3DO,SAAS,iBAAiB,YAAA,EAAkD;AACjF,EAAA,MAAM,OAAO,SAAA,EAAU;AACvB,EAAA,MAAM,CAAC,GAAA,EAAK,MAAM,CAAA,GAAID,SAAwB,IAAI,CAAA;AAClD,EAAA,MAAM,CAAC,OAAA,EAAS,UAAU,CAAA,GAAIA,QAAAA,CAAS,iBAAiB,IAAI,CAAA;AAC5D,EAAA,MAAM,CAAC,KAAA,EAAO,QAAQ,CAAA,GAAIA,SAAuB,IAAI,CAAA;AAErD,EAAAD,UAAU,MAAM;AACd,IAAA,IAAI,iBAAiB,IAAA,EAAM;AACzB,MAAA,MAAA,CAAO,IAAI,CAAA;AACX,MAAA,UAAA,CAAW,KAAK,CAAA;AAChB,MAAA,QAAA,CAAS,IAAI,CAAA;AACb,MAAA;AAAA,IACF;AACA,IAAA,IAAI,SAAA,GAAY,KAAA;AAChB,IAAA,MAAM,UAAA,GAAa,IAAI,eAAA,EAAgB;AACvC,IAAA,UAAA,CAAW,IAAI,CAAA;AACf,IAAA,QAAA,CAAS,IAAI,CAAA;AACb,IAAA,IAAA,CAAK,WAAA,CACF,GAAA,CAAI,YAAY,CAAA,CAChB,WAAA,CAAY,EAAE,MAAA,EAAQ,UAAA,CAAW,MAAA,EAAQ,CAAA,CACzC,IAAA,CAAK,CAAC,GAAA,KAAQ;AACb,MAAA,IAAI,SAAA,EAAW;AACf,MAAA,MAAA,CAAO,IAAI,GAAG,CAAA;AACd,MAAA,UAAA,CAAW,KAAK,CAAA;AAAA,IAClB,CAAC,CAAA,CACA,KAAA,CAAM,CAAC,GAAA,KAAiB;AACvB,MAAA,IAAI,SAAA,EAAW;AACf,MAAA,IAAK,GAAA,EAAsB,SAAS,YAAA,EAAc;AAClD,MAAA,QAAA,CAAS,GAAA,YAAe,QAAQ,GAAA,GAAM,IAAI,MAAM,MAAA,CAAO,GAAG,CAAC,CAAC,CAAA;AAC5D,MAAA,UAAA,CAAW,KAAK,CAAA;AAAA,IAClB,CAAC,CAAA;AACH,IAAA,OAAO,MAAM;AACX,MAAA,SAAA,GAAY,IAAA;AACZ,MAAA,UAAA,CAAW,KAAA,EAAM;AAAA,IACnB,CAAA;AAAA,EACF,CAAA,EAAG,CAAC,IAAA,EAAM,YAAY,CAAC,CAAA;AAEvB,EAAA,OAAO,EAAE,GAAA,EAAK,OAAA,EAAS,KAAA,EAAM;AAC/B","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 });\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>:conversation:created` once we\n // know who \"me\" is. Re-subscribes if `me.id` changes (rare — only on\n // sign-in/sign-out within the same provider, which is itself rare).\n useEffect(() => {\n if (!me) return;\n const userChan = chat.realtime.user(me.id);\n const off = userChan.onConversationCreated((conv) => {\n setConversations((prev) => prepend(prev, conv));\n });\n return off;\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","import type { AddMemberOptions, 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. The returned memberships\n * are appended to local state on success.\n */\n addMembers: (externalIds: string[], opts?: { role?: MemberRole }) => Promise<Membership[]>;\n /**\n * Remove a member by user_id. Optimistically removes from state;\n * rolls back on server error.\n */\n removeMember: (userId: Uuid) => 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 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 setMembers(data);\n } catch (err) {\n if ((err as DOMException)?.name === 'AbortError') return;\n // Surface to console with a recognisable prefix so callers can\n // grep for it in production logs / DevTools. Without this the\n // hook silently sets `error` state and the UI just shows a\n // generic placeholder.\n console.error('[poolse] useMembers fetch failed:', err);\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 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 setMembers((prev) =>\n prev.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 });\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 (userId: Uuid) => {\n const snapshot = membersRef.current;\n setMembers((prev) => prev.filter((m) => m.user_id !== userId));\n try {\n await chat.conversations.one(conversationId).removeMember(userId);\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 { 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\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\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\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 // Realtime listeners.\n const conv = chat.realtime.conversation(conversationId);\n\n const offNew = conv.onMessage((msg) => {\n // Simple by-id upsert. Covers three cases with one expression:\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) => {\n const next = upsertById(prev, msg);\n // If this is a thread reply, bump the root's reply_count so the\n // thread pill (\"💬 N replies\") updates live without a refetch.\n // Skip when the broadcast IS the root being upserted (msg.id ===\n // thread_root_id is impossible by construction — a root has no\n // thread_root_id — but cheap to guard).\n if (msg.thread_root_id && msg.thread_root_id !== msg.id) {\n return next.map((m) =>\n m.id === msg.thread_root_id ? { ...m, reply_count: (m.reply_count ?? 0) + 1 } : m,\n );\n }\n return next;\n });\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 ?? crypto.randomUUID();\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 type: attrs.type ?? 'text',\n body: attrs.body ?? null,\n reply_to_id: attrs.reply_to_id ?? null,\n thread_root_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 return {\n messages,\n loading,\n error,\n hasMore,\n loadMore,\n send,\n edit,\n delete: deleteMessage,\n markReadUpTo,\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 { 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\nconst PAGE_SIZE = 50;\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 ?? crypto.randomUUID();\n const tempMsg: Message = {\n id,\n tenant_id: '',\n conversation_id: conversationId,\n sender_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 type { Uuid } from '@poolse/sdk';\nimport { useCallback, useEffect, useRef, useState } from 'react';\nimport { usePoolse } from './provider.js';\nimport { useMe } from './use-me.js';\n\ninterface UseTypingState {\n /** Set of user_ids currently typing. */\n typing: Set<Uuid>;\n /**\n * Send a typing ping to the server. Debounced inside the SDK — the\n * server squashes `typing:start` to one push per (user, conversation,\n * window). Call as often as you want from input handlers.\n */\n signalTyping: () => void;\n}\n\n/**\n * Tracks who's typing in `conversationId`. Subscribes to the\n * `typing:start` / `typing:stop` broadcasts; auto-cleans up entries\n * when stop fires.\n *\n * `signalTyping` debounces on the client side to once per 500 ms so a\n * fast-typing user doesn't flood the channel — poolse does its own\n * server-side debounce too, so both layers are safe.\n */\nexport function useTyping(conversationId: string): UseTypingState {\n const chat = usePoolse();\n const { me } = useMe();\n const [typing, setTyping] = useState<Set<Uuid>>(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 meIdRef = useRef<Uuid | null>(me?.id ?? null);\n meIdRef.current = me?.id ?? null;\n\n useEffect(() => {\n setTyping(new Set());\n\n const conv = chat.realtime.conversation(conversationId);\n\n const offStart = conv.onTypingStart((evt) => {\n // Don't render the current user's own typing — they know they're typing.\n if (meIdRef.current && evt.user_id === meIdRef.current) return;\n setTyping((prev) => {\n if (prev.has(evt.user_id)) return prev;\n const next = new Set(prev);\n next.add(evt.user_id);\n return next;\n });\n });\n\n const offStop = conv.onTypingStop((evt) => {\n if (meIdRef.current && evt.user_id === meIdRef.current) return;\n setTyping((prev) => {\n if (!prev.has(evt.user_id)) return prev;\n const next = new Set(prev);\n next.delete(evt.user_id);\n return next;\n });\n });\n\n return () => {\n offStart();\n offStop();\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, Uuid } from '@poolse/sdk';\nimport { useEffect, useState } from 'react';\nimport { usePoolse } from './provider.js';\n\ninterface UsePresenceState {\n /** Set of user_ids currently online in this conversation. */\n online: Set<Uuid>;\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<Uuid>>(new Set());\n\n useEffect(() => {\n setOnline(new Set());\n\n const conv = chat.realtime.conversation(conversationId);\n\n const applyState = (state: PresenceSnapshot) => {\n setOnline(new Set(Object.keys(state)));\n };\n\n const applyDiff = (diff: { joins?: PresenceSnapshot; leaves?: PresenceSnapshot }) => {\n setOnline((prev) => {\n const next = new Set(prev);\n if (diff.joins) Object.keys(diff.joins).forEach((id) => next.add(id));\n if (diff.leaves) Object.keys(diff.leaves).forEach((id) => next.delete(id));\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 { useCallback, useRef, useState } from 'react';\nimport { usePoolse } from './provider.js';\n\ninterface UseAttachmentUploadState {\n /** Last successfully uploaded attachment, or null. */\n attachment: Attachment | null;\n uploading: boolean;\n error: Error | null;\n /**\n * Run the upload pipeline (presigned-URL request + PUT). Updates\n * local state with the resolved attachment on success; sets `error`\n * and rethrows on failure so callers can surface a toast.\n */\n upload: (input: AttachmentUploadInput) => Promise<Attachment>;\n /** Reset state (clears `attachment`, `error`). */\n reset: () => void;\n}\n\n/**\n * Stateful wrapper around `chat.attachments.upload`. Provides\n * `uploading` + `error` flags for the common \"show a spinner while\n * the PUT is in flight\" UI, plus retention of the last attachment\n * so the caller can reference its id when sending a message.\n *\n * ```tsx\n * const { upload, uploading, attachment } = useAttachmentUpload();\n * const onPick = async (file: File) => {\n * const att = await upload({\n * body: file, contentType: file.type, byteSize: file.size, filename: file.name\n * });\n * await chat.conversations.one(convId).messages.send({\n * body: 'attached',\n * custom_data: { attachment_id: att.id },\n * });\n * };\n * ```\n */\nexport function useAttachmentUpload(): UseAttachmentUploadState {\n const chat = usePoolse();\n const [attachment, setAttachment] = useState<Attachment | null>(null);\n const [uploading, setUploading] = useState(false);\n const [error, setError] = useState<Error | null>(null);\n // Track an in-flight upload's AbortController so unmount cancels it.\n const inFlightRef = useRef<AbortController | null>(null);\n\n const upload = useCallback(\n async (input: AttachmentUploadInput): Promise<Attachment> => {\n // Cancel any prior in-flight upload — last-write-wins on intent.\n inFlightRef.current?.abort();\n const controller = new AbortController();\n inFlightRef.current = controller;\n\n setUploading(true);\n setError(null);\n try {\n const att = await chat.attachments.upload(input, { signal: controller.signal });\n if (inFlightRef.current === controller) {\n setAttachment(att);\n }\n return att;\n } catch (err) {\n if ((err as DOMException)?.name === 'AbortError') throw err;\n const e = err instanceof Error ? err : new Error(String(err));\n setError(e);\n throw e;\n } finally {\n if (inFlightRef.current === controller) {\n setUploading(false);\n inFlightRef.current = null;\n }\n }\n },\n [chat],\n );\n\n const reset = useCallback(() => {\n inFlightRef.current?.abort();\n inFlightRef.current = null;\n setAttachment(null);\n setError(null);\n setUploading(false);\n }, []);\n\n return { attachment, uploading, error, upload, reset };\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"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@poolse/react",
3
- "version": "0.2.0-alpha.3",
3
+ "version": "0.2.0-alpha.4",
4
4
  "description": "Headless React hooks for poolse — realtime chat infrastructure. Provider + useMessages / useTyping / usePresence / useReactions / useAttachmentUpload / etc. NO UI.",
5
5
  "license": "MIT",
6
6
  "keywords": [
@@ -43,7 +43,7 @@
43
43
  "CHANGELOG.md"
44
44
  ],
45
45
  "dependencies": {
46
- "@poolse/sdk": "0.2.0-alpha.3"
46
+ "@poolse/sdk": "0.2.0-alpha.4"
47
47
  },
48
48
  "peerDependencies": {
49
49
  "react": ">=18"