@marktiderman/genesis-chat 0.2.2 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +119 -6
- package/dist/{chunk-VEPZROQB.js → chunk-BTG4JWLF.js} +5 -4
- package/dist/chunk-BTG4JWLF.js.map +1 -0
- package/dist/{chunk-AZS3HNLM.js → chunk-IEFULAC2.js} +25 -3
- package/dist/chunk-IEFULAC2.js.map +1 -0
- package/dist/{chunk-JU2FAPBI.js → chunk-XQ2ULNHV.js} +2 -2
- package/dist/{chunk-JU2FAPBI.js.map → chunk-XQ2ULNHV.js.map} +1 -1
- package/dist/native.d.ts +158 -6
- package/dist/native.js +404 -181
- package/dist/native.js.map +1 -1
- package/dist/push.d.ts +2 -1
- package/dist/push.js +1 -1
- package/dist/react.d.ts +6 -2
- package/dist/react.js +1 -1
- package/dist/server.js +1 -1
- package/dist/web.d.ts +6 -2
- package/dist/web.js +6 -18
- package/dist/web.js.map +1 -1
- package/package.json +9 -9
- package/src/native/__tests__/attachment-slot.test.tsx +353 -0
- package/src/native/__tests__/organise-screens.test.tsx +12 -0
- package/src/native/__tests__/push-ids.test.ts +18 -0
- package/src/native/__tests__/push.test.ts +10 -4
- package/src/native/attachment-cards.tsx +249 -11
- package/src/native/copy.ts +15 -0
- package/src/native/index.ts +28 -4
- package/src/native/media.tsx +89 -2
- package/src/native/message-bubble.tsx +78 -12
- package/src/native/push.ts +5 -2
- package/src/native/search-screen.tsx +77 -69
- package/src/native/thread-screen.tsx +23 -6
- package/src/react/error-boundary.tsx +46 -0
- package/src/react/index.tsx +6 -2
- package/src/web/cards.tsx +2 -2
- package/src/web/error-boundary.tsx +2 -30
- package/dist/chunk-AZS3HNLM.js.map +0 -1
- package/dist/chunk-VEPZROQB.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/react/index.tsx"],"names":["list"],"mappings":"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","file":"chunk-JU2FAPBI.js","sourcesContent":["/**\n * @feat:chat\n * React hooks for chat, the same on web and native: the inbox, one\n * conversation (its messages, members, your role, who is typing) kept live by\n * Realtime hints, sending through the outbox, and message actions. Server\n * state is TanStack Query's; the renderers in /web and /native only draw.\n */\nimport { useQueries, useQuery, useQueryClient } from \"@tanstack/react-query\";\nimport { createContext, useCallback, useContext, useEffect, useMemo, useRef, useState, type ReactNode } from \"react\";\nimport type { ChatClient, ConversationChannel, MessagePage } from \"../core/client\";\nimport {\n createOutbox,\n type HostedUpload,\n type LocalFile,\n type Outbox,\n type OutboxStore,\n type QueuedMessage,\n type StorageUpload,\n} from \"../core/outbox\";\nimport { sendBytes } from \"../core/transfer\";\nimport { currentActivity, firstUnreadId, mergeThread, throttle, upsertMessages, type ThreadItem } from \"../core/thread\";\nimport { attachmentKindFor, randomId } from \"../core/media\";\nimport type {\n AvailabilityInput,\n ChatActivity,\n ChatAttachment,\n ChatAvailability,\n ChatLinkPreview,\n ChatMessage,\n ChatSearchHit,\n ChatSignal,\n ChatTopic,\n ScheduleInput,\n ScheduledMessage,\n SendInput,\n TopicInput,\n} from \"../core/types\";\n\nexport const chatKeys = {\n all: [\"genesis-chat\"] as const,\n inbox: (opts?: object) => [\"genesis-chat\", \"inbox\", opts ?? {}] as const,\n unread: () => [\"genesis-chat\", \"unread\"] as const,\n conversation: (id: string) => [\"genesis-chat\", \"conversation\", id] as const,\n members: (id: string) => [\"genesis-chat\", \"members\", id] as const,\n role: (id: string) => [\"genesis-chat\", \"role\", id] as const,\n pins: (id: string) => [\"genesis-chat\", \"pins\", id] as const,\n files: (paths: string[]) => [\"genesis-chat\", \"files\", [...paths].sort()] as const,\n /** Under the conversation's key, so its `conversation` hint (set_topic broadcasts one) refreshes them. */\n topics: (id: string) => [\"genesis-chat\", \"conversation\", id, \"topics\"] as const,\n scheduled: (conversationId?: string | null) => [\"genesis-chat\", \"scheduled\", conversationId ?? null] as const,\n availability: (conversationId: string) => [\"genesis-chat\", \"conversation\", conversationId, \"availability\"] as const,\n myAvailability: () => [\"genesis-chat\", \"my-availability\"] as const,\n search: (query: string, conversationId?: string | null) => [\"genesis-chat\", \"search\", conversationId ?? null, query] as const,\n previews: (messageIds: string[]) => [\"genesis-chat\", \"previews\", [...messageIds].sort()] as const,\n /** One message's link previews (useLinkPreviews keeps one query per message). */\n preview: (messageId: string) => [\"genesis-chat\", \"preview\", messageId] as const,\n};\n\n/** How many messages a catch-up asks for at a time, and how many pages before it gives up and jumps to the newest. */\nexport const CATCH_UP_PAGE = 200;\nexport const CATCH_UP_MAX_PAGES = 10;\n\n/** What a messages list holds in the query cache: the page, and whether older messages exist. */\nexport type MessagesData = MessagePage;\n\nfunction isMessagesData(v: unknown): v is MessagesData {\n return typeof v === \"object\" && v !== null && Array.isArray((v as MessagesData).messages) && \"hasEarlier\" in v;\n}\n\n/** Adds or replaces messages in a cached list, keeping `hasEarlier`. */\nfunction upsertInto(prev: unknown, incoming: ChatMessage[]): MessagesData | undefined {\n return isMessagesData(prev) ? { ...prev, messages: upsertMessages(prev.messages, incoming) } : undefined;\n}\n\n/** Does a messages list (`[genesis-chat, conversation, id, messages, threadRootId, topic]`) hold this message? */\nexport function belongsTo(key: readonly unknown[], m: ChatMessage): boolean {\n return (\n key[0] === \"genesis-chat\" &&\n key[1] === \"conversation\" &&\n key[2] === m.conversationId &&\n key[3] === \"messages\" &&\n (key[4] ?? null) === (m.threadRootId ?? null) &&\n (key[5] == null || key[5] === m.topic)\n );\n}\n\n/**\n * Hosted video uploads (Mux direct uploads): your server makes an upload and returns its URL\n * (`createVideoUploadHandler` in /server). A video the composer marks `hosted` is sent through\n * the outbox at once, in order, with `{ kind: \"video\", provider, providerId, status: \"pending\" }`,\n * while its bytes are PUT to that URL (see `hostedUploadFrom`). Without it, videos go to storage\n * as files.\n */\nexport interface ChatVideoUpload {\n create(conversationId: string): Promise<{ url: string; providerId: string; provider: \"mux\" }>;\n}\n\n/**\n * The outbox's `hostedUpload` from a `ChatVideoUpload`: mints the upload (or, resuming, reuses\n * the one minted before), resolves at once with its id, and PUTs the whole file to its URL in\n * the background (XMLHttpRequest where there is one, for progress). A native file URI is read\n * with `readFile`. Native apps with chunked, resumable uploads pass their own `hostedUpload`.\n */\nexport function hostedUploadFrom(\n videoUpload: ChatVideoUpload,\n options: { readFile?: (uri: string) => Promise<Blob | ArrayBuffer>; fetch?: typeof fetch } = {},\n): HostedUpload {\n return async (conversationId, file, { signal, onProgress, resume }) => {\n const minted = resume?.url\n ? { url: resume.url, providerId: resume.providerId, provider: resume.provider }\n : await videoUpload.create(conversationId);\n const done = (async () => {\n const body =\n typeof file.data === \"string\"\n ? await (options.readFile ?? (() => Promise.reject(new Error(\"This file can't be read on this device\"))))(file.data)\n : file.data;\n await sendBytes(minted.url, body, { method: \"PUT\", headers: { \"Content-Type\": file.contentType }, signal, onProgress, fetch: options.fetch });\n })();\n return { provider: minted.provider, providerId: minted.providerId, status: \"pending\", url: minted.url, done };\n };\n}\n\n/** What a kind's `title`, `subtitle` and `action` are told besides the attachment. */\nexport interface ChatCardContext {\n /** The card is on a message you sent (your own check-in reads \"Sent\", not \"Answer\"). */\n mine: boolean;\n}\n\n/** What an app attachment kind's card shows (a form, a check-in): plain data, drawn by each renderer. */\nexport interface ChatAttachmentKind {\n title(attachment: ChatAttachment, ctx?: ChatCardContext): string;\n subtitle?(attachment: ChatAttachment, ctx?: ChatCardContext): string | null | undefined;\n /** The card's button: a link (`href`) or a handler (`onPress`). */\n action?(attachment: ChatAttachment, ctx?: ChatCardContext): { label: string; href?: string; onPress?: () => void } | null | undefined;\n /** What previews call it (the inbox's last message, \"Check-in\"); the title by default. */\n label?: string;\n}\n\ninterface ChatContextValue {\n client: ChatClient;\n userId: string;\n outbox: Outbox;\n queue: QueuedMessage[];\n loadPeople?: (userIds: string[]) => Promise<Record<string, ChatPerson>>;\n videoUpload?: ChatVideoUpload;\n attachmentKinds?: Record<string, ChatAttachmentKind>;\n /** Retries every failed message (call it when the connection comes back: AppState, NetInfo). */\n retryAll(): Promise<void>;\n /** Forgets every unsent message, here and in the outbox store (call it on sign-out). */\n clearOutbox(): Promise<void>;\n /** Subscribe to inbox hints (one channel for the app, fanned out here). */\n onInbox(listener: (s: ChatSignal) => void): () => void;\n}\n\nconst ChatContext = createContext<ChatContextValue | null>(null);\n\nexport interface ChatProviderProps {\n client: ChatClient;\n /** The signed-in user's id (auth.users). */\n userId: string;\n /** Where unsent messages wait between launches (localStorage, MMKV…). Memory by default. */\n outboxStore?: OutboxStore;\n /** Reads a native file URI for upload. */\n readFile?: (uri: string) => Promise<Blob | ArrayBuffer>;\n /**\n * Replaces the plain upload (resumable uploads on native). `signal` aborts when the message is\n * discarded or the outbox cleared; `onProgress(sent, total)` fills the pending bubble's bar.\n */\n upload?: StorageUpload;\n /**\n * Starts a hosted upload for files marked `hosted` (see HostedUpload): resolve with\n * `{ provider, providerId, status: \"pending\", url?, done }` once the upload id exists. Default:\n * `hostedUploadFrom(videoUpload)` when `videoUpload` is given.\n */\n hostedUpload?: HostedUpload;\n /** Makes client ids (default: a random UUID that works without crypto.randomUUID). */\n newId?: () => string;\n /** Keeps a byte file (a pasted image, a recording) across launches: write it, return a URI. */\n persistFile?: (file: LocalFile) => Promise<string>;\n /** Lets go of a sent file's preview (default: revokes `blob:` object URLs only). */\n releasePreview?: (url: string) => void;\n /** Names and avatars for user ids, fetched in batches (usePeople, usePerson). */\n loadPeople?: (userIds: string[]) => Promise<Record<string, ChatPerson>>;\n /** Hosted video uploads (Mux); videos go to storage without it. */\n videoUpload?: ChatVideoUpload;\n /** Cards for your own attachment kinds (`{ form: { title, subtitle, action } }`). */\n attachmentKinds?: Record<string, ChatAttachmentKind>;\n children: ReactNode;\n}\n\n/** How the app shows a person. */\nexport interface ChatPerson {\n name: string;\n avatarUrl?: string | null;\n}\n\n/** Puts chat in reach of every hook below it. Needs a TanStack QueryClientProvider above it. */\nexport function ChatProvider({\n client,\n userId,\n outboxStore,\n readFile,\n upload,\n hostedUpload,\n newId,\n persistFile,\n releasePreview,\n loadPeople,\n videoUpload,\n attachmentKinds,\n children,\n}: ChatProviderProps) {\n const queryClient = useQueryClient();\n const [queue, setQueue] = useState<QueuedMessage[]>([]);\n const listeners = useRef(new Set<(s: ChatSignal) => void>());\n // The outbox lives as long as the client and user, so it reads the app's functions here at call\n // time: an inline `videoUpload.create` closing over a refreshed token keeps working.\n const live = useRef({ readFile, upload, hostedUpload, videoUpload, persistFile });\n live.current = { readFile, upload, hostedUpload, videoUpload, persistFile };\n\n const outbox = useMemo(\n () =>\n createOutbox({\n client,\n userId,\n store: outboxStore,\n readFile: readFile && ((uri) => (live.current.readFile ?? readFile)(uri)),\n upload: upload && ((...args) => (live.current.upload ?? upload)(...args)),\n hostedUpload:\n hostedUpload || videoUpload\n ? (...args) => {\n const now = live.current;\n const video = now.videoUpload ?? videoUpload;\n const send = now.hostedUpload ?? (video ? hostedUploadFrom(video, { readFile: now.readFile ?? readFile }) : hostedUpload!);\n return send(...args);\n }\n : undefined,\n newId,\n persistFile: persistFile && ((file) => (live.current.persistFile ?? persistFile)(file)),\n releasePreview,\n onChange: setQueue,\n onSent: (message) => {\n // Into every loaded list it belongs to (the main timeline, its thread, its topic), so\n // the bubble never disappears between the send landing and the live hint.\n queryClient.setQueriesData<MessagesData>(\n { predicate: (q) => belongsTo(q.queryKey, message) },\n (prev) => upsertInto(prev, [message]) ?? prev,\n );\n void queryClient.invalidateQueries({ queryKey: [\"genesis-chat\", \"scheduled\"] });\n void queryClient.invalidateQueries({ queryKey: [\"genesis-chat\", \"inbox\"] });\n },\n }),\n // A new person or client is a new outbox.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [client, userId],\n );\n\n useEffect(() => {\n // What a relaunch left unsent is retried once (messages waiting for a lost file stay put),\n // and again whenever the browser comes back online.\n void outbox.load().then(() => outbox.retryAll()).catch(() => undefined);\n const online = () => void outbox.retryAll().catch(() => undefined);\n const target = typeof window !== \"undefined\" && typeof window.addEventListener === \"function\" ? window : null;\n target?.addEventListener(\"online\", online);\n const sub = client.subscribeInbox(userId, (signal) => {\n void queryClient.invalidateQueries({ queryKey: [\"genesis-chat\", \"inbox\"] });\n void queryClient.invalidateQueries({ queryKey: chatKeys.unread() });\n for (const l of listeners.current) l(signal);\n });\n return () => {\n sub.unsubscribe();\n target?.removeEventListener(\"online\", online);\n };\n }, [client, userId, outbox, queryClient]);\n\n const value = useMemo<ChatContextValue>(\n () => ({\n client,\n userId,\n outbox,\n queue,\n loadPeople,\n videoUpload,\n attachmentKinds,\n retryAll: () => outbox.retryAll(),\n clearOutbox: () => outbox.clear(),\n onInbox: (l) => {\n listeners.current.add(l);\n return () => listeners.current.delete(l);\n },\n }),\n [client, userId, outbox, queue, loadPeople, videoUpload, attachmentKinds],\n );\n return <ChatContext.Provider value={value}>{children}</ChatContext.Provider>;\n}\n\nexport function useChat(): ChatContextValue {\n const ctx = useContext(ChatContext);\n if (!ctx) throw new Error(\"Chat hooks need a <ChatProvider> above them.\");\n return ctx;\n}\n\n/** Your conversations, live. `kind` narrows to one kind; `archived` shows the archived ones. */\nexport function useInbox(opts: { kind?: string; kinds?: string[]; excludeKinds?: string[]; archived?: boolean; limit?: number } = {}) {\n const { client } = useChat();\n const query = useQuery({ queryKey: chatKeys.inbox(opts), queryFn: () => client.inbox(opts), staleTime: 15_000 });\n return { items: query.data ?? [], isLoading: query.isLoading, error: query.error, refetch: query.refetch };\n}\n\n/** How many messages wait for you everywhere (for a badge), live. */\nexport function useUnreadTotal(opts: { excludeKinds?: string[] } = {}): number {\n const { client } = useChat();\n return (\n useQuery({ queryKey: [...chatKeys.unread(), opts.excludeKinds ?? []], queryFn: () => client.unreadTotal(opts), staleTime: 15_000 }).data ??\n 0\n );\n}\n\nexport interface UseConversationOptions {\n /** Mark messages read as they arrive while this is true (the thread is on screen). Default true. */\n markRead?: boolean;\n /** One thread's replies instead of the main timeline. */\n threadRootId?: string;\n /** One topic's messages. */\n topic?: string;\n pageSize?: number;\n}\n\n/** One conversation: its messages (with what you are still sending), members, your role, and who is typing. */\nexport function useConversation(conversationId: string | null | undefined, opts: UseConversationOptions = {}) {\n const { client, userId, outbox, queue } = useChat();\n const queryClient = useQueryClient();\n const id = conversationId ?? \"\";\n const enabled = Boolean(conversationId);\n const pageSize = opts.pageSize ?? 50;\n const messagesKey = useMemo(\n () => [...chatKeys.conversation(id), \"messages\", opts.threadRootId ?? null, opts.topic ?? null] as const,\n [id, opts.threadRootId, opts.topic],\n );\n\n const conversation = useQuery({ queryKey: chatKeys.conversation(id), queryFn: () => client.conversation(id), enabled });\n const members = useQuery({ queryKey: chatKeys.members(id), queryFn: () => client.members(id), enabled, staleTime: 60_000, refetchOnMount: \"always\" });\n const kindRules = useQuery({\n queryKey: [\"genesis-chat\", \"kind\", conversation.data?.kind ?? \"\"],\n queryFn: () => client.kind(conversation.data!.kind),\n enabled: Boolean(conversation.data?.kind),\n staleTime: 10 * 60_000,\n });\n const access = useQuery({\n queryKey: chatKeys.role(id),\n queryFn: async () => ({ role: await client.myRole(id), canPost: await client.canPost(id) }),\n enabled,\n staleTime: 60_000,\n });\n\n const [loadingEarlier, setLoadingEarlier] = useState(false);\n const fetchPage = useCallback(\n () => client.messages(id, { limit: pageSize, threadRootId: opts.threadRootId, topic: opts.topic }),\n [client, id, pageSize, opts.threadRootId, opts.topic],\n );\n // Kept fresh by live hints and the catch-up on every join, so never refetched on its own.\n const messages = useQuery<MessagesData>({ queryKey: messagesKey, queryFn: fetchPage, enabled, staleTime: Infinity });\n const hasEarlier = messages.data?.hasEarlier ?? false;\n // Where \"New\" goes: what you had read when the conversation opened.\n const [readWhenOpened, setReadWhenOpened] = useState<number | null>(null);\n\n const merge = useCallback(\n (incoming: ChatMessage[], hasEarlierNow?: boolean) =>\n queryClient.setQueryData<MessagesData>(messagesKey, (prev) => {\n const base = prev ?? { messages: [], hasEarlier: false };\n return { messages: upsertMessages(base.messages, incoming), hasEarlier: hasEarlierNow ?? base.hasEarlier };\n }),\n [queryClient, messagesKey],\n );\n\n /**\n * Fetches what came after the newest message held (everything, for an empty list). Runs on\n * every join of the live channel, the first included, so messages that arrived while the\n * thread was closed, or between the first fetch and the subscription, always show. Pages\n * until a short one; after CATCH_UP_MAX_PAGES full pages (a long time away from a busy group)\n * it shows the newest page instead, with the rest behind \"load earlier\".\n */\n const catchUp = useCallback(async () => {\n const current = queryClient.getQueryData<MessagesData>(messagesKey) ?? (await queryClient.ensureQueryData<MessagesData>({ queryKey: messagesKey, queryFn: fetchPage }));\n const list = current.messages;\n let after = list.length ? list[list.length - 1]!.seq : 0;\n for (let pages = 0; ; ) {\n const page = await client.messages(id, { afterSeq: after, limit: CATCH_UP_PAGE, threadRootId: opts.threadRootId, topic: opts.topic });\n if (page.messages.length) merge(page.messages);\n if (page.messages.length < CATCH_UP_PAGE) return;\n after = Math.max(after, ...page.messages.map((m) => m.seq));\n if (++pages >= CATCH_UP_MAX_PAGES) break;\n }\n const newest = await fetchPage();\n queryClient.setQueryData<MessagesData>(messagesKey, { messages: newest.messages, hasEarlier: true });\n }, [client, fetchPage, id, merge, messagesKey, opts.threadRootId, opts.topic, queryClient]);\n\n const [activity, setActivity] = useState<ChatActivity[]>([]);\n const channel = useRef<ConversationChannel | null>(null);\n useEffect(() => {\n if (!enabled) return;\n const fetchOne = async (messageId: string) => {\n const m = await client.message(messageId);\n if (!m) return;\n const belongs = opts.threadRootId ? m.threadRootId === opts.threadRootId : m.threadRootId === null;\n if (belongs && (!opts.topic || m.topic === opts.topic)) merge([m]);\n if (m.threadRootId && !opts.threadRootId) {\n const root = await client.message(m.threadRootId);\n if (root) merge([root]);\n }\n };\n channel.current = client.subscribeConversation(id, userId, {\n onSignal: (s) => {\n if (s.type === \"message\") void fetchOne(s.id);\n else if (s.type === \"reaction\") void fetchOne(s.messageId);\n else if (s.type === \"members\") {\n void queryClient.invalidateQueries({ queryKey: chatKeys.members(id) });\n void queryClient.invalidateQueries({ queryKey: chatKeys.role(id) });\n } else if (s.type === \"conversation\") {\n // The conversation row, its topics and availability (not its messages, kept by hints).\n void queryClient.invalidateQueries({ queryKey: chatKeys.conversation(id), exact: true });\n void queryClient.invalidateQueries({ queryKey: chatKeys.topics(id) });\n void queryClient.invalidateQueries({ queryKey: chatKeys.pins(id) });\n }\n },\n onActivity: (a) => setActivity((prev) => currentActivity([...prev, a])),\n onJoin: () => void catchUp().catch(() => undefined),\n });\n return () => {\n channel.current?.unsubscribe();\n channel.current = null;\n };\n }, [client, enabled, id, userId, merge, catchUp, queryClient, opts.threadRootId, opts.topic]);\n\n // Activity fades after a few seconds without news.\n useEffect(() => {\n if (activity.length === 0) return;\n const t = setTimeout(() => setActivity((prev) => currentActivity(prev)), 2000);\n return () => clearTimeout(t);\n }, [activity]);\n\n const list = useMemo(() => messages.data?.messages ?? [], [messages.data]);\n const latestSeq = list.length ? list[list.length - 1]!.seq : 0;\n // Where \"New\" goes comes from your read place as fetched for this opening, never a cached\n // copy from an earlier visit (which would draw the line above messages already read).\n const myLastRead = members.isFetchedAfterMount ? members.data?.find((m) => m.userId === userId)?.lastReadSeq : undefined;\n useEffect(() => {\n if (readWhenOpened === null && myLastRead !== undefined) setReadWhenOpened(myLastRead);\n }, [myLastRead, readWhenOpened]);\n\n const markRead = useCallback(async () => {\n if (!enabled || latestSeq === 0) return;\n await client.markRead(id, latestSeq);\n void queryClient.invalidateQueries({ queryKey: [\"genesis-chat\", \"inbox\"] });\n void queryClient.invalidateQueries({ queryKey: chatKeys.unread() });\n }, [client, enabled, id, latestSeq, queryClient]);\n\n // Your read place is one number for the whole conversation, so only the whole timeline moves\n // it: a topic (or a thread) shows a slice, and marking up to its newest message would also\n // mark unseen messages in other topics read.\n const shouldMark = opts.markRead !== false && !opts.threadRootId && !opts.topic;\n useEffect(() => {\n if (shouldMark && latestSeq > 0) void markRead().catch(() => undefined);\n }, [shouldMark, latestSeq, markRead]);\n\n const refetchConversation = useCallback(\n () =>\n Promise.all([\n // The conversation and what hangs off it (topics, availability), never its message lists:\n // a refetch would replace loaded history and merged live messages with one fresh page.\n queryClient.refetchQueries({ queryKey: chatKeys.conversation(id), predicate: (q) => q.queryKey[3] !== \"messages\" }),\n queryClient.refetchQueries({ queryKey: chatKeys.members(id) }),\n queryClient.refetchQueries({ queryKey: chatKeys.role(id) }),\n queryClient.refetchQueries({ queryKey: chatKeys.pins(id) }),\n queryClient.refetchQueries({ queryKey: [\"genesis-chat\", \"kind\"] }),\n ]).then(() => undefined),\n [queryClient, id],\n );\n\n const loadEarlier = useCallback(async () => {\n const first = list[0];\n if (!first || loadingEarlier) return;\n setLoadingEarlier(true);\n try {\n const page = await client.messages(id, { beforeSeq: first.seq, limit: pageSize, threadRootId: opts.threadRootId, topic: opts.topic });\n merge(page.messages, page.hasEarlier);\n } finally {\n setLoadingEarlier(false);\n }\n }, [client, id, list, loadingEarlier, merge, opts.threadRootId, opts.topic, pageSize]);\n\n /** Loads earlier messages until the one with this seq is held (a search result, a pinned message). True when it is. */\n const loadUntil = useCallback(\n async (seq: number) => {\n let current = queryClient.getQueryData<MessagesData>(messagesKey);\n for (let guard = 0; guard < 20 && current; guard++) {\n const first = current.messages[0];\n if (!first || first.seq <= seq || !current.hasEarlier) break;\n const page = await client.messages(id, {\n beforeSeq: first.seq,\n limit: Math.min(200, first.seq - seq + 10),\n threadRootId: opts.threadRootId,\n topic: opts.topic,\n });\n merge(page.messages, page.hasEarlier);\n current = queryClient.getQueryData<MessagesData>(messagesKey);\n }\n return Boolean(current?.messages.some((m) => m.seq === seq));\n },\n [client, id, merge, messagesKey, opts.threadRootId, opts.topic, queryClient],\n );\n\n const pending = useMemo(\n () =>\n queue.filter(\n (q) =>\n q.input.conversationId === id &&\n (q.input.threadRootId ?? null) === (opts.threadRootId ?? null) &&\n (!opts.topic || q.input.topic === opts.topic),\n ).map((q) => ({ ...q, files: q.pendingFiles })),\n [queue, id, opts.threadRootId, opts.topic],\n );\n const items: ThreadItem[] = useMemo(() => mergeThread(list, pending), [list, pending]);\n\n const signalTyping = useMemo(() => throttle(() => channel.current?.signal(\"typing\")), []);\n const signalRecording = useMemo(\n () => throttle(() => channel.current?.signal(\"recording-voice\")),\n [],\n );\n const signalRecordingVideo = useMemo(() => throttle(() => channel.current?.signal(\"recording-video\")), []);\n\n /** Sends text and files to this conversation (through the outbox: shown at once, retried safely). */\n const send = useCallback(\n (input: Omit<SendInput, \"conversationId\" | \"clientId\">, files: LocalFile[] = []) =>\n outbox.send({ ...input, conversationId: id, threadRootId: input.threadRootId ?? opts.threadRootId, topic: input.topic ?? opts.topic }, files),\n [outbox, id, opts.threadRootId, opts.topic],\n );\n\n return {\n conversation: conversation.data ?? null,\n members: members.data ?? [],\n role: access.data?.role ?? null,\n canPost: access.data?.canPost ?? false,\n /** Your role and posting rights are still loading: show the composer as waiting, not refused. */\n accessLoading: enabled && access.isLoading,\n /** The conversation itself is still loading (it settles to `null` when you can't see it). */\n conversationLoading: conversation.isLoading,\n /** Your role couldn't be loaded (offline): offer `refetchAccess`, don't say \"can't post\". */\n accessError: access.error ?? null,\n /** Retries everything this conversation loads (role, members, the conversation, topics, availability, pins), not only access. */\n refetchAccess: refetchConversation,\n /** Same as refetchAccess: every per-conversation lookup again, for a Retry after being offline. */\n refetchConversation,\n /** The kind's rules (max members, threads, who posts). */\n kind: kindRules.data ?? null,\n /** May you pin here: owners and admins, or anyone in a two-person conversation. */\n canPin:\n access.data?.role === \"owner\" ||\n access.data?.role === \"admin\" ||\n (access.data?.role === \"member\" && kindRules.data?.maxMembers === 2),\n /** Gives a message whose files were lost on a relaunch its files again. */\n reattach: outbox.reattach,\n items,\n messages: list,\n isLoading: messages.isLoading || conversation.isLoading,\n error: messages.error ?? conversation.error,\n hasEarlier,\n loadingEarlier,\n loadEarlier,\n loadUntil,\n /** Where to draw the \"New\" line, from what you had read when it opened. */\n firstUnreadId: readWhenOpened === null ? null : firstUnreadId(list, readWhenOpened, userId),\n activity: currentActivity(activity),\n signalTyping,\n signalRecording,\n /** Tells the others you are recording a video (throttled). */\n signalRecordingVideo,\n markRead,\n send,\n retry: outbox.retry,\n discard: outbox.discard,\n refetch: catchUp,\n };\n}\n\nexport type ConversationState = ReturnType<typeof useConversation>;\n\n/** Edit, delete, react, pin, save and report, refreshing what they change. */\nexport function useMessageActions() {\n const { client } = useChat();\n const queryClient = useQueryClient();\n return useMemo(() => {\n const refresh = async (conversationId: string, messageId: string) => {\n const m = await client.message(messageId);\n queryClient.setQueriesData<MessagesData>({ queryKey: chatKeys.conversation(conversationId) }, (prev) =>\n m ? (upsertInto(prev, [m]) ?? prev) : prev,\n );\n };\n return {\n edit: async (m: ChatMessage, body: string, mentions: string[] = []) => {\n await client.edit(m.id, body, mentions);\n await refresh(m.conversationId, m.id);\n },\n remove: async (m: ChatMessage) => {\n await client.remove(m.id);\n await refresh(m.conversationId, m.id);\n },\n react: async (m: ChatMessage, emoji: string, on: boolean) => {\n await client.react(m.id, emoji, on);\n await refresh(m.conversationId, m.id);\n },\n pin: async (m: ChatMessage, on: boolean) => {\n await client.pin(m.id, on);\n void queryClient.invalidateQueries({ queryKey: chatKeys.pins(m.conversationId) });\n },\n save: (m: ChatMessage, on: boolean, note?: string) => client.save(m.id, on, note),\n report: (m: ChatMessage, reason: \"spam\" | \"harassment\" | \"safety\" | \"other\", note?: string) => client.report(m.id, reason, note),\n };\n }, [client, queryClient]);\n}\n\n/**\n * Names and avatars for these people, from the provider's `loadPeople`, fetched as one\n * batch per set of ids and cached. Unknown ids are left out.\n */\nexport function usePeople(userIds: (string | null | undefined)[]): Record<string, ChatPerson> {\n const { loadPeople } = useChat();\n const ids = useMemo(() => [...new Set(userIds.filter((x): x is string => Boolean(x)))].sort(), [userIds]);\n return (\n useQuery({\n queryKey: [\"genesis-chat\", \"people\", ids],\n queryFn: () => loadPeople!(ids),\n enabled: Boolean(loadPeople) && ids.length > 0,\n staleTime: 5 * 60_000,\n }).data ?? {}\n );\n}\n\n/** One person's name and avatar (see usePeople). */\nexport function usePerson(userId: string | null | undefined): ChatPerson | null {\n const people = usePeople(useMemo(() => [userId], [userId]));\n return userId ? (people[userId] ?? null) : null;\n}\n\n/** The pinned message ids of a conversation. */\nexport function usePins(conversationId: string | null | undefined): string[] {\n const { client } = useChat();\n return (\n useQuery({ queryKey: chatKeys.pins(conversationId ?? \"\"), queryFn: () => client.pins(conversationId!), enabled: Boolean(conversationId) }).data ?? []\n );\n}\n\n/** Signed links for files (cached by the client until shortly before they expire). */\nexport function useFileUrls(paths: (string | null | undefined)[]): Record<string, string> {\n const { client } = useChat();\n const list = useMemo(() => [...new Set(paths.filter((p): p is string => Boolean(p)))], [paths]);\n return (\n useQuery({ queryKey: chatKeys.files(list), queryFn: () => client.fileUrls(list), enabled: list.length > 0, staleTime: 50 * 60_000 }).data ?? {}\n );\n}\n\n/** Starts (or finds again) a conversation, then refreshes the inbox. */\nexport function useStartConversation() {\n const { client } = useChat();\n const queryClient = useQueryClient();\n return useCallback(\n async (kind: string, memberIds: string[], opts?: { title?: string; subjectType?: string; subjectId?: string }) => {\n const id = await client.startConversation(kind, memberIds, opts);\n void queryClient.invalidateQueries({ queryKey: [\"genesis-chat\", \"inbox\"] });\n return id;\n },\n [client, queryClient],\n );\n}\n\n// ── Migration 0002: topics, scheduled send, availability, broadcast, search, previews ──\n\n/**\n * A conversation's topics, live (set_topic's hint refreshes them), and `setTopic` for owners\n * and admins: add one (`setTopic(\"week-1\", { title: \"Week 1\" })`), close or reopen it.\n */\nexport function useTopics(conversationId: string | null | undefined) {\n const { client } = useChat();\n const queryClient = useQueryClient();\n const id = conversationId ?? \"\";\n const query = useQuery({ queryKey: chatKeys.topics(id), queryFn: () => client.topics(id), enabled: Boolean(conversationId), staleTime: 60_000 });\n const setTopic = useCallback(\n async (topic: string, input: TopicInput = {}) => {\n await client.setTopic(id, topic, input);\n await queryClient.invalidateQueries({ queryKey: chatKeys.topics(id) });\n },\n [client, id, queryClient],\n );\n const topics: ChatTopic[] = query.data ?? [];\n return { topics, isLoading: query.isLoading, error: query.error, setTopic, refetch: query.refetch };\n}\n\n/**\n * Your scheduled messages (in one conversation, or all), soonest first, with `schedule` and\n * `cancel` (which also removes one that failed). `schedule` uploads its files to storage first,\n * the way `send` does (the provider's `upload` hook, or a native URI read through `readFile`),\n * then schedules them with the message. A file marked `hosted` goes to storage too.\n */\nexport function useScheduled(conversationId?: string | null, opts: { enabled?: boolean } = {}) {\n const { client, outbox } = useChat();\n const queryClient = useQueryClient();\n const query = useQuery({\n queryKey: chatKeys.scheduled(conversationId),\n queryFn: () => client.scheduled(conversationId ?? undefined),\n enabled: opts.enabled ?? true,\n staleTime: 30_000,\n });\n const refresh = useCallback(() => queryClient.invalidateQueries({ queryKey: [\"genesis-chat\", \"scheduled\"] }), [queryClient]);\n const schedule = useCallback(\n async (input: Omit<ScheduleInput, \"clientId\"> & { clientId?: string }, files: LocalFile[] = []) => {\n const attachments = [...(input.attachments ?? [])];\n for (const f of files) {\n const path = await outbox.uploadFile(input.conversationId, f);\n attachments.push({ ...f.meta, kind: f.meta?.kind ?? attachmentKindFor(f.contentType), path, name: f.meta?.name ?? f.name, mime: f.contentType });\n }\n const id = await client.schedule({ ...input, clientId: input.clientId ?? randomId(), attachments });\n await refresh();\n return id;\n },\n [client, outbox, refresh],\n );\n const cancel = useCallback(\n async (id: string) => {\n queryClient.setQueriesData<ScheduledMessage[]>({ queryKey: [\"genesis-chat\", \"scheduled\"] }, (prev) => (Array.isArray(prev) ? prev.filter((s) => s.id !== id) : prev));\n try {\n await client.cancelScheduled(id);\n } finally {\n await refresh();\n }\n },\n [client, queryClient, refresh],\n );\n const items: ScheduledMessage[] = query.data ?? [];\n return { items, isLoading: query.isLoading, error: query.error, schedule, cancel, refetch: query.refetch };\n}\n\n/**\n * Availability: yours (`mine`, `setMine`) and, given a conversation, its members' (`members`,\n * `forUser`). Pair with `awayLine` and `isWithinWorkingHours` from the core.\n */\nexport function useAvailability(conversationId?: string | null) {\n const { client, userId } = useChat();\n const queryClient = useQueryClient();\n const mine = useQuery({ queryKey: chatKeys.myAvailability(), queryFn: () => client.myAvailability(), staleTime: 5 * 60_000 });\n const members = useQuery({\n queryKey: chatKeys.availability(conversationId ?? \"\"),\n queryFn: () => client.availabilityFor(conversationId!),\n enabled: Boolean(conversationId),\n staleTime: 5 * 60_000,\n });\n const setMine = useCallback(\n async (input: AvailabilityInput) => {\n await client.setAvailability(input);\n await queryClient.invalidateQueries({ queryKey: chatKeys.myAvailability() });\n await queryClient.invalidateQueries({ predicate: (q) => q.queryKey[0] === \"genesis-chat\" && q.queryKey[3] === \"availability\" });\n },\n [client, queryClient],\n );\n const list: ChatAvailability[] = members.data ?? [];\n const forUser = useCallback((id: string) => list.find((a) => a.userId === id) ?? null, [list]);\n return {\n mine: mine.data ?? null,\n mineLoading: mine.isLoading,\n setMine,\n members: list,\n /** Everyone else's, without yours. */\n others: list.filter((a) => a.userId !== userId),\n forUser,\n isLoading: mine.isLoading || (Boolean(conversationId) && members.isLoading),\n };\n}\n\n/** Sends one message into many conversations (replies come back privately in each). */\nexport function useBroadcast() {\n const { client } = useChat();\n const queryClient = useQueryClient();\n const [sending, setSending] = useState(false);\n const send = useCallback(\n async (conversationIds: string[], body: string, opts: { silent?: boolean; clientId?: string } = {}) => {\n setSending(true);\n try {\n const ids = await client.broadcast(conversationIds, opts.clientId ?? randomId(), body, { silent: opts.silent });\n void queryClient.invalidateQueries({ queryKey: [\"genesis-chat\", \"inbox\"] });\n return ids;\n } finally {\n setSending(false);\n }\n },\n [client, queryClient],\n );\n return { send, sending };\n}\n\n/** The value, once it has stopped changing for `ms`. */\nexport function useDebouncedValue<T>(value: T, ms: number): T {\n const [v, setV] = useState(value);\n useEffect(() => {\n if (ms <= 0) {\n setV(value);\n return;\n }\n const t = setTimeout(() => setV(value), ms);\n return () => clearTimeout(t);\n }, [value, ms]);\n return ms <= 0 ? value : v;\n}\n\n/** Search, debounced (250 ms by default), in one conversation or all of yours. Queries under two characters return nothing. */\nexport function useSearch(query: string, opts: { conversationId?: string | null; debounceMs?: number; limit?: number } = {}) {\n const { client } = useChat();\n const q = useDebouncedValue(query.trim(), opts.debounceMs ?? 250);\n const enabled = q.length >= 2;\n const result = useQuery({\n queryKey: chatKeys.search(q, opts.conversationId),\n queryFn: () => client.search(q, opts.conversationId ?? null, { limit: opts.limit }),\n enabled,\n staleTime: 30_000,\n });\n const hits: ChatSearchHit[] = enabled ? (result.data ?? []) : [];\n return {\n hits,\n /** The query the hits are for. */\n query: q,\n /** Typing, or fetching: results are on their way. */\n isSearching: query.trim() !== q || (enabled && result.isFetching),\n error: result.error,\n };\n}\n\n/** At most this many link-preview reads at once, per client. */\nexport const LINK_PREVIEW_CONCURRENCY = 4;\nconst previewGates = new WeakMap<object, <T>(task: () => Promise<T>) => Promise<T>>();\n\n/** A gate that lets `max` tasks run at once and queues the rest. */\nfunction gate(max: number) {\n let active = 0;\n const waiting: (() => void)[] = [];\n return async <T,>(task: () => Promise<T>): Promise<T> => {\n if (active >= max) await new Promise<void>((r) => waiting.push(r));\n active += 1;\n try {\n return await task();\n } finally {\n active -= 1;\n waiting.shift()?.();\n }\n };\n}\n\n/**\n * Link previews for these messages, by message id, in link order (only those the server has\n * fetched). Pass the messages whose text has links (`extractLinks(body).length > 0`). One query\n * per message, so a new message asks only for its own, and at most LINK_PREVIEW_CONCURRENCY\n * run at once. One with none yet is asked again a few times, since the runner fills them\n * moments after it lands.\n */\nexport function useLinkPreviews(messageIds: (string | null | undefined)[]): Record<string, ChatLinkPreview[]> {\n const { client } = useChat();\n const list = useMemo(() => [...new Set(messageIds.filter((u): u is string => Boolean(u)))].sort(), [messageIds]);\n let run = previewGates.get(client);\n if (!run) {\n run = gate(LINK_PREVIEW_CONCURRENCY);\n previewGates.set(client, run);\n }\n const limited = run;\n const combine = useCallback(\n (results: { data?: ChatLinkPreview[] }[]) => {\n let out: Record<string, ChatLinkPreview[]> | null = null;\n results.forEach((r, i) => {\n if (r.data) (out ??= {})[list[i]!] = r.data;\n });\n return out ?? EMPTY_PREVIEWS;\n },\n [list],\n );\n return useQueries({\n queries: list.map((id) => ({\n queryKey: chatKeys.preview(id),\n queryFn: () => limited(async () => (await client.linkPreviewsFor([id]))[id] ?? []),\n staleTime: 60_000,\n refetchInterval: (q: { state: { data?: ChatLinkPreview[]; dataUpdateCount: number } }) =>\n !q.state.data?.length && q.state.dataUpdateCount < 4 ? 5_000 : false,\n })),\n combine,\n });\n}\nconst EMPTY_PREVIEWS: Record<string, ChatLinkPreview[]> = {};\n\nexport type { ThreadItem, LocalFile, QueuedMessage };\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/react/index.tsx"],"names":["list"],"mappings":"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","file":"chunk-XQ2ULNHV.js","sourcesContent":["/**\n * @feat:chat\n * React hooks for chat, the same on web and native: the inbox, one\n * conversation (its messages, members, your role, who is typing) kept live by\n * Realtime hints, sending through the outbox, and message actions. Server\n * state is TanStack Query's; the renderers in /web and /native only draw.\n */\nimport { useQueries, useQuery, useQueryClient } from \"@tanstack/react-query\";\nimport { createContext, useCallback, useContext, useEffect, useMemo, useRef, useState, type ReactNode } from \"react\";\nimport type { ChatClient, ConversationChannel, MessagePage } from \"../core/client\";\nimport {\n createOutbox,\n type HostedUpload,\n type LocalFile,\n type Outbox,\n type OutboxStore,\n type QueuedMessage,\n type StorageUpload,\n} from \"../core/outbox\";\nimport { sendBytes } from \"../core/transfer\";\nimport { currentActivity, firstUnreadId, mergeThread, throttle, upsertMessages, type ThreadItem } from \"../core/thread\";\nimport { attachmentKindFor, randomId } from \"../core/media\";\nimport type {\n AvailabilityInput,\n ChatActivity,\n ChatAttachment,\n ChatAvailability,\n ChatLinkPreview,\n ChatMessage,\n ChatSearchHit,\n ChatSignal,\n ChatTopic,\n ScheduleInput,\n ScheduledMessage,\n SendInput,\n TopicInput,\n} from \"../core/types\";\n\nexport const chatKeys = {\n all: [\"genesis-chat\"] as const,\n inbox: (opts?: object) => [\"genesis-chat\", \"inbox\", opts ?? {}] as const,\n unread: () => [\"genesis-chat\", \"unread\"] as const,\n conversation: (id: string) => [\"genesis-chat\", \"conversation\", id] as const,\n members: (id: string) => [\"genesis-chat\", \"members\", id] as const,\n role: (id: string) => [\"genesis-chat\", \"role\", id] as const,\n pins: (id: string) => [\"genesis-chat\", \"pins\", id] as const,\n files: (paths: string[]) => [\"genesis-chat\", \"files\", [...paths].sort()] as const,\n /** Under the conversation's key, so its `conversation` hint (set_topic broadcasts one) refreshes them. */\n topics: (id: string) => [\"genesis-chat\", \"conversation\", id, \"topics\"] as const,\n scheduled: (conversationId?: string | null) => [\"genesis-chat\", \"scheduled\", conversationId ?? null] as const,\n availability: (conversationId: string) => [\"genesis-chat\", \"conversation\", conversationId, \"availability\"] as const,\n myAvailability: () => [\"genesis-chat\", \"my-availability\"] as const,\n search: (query: string, conversationId?: string | null) => [\"genesis-chat\", \"search\", conversationId ?? null, query] as const,\n previews: (messageIds: string[]) => [\"genesis-chat\", \"previews\", [...messageIds].sort()] as const,\n /** One message's link previews (useLinkPreviews keeps one query per message). */\n preview: (messageId: string) => [\"genesis-chat\", \"preview\", messageId] as const,\n};\n\n/** How many messages a catch-up asks for at a time, and how many pages before it gives up and jumps to the newest. */\nexport const CATCH_UP_PAGE = 200;\nexport const CATCH_UP_MAX_PAGES = 10;\n\n/** What a messages list holds in the query cache: the page, and whether older messages exist. */\nexport type MessagesData = MessagePage;\n\nfunction isMessagesData(v: unknown): v is MessagesData {\n return typeof v === \"object\" && v !== null && Array.isArray((v as MessagesData).messages) && \"hasEarlier\" in v;\n}\n\n/** Adds or replaces messages in a cached list, keeping `hasEarlier`. */\nfunction upsertInto(prev: unknown, incoming: ChatMessage[]): MessagesData | undefined {\n return isMessagesData(prev) ? { ...prev, messages: upsertMessages(prev.messages, incoming) } : undefined;\n}\n\n/** Does a messages list (`[genesis-chat, conversation, id, messages, threadRootId, topic]`) hold this message? */\nexport function belongsTo(key: readonly unknown[], m: ChatMessage): boolean {\n return (\n key[0] === \"genesis-chat\" &&\n key[1] === \"conversation\" &&\n key[2] === m.conversationId &&\n key[3] === \"messages\" &&\n (key[4] ?? null) === (m.threadRootId ?? null) &&\n (key[5] == null || key[5] === m.topic)\n );\n}\n\n/**\n * Hosted video uploads (Mux direct uploads): your server makes an upload and returns its URL\n * (`createVideoUploadHandler` in /server). A video the composer marks `hosted` is sent through\n * the outbox at once, in order, with `{ kind: \"video\", provider, providerId, status: \"pending\" }`,\n * while its bytes are PUT to that URL (see `hostedUploadFrom`). Without it, videos go to storage\n * as files.\n */\nexport interface ChatVideoUpload {\n create(conversationId: string): Promise<{ url: string; providerId: string; provider: \"mux\" }>;\n}\n\n/**\n * The outbox's `hostedUpload` from a `ChatVideoUpload`: mints the upload (or, resuming, reuses\n * the one minted before), resolves at once with its id, and PUTs the whole file to its URL in\n * the background (XMLHttpRequest where there is one, for progress). A native file URI is read\n * with `readFile`. Native apps with chunked, resumable uploads pass their own `hostedUpload`.\n */\nexport function hostedUploadFrom(\n videoUpload: ChatVideoUpload,\n options: { readFile?: (uri: string) => Promise<Blob | ArrayBuffer>; fetch?: typeof fetch } = {},\n): HostedUpload {\n return async (conversationId, file, { signal, onProgress, resume }) => {\n const minted = resume?.url\n ? { url: resume.url, providerId: resume.providerId, provider: resume.provider }\n : await videoUpload.create(conversationId);\n const done = (async () => {\n const body =\n typeof file.data === \"string\"\n ? await (options.readFile ?? (() => Promise.reject(new Error(\"This file can't be read on this device\"))))(file.data)\n : file.data;\n await sendBytes(minted.url, body, { method: \"PUT\", headers: { \"Content-Type\": file.contentType }, signal, onProgress, fetch: options.fetch });\n })();\n return { provider: minted.provider, providerId: minted.providerId, status: \"pending\", url: minted.url, done };\n };\n}\n\n/** What a kind's `title`, `subtitle` and `action` are told besides the attachment. */\nexport interface ChatCardContext {\n /** The card is on a message you sent (your own check-in reads \"Sent\", not \"Answer\"). */\n mine: boolean;\n}\n\n/** What an app attachment kind's card shows (a form, a check-in): plain data, drawn by each renderer. */\nexport interface ChatAttachmentKind {\n title(attachment: ChatAttachment, ctx?: ChatCardContext): string;\n subtitle?(attachment: ChatAttachment, ctx?: ChatCardContext): string | null | undefined;\n /**\n * The card's button: a link (`href`) or a handler (`onPress`). On native the button is also the\n * bubble's VoiceOver action, and a handler that returns a promise shows the card as busy until\n * it settles (and a short error if it rejects).\n */\n action?(attachment: ChatAttachment, ctx?: ChatCardContext): { label: string; href?: string; onPress?: () => void | Promise<unknown> } | null | undefined;\n /** What previews call it (the inbox's last message, \"Check-in\"); the title by default. */\n label?: string;\n}\n\ninterface ChatContextValue {\n client: ChatClient;\n userId: string;\n outbox: Outbox;\n queue: QueuedMessage[];\n loadPeople?: (userIds: string[]) => Promise<Record<string, ChatPerson>>;\n videoUpload?: ChatVideoUpload;\n attachmentKinds?: Record<string, ChatAttachmentKind>;\n /** Retries every failed message (call it when the connection comes back: AppState, NetInfo). */\n retryAll(): Promise<void>;\n /** Forgets every unsent message, here and in the outbox store (call it on sign-out). */\n clearOutbox(): Promise<void>;\n /** Subscribe to inbox hints (one channel for the app, fanned out here). */\n onInbox(listener: (s: ChatSignal) => void): () => void;\n}\n\nconst ChatContext = createContext<ChatContextValue | null>(null);\n\nexport interface ChatProviderProps {\n client: ChatClient;\n /** The signed-in user's id (auth.users). */\n userId: string;\n /** Where unsent messages wait between launches (localStorage, MMKV…). Memory by default. */\n outboxStore?: OutboxStore;\n /** Reads a native file URI for upload. */\n readFile?: (uri: string) => Promise<Blob | ArrayBuffer>;\n /**\n * Replaces the plain upload (resumable uploads on native). `signal` aborts when the message is\n * discarded or the outbox cleared; `onProgress(sent, total)` fills the pending bubble's bar.\n */\n upload?: StorageUpload;\n /**\n * Starts a hosted upload for files marked `hosted` (see HostedUpload): resolve with\n * `{ provider, providerId, status: \"pending\", url?, done }` once the upload id exists. Default:\n * `hostedUploadFrom(videoUpload)` when `videoUpload` is given.\n */\n hostedUpload?: HostedUpload;\n /** Makes client ids (default: a random UUID that works without crypto.randomUUID). */\n newId?: () => string;\n /** Keeps a byte file (a pasted image, a recording) across launches: write it, return a URI. */\n persistFile?: (file: LocalFile) => Promise<string>;\n /** Lets go of a sent file's preview (default: revokes `blob:` object URLs only). */\n releasePreview?: (url: string) => void;\n /** Names and avatars for user ids, fetched in batches (usePeople, usePerson). */\n loadPeople?: (userIds: string[]) => Promise<Record<string, ChatPerson>>;\n /** Hosted video uploads (Mux); videos go to storage without it. */\n videoUpload?: ChatVideoUpload;\n /** Cards for your own attachment kinds (`{ form: { title, subtitle, action } }`). */\n attachmentKinds?: Record<string, ChatAttachmentKind>;\n children: ReactNode;\n}\n\n/** How the app shows a person. */\nexport interface ChatPerson {\n name: string;\n avatarUrl?: string | null;\n}\n\n/** Puts chat in reach of every hook below it. Needs a TanStack QueryClientProvider above it. */\nexport function ChatProvider({\n client,\n userId,\n outboxStore,\n readFile,\n upload,\n hostedUpload,\n newId,\n persistFile,\n releasePreview,\n loadPeople,\n videoUpload,\n attachmentKinds,\n children,\n}: ChatProviderProps) {\n const queryClient = useQueryClient();\n const [queue, setQueue] = useState<QueuedMessage[]>([]);\n const listeners = useRef(new Set<(s: ChatSignal) => void>());\n // The outbox lives as long as the client and user, so it reads the app's functions here at call\n // time: an inline `videoUpload.create` closing over a refreshed token keeps working.\n const live = useRef({ readFile, upload, hostedUpload, videoUpload, persistFile });\n live.current = { readFile, upload, hostedUpload, videoUpload, persistFile };\n\n const outbox = useMemo(\n () =>\n createOutbox({\n client,\n userId,\n store: outboxStore,\n readFile: readFile && ((uri) => (live.current.readFile ?? readFile)(uri)),\n upload: upload && ((...args) => (live.current.upload ?? upload)(...args)),\n hostedUpload:\n hostedUpload || videoUpload\n ? (...args) => {\n const now = live.current;\n const video = now.videoUpload ?? videoUpload;\n const send = now.hostedUpload ?? (video ? hostedUploadFrom(video, { readFile: now.readFile ?? readFile }) : hostedUpload!);\n return send(...args);\n }\n : undefined,\n newId,\n persistFile: persistFile && ((file) => (live.current.persistFile ?? persistFile)(file)),\n releasePreview,\n onChange: setQueue,\n onSent: (message) => {\n // Into every loaded list it belongs to (the main timeline, its thread, its topic), so\n // the bubble never disappears between the send landing and the live hint.\n queryClient.setQueriesData<MessagesData>(\n { predicate: (q) => belongsTo(q.queryKey, message) },\n (prev) => upsertInto(prev, [message]) ?? prev,\n );\n void queryClient.invalidateQueries({ queryKey: [\"genesis-chat\", \"scheduled\"] });\n void queryClient.invalidateQueries({ queryKey: [\"genesis-chat\", \"inbox\"] });\n },\n }),\n // A new person or client is a new outbox.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [client, userId],\n );\n\n useEffect(() => {\n // What a relaunch left unsent is retried once (messages waiting for a lost file stay put),\n // and again whenever the browser comes back online.\n void outbox.load().then(() => outbox.retryAll()).catch(() => undefined);\n const online = () => void outbox.retryAll().catch(() => undefined);\n const target = typeof window !== \"undefined\" && typeof window.addEventListener === \"function\" ? window : null;\n target?.addEventListener(\"online\", online);\n const sub = client.subscribeInbox(userId, (signal) => {\n void queryClient.invalidateQueries({ queryKey: [\"genesis-chat\", \"inbox\"] });\n void queryClient.invalidateQueries({ queryKey: chatKeys.unread() });\n for (const l of listeners.current) l(signal);\n });\n return () => {\n sub.unsubscribe();\n target?.removeEventListener(\"online\", online);\n };\n }, [client, userId, outbox, queryClient]);\n\n const value = useMemo<ChatContextValue>(\n () => ({\n client,\n userId,\n outbox,\n queue,\n loadPeople,\n videoUpload,\n attachmentKinds,\n retryAll: () => outbox.retryAll(),\n clearOutbox: () => outbox.clear(),\n onInbox: (l) => {\n listeners.current.add(l);\n return () => listeners.current.delete(l);\n },\n }),\n [client, userId, outbox, queue, loadPeople, videoUpload, attachmentKinds],\n );\n return <ChatContext.Provider value={value}>{children}</ChatContext.Provider>;\n}\n\nexport function useChat(): ChatContextValue {\n const ctx = useContext(ChatContext);\n if (!ctx) throw new Error(\"Chat hooks need a <ChatProvider> above them.\");\n return ctx;\n}\n\n/** Your conversations, live. `kind` narrows to one kind; `archived` shows the archived ones. */\nexport function useInbox(opts: { kind?: string; kinds?: string[]; excludeKinds?: string[]; archived?: boolean; limit?: number } = {}) {\n const { client } = useChat();\n const query = useQuery({ queryKey: chatKeys.inbox(opts), queryFn: () => client.inbox(opts), staleTime: 15_000 });\n return { items: query.data ?? [], isLoading: query.isLoading, error: query.error, refetch: query.refetch };\n}\n\n/** How many messages wait for you everywhere (for a badge), live. */\nexport function useUnreadTotal(opts: { excludeKinds?: string[] } = {}): number {\n const { client } = useChat();\n return (\n useQuery({ queryKey: [...chatKeys.unread(), opts.excludeKinds ?? []], queryFn: () => client.unreadTotal(opts), staleTime: 15_000 }).data ??\n 0\n );\n}\n\nexport interface UseConversationOptions {\n /** Mark messages read as they arrive while this is true (the thread is on screen). Default true. */\n markRead?: boolean;\n /** One thread's replies instead of the main timeline. */\n threadRootId?: string;\n /** One topic's messages. */\n topic?: string;\n pageSize?: number;\n}\n\n/** One conversation: its messages (with what you are still sending), members, your role, and who is typing. */\nexport function useConversation(conversationId: string | null | undefined, opts: UseConversationOptions = {}) {\n const { client, userId, outbox, queue } = useChat();\n const queryClient = useQueryClient();\n const id = conversationId ?? \"\";\n const enabled = Boolean(conversationId);\n const pageSize = opts.pageSize ?? 50;\n const messagesKey = useMemo(\n () => [...chatKeys.conversation(id), \"messages\", opts.threadRootId ?? null, opts.topic ?? null] as const,\n [id, opts.threadRootId, opts.topic],\n );\n\n const conversation = useQuery({ queryKey: chatKeys.conversation(id), queryFn: () => client.conversation(id), enabled });\n const members = useQuery({ queryKey: chatKeys.members(id), queryFn: () => client.members(id), enabled, staleTime: 60_000, refetchOnMount: \"always\" });\n const kindRules = useQuery({\n queryKey: [\"genesis-chat\", \"kind\", conversation.data?.kind ?? \"\"],\n queryFn: () => client.kind(conversation.data!.kind),\n enabled: Boolean(conversation.data?.kind),\n staleTime: 10 * 60_000,\n });\n const access = useQuery({\n queryKey: chatKeys.role(id),\n queryFn: async () => ({ role: await client.myRole(id), canPost: await client.canPost(id) }),\n enabled,\n staleTime: 60_000,\n });\n\n const [loadingEarlier, setLoadingEarlier] = useState(false);\n const fetchPage = useCallback(\n () => client.messages(id, { limit: pageSize, threadRootId: opts.threadRootId, topic: opts.topic }),\n [client, id, pageSize, opts.threadRootId, opts.topic],\n );\n // Kept fresh by live hints and the catch-up on every join, so never refetched on its own.\n const messages = useQuery<MessagesData>({ queryKey: messagesKey, queryFn: fetchPage, enabled, staleTime: Infinity });\n const hasEarlier = messages.data?.hasEarlier ?? false;\n // Where \"New\" goes: what you had read when the conversation opened.\n const [readWhenOpened, setReadWhenOpened] = useState<number | null>(null);\n\n const merge = useCallback(\n (incoming: ChatMessage[], hasEarlierNow?: boolean) =>\n queryClient.setQueryData<MessagesData>(messagesKey, (prev) => {\n const base = prev ?? { messages: [], hasEarlier: false };\n return { messages: upsertMessages(base.messages, incoming), hasEarlier: hasEarlierNow ?? base.hasEarlier };\n }),\n [queryClient, messagesKey],\n );\n\n /**\n * Fetches what came after the newest message held (everything, for an empty list). Runs on\n * every join of the live channel, the first included, so messages that arrived while the\n * thread was closed, or between the first fetch and the subscription, always show. Pages\n * until a short one; after CATCH_UP_MAX_PAGES full pages (a long time away from a busy group)\n * it shows the newest page instead, with the rest behind \"load earlier\".\n */\n const catchUp = useCallback(async () => {\n const current = queryClient.getQueryData<MessagesData>(messagesKey) ?? (await queryClient.ensureQueryData<MessagesData>({ queryKey: messagesKey, queryFn: fetchPage }));\n const list = current.messages;\n let after = list.length ? list[list.length - 1]!.seq : 0;\n for (let pages = 0; ; ) {\n const page = await client.messages(id, { afterSeq: after, limit: CATCH_UP_PAGE, threadRootId: opts.threadRootId, topic: opts.topic });\n if (page.messages.length) merge(page.messages);\n if (page.messages.length < CATCH_UP_PAGE) return;\n after = Math.max(after, ...page.messages.map((m) => m.seq));\n if (++pages >= CATCH_UP_MAX_PAGES) break;\n }\n const newest = await fetchPage();\n queryClient.setQueryData<MessagesData>(messagesKey, { messages: newest.messages, hasEarlier: true });\n }, [client, fetchPage, id, merge, messagesKey, opts.threadRootId, opts.topic, queryClient]);\n\n const [activity, setActivity] = useState<ChatActivity[]>([]);\n const channel = useRef<ConversationChannel | null>(null);\n useEffect(() => {\n if (!enabled) return;\n const fetchOne = async (messageId: string) => {\n const m = await client.message(messageId);\n if (!m) return;\n const belongs = opts.threadRootId ? m.threadRootId === opts.threadRootId : m.threadRootId === null;\n if (belongs && (!opts.topic || m.topic === opts.topic)) merge([m]);\n if (m.threadRootId && !opts.threadRootId) {\n const root = await client.message(m.threadRootId);\n if (root) merge([root]);\n }\n };\n channel.current = client.subscribeConversation(id, userId, {\n onSignal: (s) => {\n if (s.type === \"message\") void fetchOne(s.id);\n else if (s.type === \"reaction\") void fetchOne(s.messageId);\n else if (s.type === \"members\") {\n void queryClient.invalidateQueries({ queryKey: chatKeys.members(id) });\n void queryClient.invalidateQueries({ queryKey: chatKeys.role(id) });\n } else if (s.type === \"conversation\") {\n // The conversation row, its topics and availability (not its messages, kept by hints).\n void queryClient.invalidateQueries({ queryKey: chatKeys.conversation(id), exact: true });\n void queryClient.invalidateQueries({ queryKey: chatKeys.topics(id) });\n void queryClient.invalidateQueries({ queryKey: chatKeys.pins(id) });\n }\n },\n onActivity: (a) => setActivity((prev) => currentActivity([...prev, a])),\n onJoin: () => void catchUp().catch(() => undefined),\n });\n return () => {\n channel.current?.unsubscribe();\n channel.current = null;\n };\n }, [client, enabled, id, userId, merge, catchUp, queryClient, opts.threadRootId, opts.topic]);\n\n // Activity fades after a few seconds without news.\n useEffect(() => {\n if (activity.length === 0) return;\n const t = setTimeout(() => setActivity((prev) => currentActivity(prev)), 2000);\n return () => clearTimeout(t);\n }, [activity]);\n\n const list = useMemo(() => messages.data?.messages ?? [], [messages.data]);\n const latestSeq = list.length ? list[list.length - 1]!.seq : 0;\n // Where \"New\" goes comes from your read place as fetched for this opening, never a cached\n // copy from an earlier visit (which would draw the line above messages already read).\n const myLastRead = members.isFetchedAfterMount ? members.data?.find((m) => m.userId === userId)?.lastReadSeq : undefined;\n useEffect(() => {\n if (readWhenOpened === null && myLastRead !== undefined) setReadWhenOpened(myLastRead);\n }, [myLastRead, readWhenOpened]);\n\n const markRead = useCallback(async () => {\n if (!enabled || latestSeq === 0) return;\n await client.markRead(id, latestSeq);\n void queryClient.invalidateQueries({ queryKey: [\"genesis-chat\", \"inbox\"] });\n void queryClient.invalidateQueries({ queryKey: chatKeys.unread() });\n }, [client, enabled, id, latestSeq, queryClient]);\n\n // Your read place is one number for the whole conversation, so only the whole timeline moves\n // it: a topic (or a thread) shows a slice, and marking up to its newest message would also\n // mark unseen messages in other topics read.\n const shouldMark = opts.markRead !== false && !opts.threadRootId && !opts.topic;\n useEffect(() => {\n if (shouldMark && latestSeq > 0) void markRead().catch(() => undefined);\n }, [shouldMark, latestSeq, markRead]);\n\n const refetchConversation = useCallback(\n () =>\n Promise.all([\n // The conversation and what hangs off it (topics, availability), never its message lists:\n // a refetch would replace loaded history and merged live messages with one fresh page.\n queryClient.refetchQueries({ queryKey: chatKeys.conversation(id), predicate: (q) => q.queryKey[3] !== \"messages\" }),\n queryClient.refetchQueries({ queryKey: chatKeys.members(id) }),\n queryClient.refetchQueries({ queryKey: chatKeys.role(id) }),\n queryClient.refetchQueries({ queryKey: chatKeys.pins(id) }),\n queryClient.refetchQueries({ queryKey: [\"genesis-chat\", \"kind\"] }),\n ]).then(() => undefined),\n [queryClient, id],\n );\n\n const loadEarlier = useCallback(async () => {\n const first = list[0];\n if (!first || loadingEarlier) return;\n setLoadingEarlier(true);\n try {\n const page = await client.messages(id, { beforeSeq: first.seq, limit: pageSize, threadRootId: opts.threadRootId, topic: opts.topic });\n merge(page.messages, page.hasEarlier);\n } finally {\n setLoadingEarlier(false);\n }\n }, [client, id, list, loadingEarlier, merge, opts.threadRootId, opts.topic, pageSize]);\n\n /** Loads earlier messages until the one with this seq is held (a search result, a pinned message). True when it is. */\n const loadUntil = useCallback(\n async (seq: number) => {\n let current = queryClient.getQueryData<MessagesData>(messagesKey);\n for (let guard = 0; guard < 20 && current; guard++) {\n const first = current.messages[0];\n if (!first || first.seq <= seq || !current.hasEarlier) break;\n const page = await client.messages(id, {\n beforeSeq: first.seq,\n limit: Math.min(200, first.seq - seq + 10),\n threadRootId: opts.threadRootId,\n topic: opts.topic,\n });\n merge(page.messages, page.hasEarlier);\n current = queryClient.getQueryData<MessagesData>(messagesKey);\n }\n return Boolean(current?.messages.some((m) => m.seq === seq));\n },\n [client, id, merge, messagesKey, opts.threadRootId, opts.topic, queryClient],\n );\n\n const pending = useMemo(\n () =>\n queue.filter(\n (q) =>\n q.input.conversationId === id &&\n (q.input.threadRootId ?? null) === (opts.threadRootId ?? null) &&\n (!opts.topic || q.input.topic === opts.topic),\n ).map((q) => ({ ...q, files: q.pendingFiles })),\n [queue, id, opts.threadRootId, opts.topic],\n );\n const items: ThreadItem[] = useMemo(() => mergeThread(list, pending), [list, pending]);\n\n const signalTyping = useMemo(() => throttle(() => channel.current?.signal(\"typing\")), []);\n const signalRecording = useMemo(\n () => throttle(() => channel.current?.signal(\"recording-voice\")),\n [],\n );\n const signalRecordingVideo = useMemo(() => throttle(() => channel.current?.signal(\"recording-video\")), []);\n\n /** Sends text and files to this conversation (through the outbox: shown at once, retried safely). */\n const send = useCallback(\n (input: Omit<SendInput, \"conversationId\" | \"clientId\">, files: LocalFile[] = []) =>\n outbox.send({ ...input, conversationId: id, threadRootId: input.threadRootId ?? opts.threadRootId, topic: input.topic ?? opts.topic }, files),\n [outbox, id, opts.threadRootId, opts.topic],\n );\n\n return {\n conversation: conversation.data ?? null,\n members: members.data ?? [],\n role: access.data?.role ?? null,\n canPost: access.data?.canPost ?? false,\n /** Your role and posting rights are still loading: show the composer as waiting, not refused. */\n accessLoading: enabled && access.isLoading,\n /** The conversation itself is still loading (it settles to `null` when you can't see it). */\n conversationLoading: conversation.isLoading,\n /** Your role couldn't be loaded (offline): offer `refetchAccess`, don't say \"can't post\". */\n accessError: access.error ?? null,\n /** Retries everything this conversation loads (role, members, the conversation, topics, availability, pins), not only access. */\n refetchAccess: refetchConversation,\n /** Same as refetchAccess: every per-conversation lookup again, for a Retry after being offline. */\n refetchConversation,\n /** The kind's rules (max members, threads, who posts). */\n kind: kindRules.data ?? null,\n /** May you pin here: owners and admins, or anyone in a two-person conversation. */\n canPin:\n access.data?.role === \"owner\" ||\n access.data?.role === \"admin\" ||\n (access.data?.role === \"member\" && kindRules.data?.maxMembers === 2),\n /** Gives a message whose files were lost on a relaunch its files again. */\n reattach: outbox.reattach,\n items,\n messages: list,\n isLoading: messages.isLoading || conversation.isLoading,\n error: messages.error ?? conversation.error,\n hasEarlier,\n loadingEarlier,\n loadEarlier,\n loadUntil,\n /** Where to draw the \"New\" line, from what you had read when it opened. */\n firstUnreadId: readWhenOpened === null ? null : firstUnreadId(list, readWhenOpened, userId),\n activity: currentActivity(activity),\n signalTyping,\n signalRecording,\n /** Tells the others you are recording a video (throttled). */\n signalRecordingVideo,\n markRead,\n send,\n retry: outbox.retry,\n discard: outbox.discard,\n refetch: catchUp,\n };\n}\n\nexport type ConversationState = ReturnType<typeof useConversation>;\n\n/** Edit, delete, react, pin, save and report, refreshing what they change. */\nexport function useMessageActions() {\n const { client } = useChat();\n const queryClient = useQueryClient();\n return useMemo(() => {\n const refresh = async (conversationId: string, messageId: string) => {\n const m = await client.message(messageId);\n queryClient.setQueriesData<MessagesData>({ queryKey: chatKeys.conversation(conversationId) }, (prev) =>\n m ? (upsertInto(prev, [m]) ?? prev) : prev,\n );\n };\n return {\n edit: async (m: ChatMessage, body: string, mentions: string[] = []) => {\n await client.edit(m.id, body, mentions);\n await refresh(m.conversationId, m.id);\n },\n remove: async (m: ChatMessage) => {\n await client.remove(m.id);\n await refresh(m.conversationId, m.id);\n },\n react: async (m: ChatMessage, emoji: string, on: boolean) => {\n await client.react(m.id, emoji, on);\n await refresh(m.conversationId, m.id);\n },\n pin: async (m: ChatMessage, on: boolean) => {\n await client.pin(m.id, on);\n void queryClient.invalidateQueries({ queryKey: chatKeys.pins(m.conversationId) });\n },\n save: (m: ChatMessage, on: boolean, note?: string) => client.save(m.id, on, note),\n report: (m: ChatMessage, reason: \"spam\" | \"harassment\" | \"safety\" | \"other\", note?: string) => client.report(m.id, reason, note),\n };\n }, [client, queryClient]);\n}\n\n/**\n * Names and avatars for these people, from the provider's `loadPeople`, fetched as one\n * batch per set of ids and cached. Unknown ids are left out.\n */\nexport function usePeople(userIds: (string | null | undefined)[]): Record<string, ChatPerson> {\n const { loadPeople } = useChat();\n const ids = useMemo(() => [...new Set(userIds.filter((x): x is string => Boolean(x)))].sort(), [userIds]);\n return (\n useQuery({\n queryKey: [\"genesis-chat\", \"people\", ids],\n queryFn: () => loadPeople!(ids),\n enabled: Boolean(loadPeople) && ids.length > 0,\n staleTime: 5 * 60_000,\n }).data ?? {}\n );\n}\n\n/** One person's name and avatar (see usePeople). */\nexport function usePerson(userId: string | null | undefined): ChatPerson | null {\n const people = usePeople(useMemo(() => [userId], [userId]));\n return userId ? (people[userId] ?? null) : null;\n}\n\n/** The pinned message ids of a conversation. */\nexport function usePins(conversationId: string | null | undefined): string[] {\n const { client } = useChat();\n return (\n useQuery({ queryKey: chatKeys.pins(conversationId ?? \"\"), queryFn: () => client.pins(conversationId!), enabled: Boolean(conversationId) }).data ?? []\n );\n}\n\n/** Signed links for files (cached by the client until shortly before they expire). */\nexport function useFileUrls(paths: (string | null | undefined)[]): Record<string, string> {\n const { client } = useChat();\n const list = useMemo(() => [...new Set(paths.filter((p): p is string => Boolean(p)))], [paths]);\n return (\n useQuery({ queryKey: chatKeys.files(list), queryFn: () => client.fileUrls(list), enabled: list.length > 0, staleTime: 50 * 60_000 }).data ?? {}\n );\n}\n\n/** Starts (or finds again) a conversation, then refreshes the inbox. */\nexport function useStartConversation() {\n const { client } = useChat();\n const queryClient = useQueryClient();\n return useCallback(\n async (kind: string, memberIds: string[], opts?: { title?: string; subjectType?: string; subjectId?: string }) => {\n const id = await client.startConversation(kind, memberIds, opts);\n void queryClient.invalidateQueries({ queryKey: [\"genesis-chat\", \"inbox\"] });\n return id;\n },\n [client, queryClient],\n );\n}\n\n// ── Migration 0002: topics, scheduled send, availability, broadcast, search, previews ──\n\n/**\n * A conversation's topics, live (set_topic's hint refreshes them), and `setTopic` for owners\n * and admins: add one (`setTopic(\"week-1\", { title: \"Week 1\" })`), close or reopen it.\n */\nexport function useTopics(conversationId: string | null | undefined) {\n const { client } = useChat();\n const queryClient = useQueryClient();\n const id = conversationId ?? \"\";\n const query = useQuery({ queryKey: chatKeys.topics(id), queryFn: () => client.topics(id), enabled: Boolean(conversationId), staleTime: 60_000 });\n const setTopic = useCallback(\n async (topic: string, input: TopicInput = {}) => {\n await client.setTopic(id, topic, input);\n await queryClient.invalidateQueries({ queryKey: chatKeys.topics(id) });\n },\n [client, id, queryClient],\n );\n const topics: ChatTopic[] = query.data ?? [];\n return { topics, isLoading: query.isLoading, error: query.error, setTopic, refetch: query.refetch };\n}\n\n/**\n * Your scheduled messages (in one conversation, or all), soonest first, with `schedule` and\n * `cancel` (which also removes one that failed). `schedule` uploads its files to storage first,\n * the way `send` does (the provider's `upload` hook, or a native URI read through `readFile`),\n * then schedules them with the message. A file marked `hosted` goes to storage too.\n */\nexport function useScheduled(conversationId?: string | null, opts: { enabled?: boolean } = {}) {\n const { client, outbox } = useChat();\n const queryClient = useQueryClient();\n const query = useQuery({\n queryKey: chatKeys.scheduled(conversationId),\n queryFn: () => client.scheduled(conversationId ?? undefined),\n enabled: opts.enabled ?? true,\n staleTime: 30_000,\n });\n const refresh = useCallback(() => queryClient.invalidateQueries({ queryKey: [\"genesis-chat\", \"scheduled\"] }), [queryClient]);\n const schedule = useCallback(\n async (input: Omit<ScheduleInput, \"clientId\"> & { clientId?: string }, files: LocalFile[] = []) => {\n const attachments = [...(input.attachments ?? [])];\n for (const f of files) {\n const path = await outbox.uploadFile(input.conversationId, f);\n attachments.push({ ...f.meta, kind: f.meta?.kind ?? attachmentKindFor(f.contentType), path, name: f.meta?.name ?? f.name, mime: f.contentType });\n }\n const id = await client.schedule({ ...input, clientId: input.clientId ?? randomId(), attachments });\n await refresh();\n return id;\n },\n [client, outbox, refresh],\n );\n const cancel = useCallback(\n async (id: string) => {\n queryClient.setQueriesData<ScheduledMessage[]>({ queryKey: [\"genesis-chat\", \"scheduled\"] }, (prev) => (Array.isArray(prev) ? prev.filter((s) => s.id !== id) : prev));\n try {\n await client.cancelScheduled(id);\n } finally {\n await refresh();\n }\n },\n [client, queryClient, refresh],\n );\n const items: ScheduledMessage[] = query.data ?? [];\n return { items, isLoading: query.isLoading, error: query.error, schedule, cancel, refetch: query.refetch };\n}\n\n/**\n * Availability: yours (`mine`, `setMine`) and, given a conversation, its members' (`members`,\n * `forUser`). Pair with `awayLine` and `isWithinWorkingHours` from the core.\n */\nexport function useAvailability(conversationId?: string | null) {\n const { client, userId } = useChat();\n const queryClient = useQueryClient();\n const mine = useQuery({ queryKey: chatKeys.myAvailability(), queryFn: () => client.myAvailability(), staleTime: 5 * 60_000 });\n const members = useQuery({\n queryKey: chatKeys.availability(conversationId ?? \"\"),\n queryFn: () => client.availabilityFor(conversationId!),\n enabled: Boolean(conversationId),\n staleTime: 5 * 60_000,\n });\n const setMine = useCallback(\n async (input: AvailabilityInput) => {\n await client.setAvailability(input);\n await queryClient.invalidateQueries({ queryKey: chatKeys.myAvailability() });\n await queryClient.invalidateQueries({ predicate: (q) => q.queryKey[0] === \"genesis-chat\" && q.queryKey[3] === \"availability\" });\n },\n [client, queryClient],\n );\n const list: ChatAvailability[] = members.data ?? [];\n const forUser = useCallback((id: string) => list.find((a) => a.userId === id) ?? null, [list]);\n return {\n mine: mine.data ?? null,\n mineLoading: mine.isLoading,\n setMine,\n members: list,\n /** Everyone else's, without yours. */\n others: list.filter((a) => a.userId !== userId),\n forUser,\n isLoading: mine.isLoading || (Boolean(conversationId) && members.isLoading),\n };\n}\n\n/** Sends one message into many conversations (replies come back privately in each). */\nexport function useBroadcast() {\n const { client } = useChat();\n const queryClient = useQueryClient();\n const [sending, setSending] = useState(false);\n const send = useCallback(\n async (conversationIds: string[], body: string, opts: { silent?: boolean; clientId?: string } = {}) => {\n setSending(true);\n try {\n const ids = await client.broadcast(conversationIds, opts.clientId ?? randomId(), body, { silent: opts.silent });\n void queryClient.invalidateQueries({ queryKey: [\"genesis-chat\", \"inbox\"] });\n return ids;\n } finally {\n setSending(false);\n }\n },\n [client, queryClient],\n );\n return { send, sending };\n}\n\n/** The value, once it has stopped changing for `ms`. */\nexport function useDebouncedValue<T>(value: T, ms: number): T {\n const [v, setV] = useState(value);\n useEffect(() => {\n if (ms <= 0) {\n setV(value);\n return;\n }\n const t = setTimeout(() => setV(value), ms);\n return () => clearTimeout(t);\n }, [value, ms]);\n return ms <= 0 ? value : v;\n}\n\n/** Search, debounced (250 ms by default), in one conversation or all of yours. Queries under two characters return nothing. */\nexport function useSearch(query: string, opts: { conversationId?: string | null; debounceMs?: number; limit?: number } = {}) {\n const { client } = useChat();\n const q = useDebouncedValue(query.trim(), opts.debounceMs ?? 250);\n const enabled = q.length >= 2;\n const result = useQuery({\n queryKey: chatKeys.search(q, opts.conversationId),\n queryFn: () => client.search(q, opts.conversationId ?? null, { limit: opts.limit }),\n enabled,\n staleTime: 30_000,\n });\n const hits: ChatSearchHit[] = enabled ? (result.data ?? []) : [];\n return {\n hits,\n /** The query the hits are for. */\n query: q,\n /** Typing, or fetching: results are on their way. */\n isSearching: query.trim() !== q || (enabled && result.isFetching),\n error: result.error,\n };\n}\n\n/** At most this many link-preview reads at once, per client. */\nexport const LINK_PREVIEW_CONCURRENCY = 4;\nconst previewGates = new WeakMap<object, <T>(task: () => Promise<T>) => Promise<T>>();\n\n/** A gate that lets `max` tasks run at once and queues the rest. */\nfunction gate(max: number) {\n let active = 0;\n const waiting: (() => void)[] = [];\n return async <T,>(task: () => Promise<T>): Promise<T> => {\n if (active >= max) await new Promise<void>((r) => waiting.push(r));\n active += 1;\n try {\n return await task();\n } finally {\n active -= 1;\n waiting.shift()?.();\n }\n };\n}\n\n/**\n * Link previews for these messages, by message id, in link order (only those the server has\n * fetched). Pass the messages whose text has links (`extractLinks(body).length > 0`). One query\n * per message, so a new message asks only for its own, and at most LINK_PREVIEW_CONCURRENCY\n * run at once. One with none yet is asked again a few times, since the runner fills them\n * moments after it lands.\n */\nexport function useLinkPreviews(messageIds: (string | null | undefined)[]): Record<string, ChatLinkPreview[]> {\n const { client } = useChat();\n const list = useMemo(() => [...new Set(messageIds.filter((u): u is string => Boolean(u)))].sort(), [messageIds]);\n let run = previewGates.get(client);\n if (!run) {\n run = gate(LINK_PREVIEW_CONCURRENCY);\n previewGates.set(client, run);\n }\n const limited = run;\n const combine = useCallback(\n (results: { data?: ChatLinkPreview[] }[]) => {\n let out: Record<string, ChatLinkPreview[]> | null = null;\n results.forEach((r, i) => {\n if (r.data) (out ??= {})[list[i]!] = r.data;\n });\n return out ?? EMPTY_PREVIEWS;\n },\n [list],\n );\n return useQueries({\n queries: list.map((id) => ({\n queryKey: chatKeys.preview(id),\n queryFn: () => limited(async () => (await client.linkPreviewsFor([id]))[id] ?? []),\n staleTime: 60_000,\n refetchInterval: (q: { state: { data?: ChatLinkPreview[]; dataUpdateCount: number } }) =>\n !q.state.data?.length && q.state.dataUpdateCount < 4 ? 5_000 : false,\n })),\n combine,\n });\n}\nconst EMPTY_PREVIEWS: Record<string, ChatLinkPreview[]> = {};\n\nexport type { ThreadItem, LocalFile, QueuedMessage };\n"]}
|
package/dist/native.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as react from 'react';
|
|
2
|
-
import { ComponentType, ReactNode } from 'react';
|
|
2
|
+
import { ComponentType, ReactNode, ReactElement } from 'react';
|
|
3
3
|
import { InboxPageProps, InboxItem, ScreenHeaderProps } from '@marktiderman/genesis-ui-native/layouts';
|
|
4
4
|
import { m as ChatInboxItem, h as ChatAttachment, q as ChatMessage, k as ChatConversation, t as ChatRole, P as PendingFile, o as ChatLinkPreview, F as SendInput, x as ChatTopic, T as TopicInput, S as ScheduleInput, W as Weekday, C as ChatAvailability, d as AvailabilityInput, p as ChatMember, a as WorkingHours, u as ChatSearchHit } from './client-DUIG1hum.js';
|
|
5
5
|
import { ChatAttachmentKind, ChatCardContext, ChatVideoUpload } from './react.js';
|
|
@@ -216,6 +216,15 @@ interface ChatNativeCopy extends ChatOrganiseCopy {
|
|
|
216
216
|
/** The bubble's VoiceOver action for its link preview. */
|
|
217
217
|
openLinkAction: string;
|
|
218
218
|
attachmentCard: string;
|
|
219
|
+
/** Under an attachment card whose action failed (ticking a task offline). */
|
|
220
|
+
cardActionFailed: string;
|
|
221
|
+
/** Under an attachment card whose action ran too long (`cardActionTimeoutMs`). */
|
|
222
|
+
cardActionTimedOut: string;
|
|
223
|
+
/** A voice note's transcript: still being made, its VoiceOver label, and the toggle for a long one. */
|
|
224
|
+
transcribing: string;
|
|
225
|
+
transcriptLabel: string;
|
|
226
|
+
showMore: string;
|
|
227
|
+
showLess: string;
|
|
219
228
|
openImage: string;
|
|
220
229
|
closeViewer: string;
|
|
221
230
|
photoOf: string;
|
|
@@ -615,10 +624,18 @@ declare function attachmentPreview(body: string, attachment: string | ChatAttach
|
|
|
615
624
|
declare function messagePreview(message: ChatMessage, kinds: Record<string, ChatAttachmentKind> | undefined): string;
|
|
616
625
|
|
|
617
626
|
type OpenAttachment = (attachment: ChatAttachment, message: ChatMessage) => void;
|
|
618
|
-
/**
|
|
627
|
+
/** The kinds the package draws itself; every other kind is the app's. */
|
|
628
|
+
declare const BUILT_IN_KINDS: ReadonlySet<string>;
|
|
629
|
+
/** The app's registered kind for this attachment kind (own keys only, never `constructor` and the like). */
|
|
630
|
+
declare function attachmentKindOf(kinds: Record<string, ChatAttachmentKind> | undefined, kind: string): ChatAttachmentKind | undefined;
|
|
631
|
+
/**
|
|
632
|
+
* A message's attachments split into the app's cards and the rest (photos, voice, video, files).
|
|
633
|
+
* A card is a registered kind; with `slot` (the app draws its kinds) also any kind the package
|
|
634
|
+
* doesn't draw itself, as on the web.
|
|
635
|
+
*/
|
|
619
636
|
declare function splitCardAttachments<T extends {
|
|
620
637
|
kind: string;
|
|
621
|
-
}>(attachments: readonly T[], kinds: Record<string, ChatAttachmentKind> | undefined): {
|
|
638
|
+
}>(attachments: readonly T[], kinds: Record<string, ChatAttachmentKind> | undefined, slot?: boolean): {
|
|
622
639
|
cards: T[];
|
|
623
640
|
rest: T[];
|
|
624
641
|
};
|
|
@@ -633,15 +650,108 @@ declare function cardAction(kind: ChatAttachmentKind | undefined, attachment: Ch
|
|
|
633
650
|
label: string;
|
|
634
651
|
run: () => void;
|
|
635
652
|
} | null;
|
|
653
|
+
/** Where one card's app action stands: running, or failed with a short message. */
|
|
654
|
+
interface CardRunState {
|
|
655
|
+
pending: boolean;
|
|
656
|
+
error: string | null;
|
|
657
|
+
}
|
|
658
|
+
/** How long a card's action may run before it reads as failed (`useCardRuns`, `cardActionTimeoutMs`). */
|
|
659
|
+
declare const CARD_ACTION_TIMEOUT_MS = 30000;
|
|
660
|
+
interface CardRunOptions {
|
|
661
|
+
/** The error once an action threw or rejected (copy `cardActionFailed`). */
|
|
662
|
+
failedText: string;
|
|
663
|
+
/** The error once an action ran longer than `timeoutMs` (copy `cardActionTimedOut`). */
|
|
664
|
+
timedOutText?: string;
|
|
665
|
+
/** Milliseconds before a running action reads as failed; 30 s by default, 0 for never. */
|
|
666
|
+
timeoutMs?: number;
|
|
667
|
+
}
|
|
668
|
+
/**
|
|
669
|
+
* Runs the app's actions for a message's cards (tick a task, answer a check-in) and keeps each
|
|
670
|
+
* card's state by attachment id: `pending` until the action settles, then `error` (the copy's
|
|
671
|
+
* `cardActionFailed`) if it threw or rejected. Only a promise makes a card busy; a second run
|
|
672
|
+
* while one is pending is ignored. One that hasn't settled after `timeoutMs` (30 s) stops being
|
|
673
|
+
* busy and reads as failed (`cardActionTimedOut`); what it settles to later is ignored.
|
|
674
|
+
*/
|
|
675
|
+
declare function useCardRuns(options: CardRunOptions | string): {
|
|
676
|
+
stateOf(id: string): CardRunState;
|
|
677
|
+
run(id: string, task: () => unknown): Promise<void>;
|
|
678
|
+
};
|
|
679
|
+
/**
|
|
680
|
+
* What the `attachment` slot gets: the web slot's props (`attachment`, `message`, `url`, `mine`)
|
|
681
|
+
* and what a native card needs besides. The bubble is one VoiceOver element, so a control drawn
|
|
682
|
+
* here (a checkbox) is reached through the kind's `action`, which the bubble offers as its own
|
|
683
|
+
* action: give the kind one, and call `action.run` from the control so both stay the same.
|
|
684
|
+
*/
|
|
685
|
+
interface ChatAttachmentSlotProps {
|
|
686
|
+
attachment: ChatAttachment;
|
|
687
|
+
message: ChatMessage;
|
|
688
|
+
/**
|
|
689
|
+
* Its signed URL when it has a file (else its `url`), only when it is http(s): the attachment's
|
|
690
|
+
* `url` is whatever the sender put there, so any other scheme (javascript:, file:) is null.
|
|
691
|
+
*/
|
|
692
|
+
url: string | null;
|
|
693
|
+
/** On a message you sent (drawn on the tint). */
|
|
694
|
+
mine: boolean;
|
|
695
|
+
/** The app's kind for it (`ChatProvider attachmentKinds`), when registered. */
|
|
696
|
+
kind: ChatAttachmentKind | undefined;
|
|
697
|
+
/** The kind's `action`, ready to call: it runs through `run`, so `pending` and `error` follow it. Null without one. */
|
|
698
|
+
action: {
|
|
699
|
+
label: string;
|
|
700
|
+
run: () => void;
|
|
701
|
+
} | null;
|
|
702
|
+
/** Runs an app action (tick a task): `pending` until it settles, `error` if it throws or rejects. */
|
|
703
|
+
run(task: () => unknown): void;
|
|
704
|
+
pending: boolean;
|
|
705
|
+
/** A short message once an action failed; cleared by the next run. */
|
|
706
|
+
error: string | null;
|
|
707
|
+
/** The card the package would draw: return it for kinds the slot doesn't draw. */
|
|
708
|
+
fallback: ReactElement;
|
|
709
|
+
testID: string;
|
|
710
|
+
}
|
|
711
|
+
/**
|
|
712
|
+
* Draws the app's own attachment kinds; `null` hides the kinds that aren't registered. A slot that
|
|
713
|
+
* returns null draws nothing for that attachment (a bubble left with nothing is not shown).
|
|
714
|
+
*/
|
|
715
|
+
type ChatAttachmentSlot = ComponentType<ChatAttachmentSlotProps>;
|
|
716
|
+
/** A URL a slot may be given: http or https only, else null. */
|
|
717
|
+
declare function slotUrl(url: string | null | undefined): string | null;
|
|
636
718
|
interface ChatAttachmentCardProps {
|
|
637
719
|
attachment: ChatAttachment;
|
|
638
720
|
message: ChatMessage;
|
|
639
|
-
kind
|
|
721
|
+
/** The app's kind; without one the card shows the attachment's name (or kind) and no button. */
|
|
722
|
+
kind?: ChatAttachmentKind;
|
|
640
723
|
mine?: boolean;
|
|
641
724
|
onOpenAttachment?: OpenAttachment;
|
|
725
|
+
/** Runs the button's action (the bubble passes its own, for busy and error state); calls it straight away by default. */
|
|
726
|
+
run?: (task: () => unknown) => void;
|
|
727
|
+
/** Busy while the action runs; the error under the card once it failed. */
|
|
728
|
+
state?: CardRunState;
|
|
729
|
+
testID?: string;
|
|
730
|
+
}
|
|
731
|
+
declare function ChatAttachmentCard({ attachment, message, kind, mine, onOpenAttachment, run, state, testID }: ChatAttachmentCardProps): react.JSX.Element;
|
|
732
|
+
/** The line under a card whose action failed. */
|
|
733
|
+
declare function CardError({ text, mine, testID }: {
|
|
734
|
+
text: string;
|
|
735
|
+
mine: boolean;
|
|
642
736
|
testID?: string;
|
|
737
|
+
}): react.JSX.Element;
|
|
738
|
+
interface AppAttachmentProps {
|
|
739
|
+
attachment: ChatAttachment;
|
|
740
|
+
message: ChatMessage;
|
|
741
|
+
kind: ChatAttachmentKind | undefined;
|
|
742
|
+
url: string | null;
|
|
743
|
+
mine: boolean;
|
|
744
|
+
/** The app's slot: a component draws it, `null` hides an unregistered kind, undefined draws the card. */
|
|
745
|
+
slot?: ChatAttachmentSlot | null;
|
|
746
|
+
/** Told whether it drew nothing (the slot returned null, or hid the kind), so the bubble can leave it out. */
|
|
747
|
+
onEmpty?: (id: string, empty: boolean) => void;
|
|
748
|
+
onOpenAttachment?: OpenAttachment;
|
|
749
|
+
run: (task: () => unknown) => void;
|
|
750
|
+
state: CardRunState;
|
|
751
|
+
testID: string;
|
|
643
752
|
}
|
|
644
|
-
|
|
753
|
+
/** One app attachment in a bubble: through the app's slot when there is one, else the card. */
|
|
754
|
+
declare function AppAttachment({ attachment, message, kind, url, mine, slot, onOpenAttachment, onEmpty, run, state, testID }: AppAttachmentProps): react.JSX.Element | null;
|
|
645
755
|
|
|
646
756
|
/**
|
|
647
757
|
* @feat:chat
|
|
@@ -745,6 +855,14 @@ interface ChatThreadScreenProps {
|
|
|
745
855
|
availability?: boolean;
|
|
746
856
|
/** An app attachment card's button (a form, a check-in), when its kind gives no `onPress`. */
|
|
747
857
|
onOpenAttachment?: OpenAttachment;
|
|
858
|
+
/**
|
|
859
|
+
* Swap parts, as the web `ChatThread` does. `attachment` draws the app's own attachment kinds
|
|
860
|
+
* (a task with a checkbox): every kind the package doesn't draw, with `fallback` for the card it
|
|
861
|
+
* would have been; `null` hides kinds that aren't registered. Define it at module scope.
|
|
862
|
+
*/
|
|
863
|
+
slots?: ChatThreadScreenSlots;
|
|
864
|
+
/** How long an app card's action may run before it reads as failed; 30 s by default, 0 for never. */
|
|
865
|
+
cardActionTimeoutMs?: number;
|
|
748
866
|
/**
|
|
749
867
|
* Whether the screen is the one shown (the navigator's `useIsFocused()`). When it turns false a
|
|
750
868
|
* video or voice note of this thread that is playing pauses: switching tab keeps the screen
|
|
@@ -753,6 +871,10 @@ interface ChatThreadScreenProps {
|
|
|
753
871
|
focused?: boolean;
|
|
754
872
|
testID?: string;
|
|
755
873
|
}
|
|
874
|
+
interface ChatThreadScreenSlots {
|
|
875
|
+
/** Draws the app's own attachment kinds; the card by default. */
|
|
876
|
+
attachment?: ChatAttachmentSlot | null;
|
|
877
|
+
}
|
|
756
878
|
/** Points from the bottom that still count as "at the bottom" (FlatList, which follows by hand). */
|
|
757
879
|
declare const AT_BOTTOM_POINTS = 120;
|
|
758
880
|
/**
|
|
@@ -1015,6 +1137,14 @@ interface MessageBubbleProps {
|
|
|
1015
1137
|
attachmentKinds?: Record<string, ChatAttachmentKind>;
|
|
1016
1138
|
/** A card's button, when its kind gives no `onPress` of its own. */
|
|
1017
1139
|
onOpenAttachment?: OpenAttachment;
|
|
1140
|
+
/**
|
|
1141
|
+
* Draws the app's own attachment kinds (a task with a checkbox, a worksheet with its progress)
|
|
1142
|
+
* instead of the card: every kind the package doesn't draw, registered or not. `null` hides the
|
|
1143
|
+
* kinds that aren't registered. Define it at module scope (or memoize it) so rows stay memoized.
|
|
1144
|
+
*/
|
|
1145
|
+
attachmentSlot?: ChatAttachmentSlot | null;
|
|
1146
|
+
/** How long an app card's action may run before it reads as failed; 30 s by default, 0 for never. */
|
|
1147
|
+
cardActionTimeoutMs?: number;
|
|
1018
1148
|
testID: string;
|
|
1019
1149
|
}
|
|
1020
1150
|
declare function formatClock(iso: string): string;
|
|
@@ -1117,6 +1247,9 @@ interface BubbleAttachment {
|
|
|
1117
1247
|
posterUri?: string | null;
|
|
1118
1248
|
/** Still on its way from this phone. */
|
|
1119
1249
|
uploading?: boolean;
|
|
1250
|
+
/** A voice note's (or video's) transcript, and whether one is still being made. */
|
|
1251
|
+
transcript?: string | null;
|
|
1252
|
+
transcriptStatus?: ChatAttachment["transcriptStatus"];
|
|
1120
1253
|
}
|
|
1121
1254
|
/** The paths a set of messages needs signed links for. */
|
|
1122
1255
|
declare function attachmentPaths(attachments: readonly ChatAttachment[]): string[];
|
|
@@ -1127,6 +1260,25 @@ interface AttachmentsProps {
|
|
|
1127
1260
|
testID: string;
|
|
1128
1261
|
}
|
|
1129
1262
|
declare function MessageAttachments({ attachments, mine, onOpenImage, testID }: AttachmentsProps): react.JSX.Element;
|
|
1263
|
+
/** Lines a transcript shows before "Show more". */
|
|
1264
|
+
declare const TRANSCRIPT_LINES = 3;
|
|
1265
|
+
/**
|
|
1266
|
+
* Whether a transcript folds behind "Show more": by its laid-out line count once measured. Before
|
|
1267
|
+
* any layout (unit tests, where nothing is laid out) a rough guess from its length stands in.
|
|
1268
|
+
*/
|
|
1269
|
+
declare function transcriptIsLong(text: string, measuredLines?: number | null): boolean;
|
|
1270
|
+
interface VoiceTranscriptProps {
|
|
1271
|
+
transcript: string | null | undefined;
|
|
1272
|
+
status: ChatAttachment["transcriptStatus"] | undefined;
|
|
1273
|
+
mine: boolean;
|
|
1274
|
+
testID: string;
|
|
1275
|
+
}
|
|
1276
|
+
/**
|
|
1277
|
+
* A voice note's transcript under the player: "Transcribing…" while it is made, then the text,
|
|
1278
|
+
* folded to three lines with "Show more" when it is longer. The bubble reads the whole transcript
|
|
1279
|
+
* to VoiceOver, so the toggle is for sight only.
|
|
1280
|
+
*/
|
|
1281
|
+
declare function VoiceTranscript({ transcript, status, mine, testID }: VoiceTranscriptProps): react.JSX.Element | null;
|
|
1130
1282
|
|
|
1131
1283
|
interface ChatPhoto {
|
|
1132
1284
|
key: string;
|
|
@@ -1937,4 +2089,4 @@ declare function ModerationMarker({ note, mine, testID }: {
|
|
|
1937
2089
|
testID?: string;
|
|
1938
2090
|
}): react.JSX.Element;
|
|
1939
2091
|
|
|
1940
|
-
export { AT_BOTTOM_POINTS, type AppStateLike, type AudioPlayerLike, type AudioRecorderLike, type AudioStatusLike, type AvailabilityForm, type BubbleAttachment, type BuildRowsOptions, type ByteSource, type CameraViewHandleLike, ChatAccessError, type ChatAccessErrorProps, ChatAttachmentCard, type ChatAttachmentCardProps, ChatAutoRetry, type ChatAutoRetryOptions, ChatAvailabilityScreen, type ChatAvailabilityScreenProps, ChatAwayLine, type ChatAwayLineProps, ChatBroadcastSheet, type ChatBroadcastSheetProps, ChatCardContext, ChatComposer, type ChatComposerHandle, type ChatComposerProps, ChatEmojiPicker, type ChatEmojiPickerProps, ChatEmojiPickerSheet, type ChatEmojiPickerSheetProps, ChatIconButton, type ChatIconButtonProps, ChatInboxScreen, type ChatInboxScreenProps, ChatLinkPreviewCard, type ChatLinkPreviewCardProps, ChatMediaViewer, type ChatMediaViewerProps, type ChatNativeContextValue, type ChatNativeCopy, type ChatNativeCopyOverrides, type ChatNativeModules, ChatNativeProvider, type ChatNativeProviderProps, type ChatOrganiseCopy, type ChatPerson, type ChatPhoto, ChatPhotoViewer, type ChatPhotoViewerProps, ChatScheduleSheet, type ChatScheduleSheetProps, ChatScheduledBar, type ChatScheduledBarProps, ChatScheduledList, type ChatScheduledListProps, ChatSearchScreen, type ChatSearchScreenProps, ChatStartButton, type ChatStartPerson, ChatStartSheet, type ChatStartSheetProps, ChatThreadScreen, type ChatThreadScreenProps, type ChatThreadStackOptionsProps, ChatTopicBar, type ChatTopicBarProps, ChatVideoPlayer, type ChatVideoPlayerProps, ChatVideoRecorder, type ChatVideoRecorderProps, type ChatVideoState, type ChunkFileLike, type ChunkedPutOptions, type ClipboardLike, type ComposerAction, type ComposerAttachment, type ComposerDraft, type ComposerState, DISMISS_DISTANCE, DISMISS_VELOCITY, type DayHours, type DraftStorageLike, EMOJI_CATEGORIES, type EmojiCategoryId, type EmojiEntry, type ExpoAudioLike, type ExpoCameraLike, type ExpoVideoLike, type HapticEvent, type HapticsLike, type ImagePickerLike, type JumpTarget, type KeyboardAvoidingLike, MAX_ZOOM, type MediaLibraryLike, type MessageActionContext, type MessageActionId, MessageActionsSheet, type MessageActionsSheetProps, MessageAttachments, MessageBubble, type MessageBubbleProps, type MintedUpload, ModerationMarker, type ModerationNote, type NetInfoLike, type OpenAttachment, type OutboxSend, type PermissionLike, type PickedAssetLike, type PickerResultLike, QUICK_REACTIONS, RECENT_EMOJI_MAX, type RecordedVideo, type RecorderConfig, type RecorderEffect, type RecorderEvent, type RecorderNotice, type RecorderPhase, type RecorderState, type RecorderStateLike, type ReplyTarget, SearchSnippet, type SharingLike, type StartVideoInput, TUS_CHUNK_BYTES, type ThreadRow, type TopicMenuAction, type TusUploadOptions, type UseJumpOptions, type UseVoiceRecorderOptions, VIDEO_CHUNK_BYTES, VIDEO_HOLD_MS, VIDEO_MIN_MS, type VideoPlayerLike, type VideoRecorderEffect, type VideoRecorderEvent, type VideoRecorderPhase, type VideoRecorderState, type VideoUploadError, type VideoUploadTask, VideoUploadTray, type VideoUploadTrayProps, type VideoUploads, type VideoViewHandleLike, VoiceNotePlayer, type VoiceNotePlayerProps, type WebBrowserLike, type WeekHours, activePlaybackId, attachmentPaths, attachmentPreview, availabilityInput, awayLineFor, barsThatFit, base64ToBytes, base64Utf8, broadcastOutcome, broadcastRows, buildThreadRows, canManageTopics, canReactTo, canSend, cardAction, cardTitle, chatNativeCopy, chatOrganiseCopy, chatThreadStackOptions, checkTopicName, chunkedPut, claimPlayback, clearDrafts, clockToDate, composerDisabledReason, composerReducer, createDraftSaver, createTusUpload, createVideoUploads, cycleVideoRate, cycleVoiceNoteRate, dateToClock, defaultScheduleAt, defaultWeek, deviceTimeZone, displayBody, draftKey, emojiEntry, emojiInCategory, emptyComposer, fileFromDataUri, fileSource, filesFromAssets, fill, forgetRecentEmoji, formFrom, formatClock, fullScreenVideo, galleryFor, haptic, hoursFromWeek, idleRecorder, inboxRow, initialVideoRecorder, initials, insertAtSelection, invertedRows, isLocalUri, isOnline, isOpenableHref, isVideoPlaying, linkHost, linkPreviewIds, liveBars, loadDraft, loadRecentEmoji, memoryDraftStorage, messageActionsFor, messagePreview, moderationNote, moderationText, muxPosterUrl, muxStreamUrl, nearBottom, nextOffset, openChatLink, panLimit, pauseChatPlayback, pinchScale, previewToShow, pushRecentEmoji, recentEmojiKey, recordedVideoFile, recorderStep, recordingType, releasePlayback, replyTargetFor, resolveChatCopy, rowIndexOf, rowKey, sameTimeDays, saveRecentEmoji, scheduleInputFrom, scrubSeconds, searchEmoji, shouldDismiss, snippetText, splitCardAttachments, threadListMode, timeZones, toSend, toggleVideo, toggleVideoMute, toggleVoiceNote, topicClosedFor, topicMenuFor, useAwayLine, useChatAutoRetry, useChatComposer, useChatNative, useChatThreadStackOptions, useJumpToMessage, usePlayingVideo, usePlayingVoiceNote, useScheduleSend, useVideoUploads, useVoiceRecorder, videoRecorderStep, videoSource, videoState, videoUploads, voiceNoteFile, waveformBars, weekFromHours, withDay, withTime };
|
|
2092
|
+
export { AT_BOTTOM_POINTS, AppAttachment, type AppAttachmentProps, type AppStateLike, type AudioPlayerLike, type AudioRecorderLike, type AudioStatusLike, type AvailabilityForm, BUILT_IN_KINDS, type BubbleAttachment, type BuildRowsOptions, type ByteSource, CARD_ACTION_TIMEOUT_MS, type CameraViewHandleLike, CardError, type CardRunOptions, type CardRunState, ChatAccessError, type ChatAccessErrorProps, ChatAttachmentCard, type ChatAttachmentCardProps, type ChatAttachmentSlot, type ChatAttachmentSlotProps, ChatAutoRetry, type ChatAutoRetryOptions, ChatAvailabilityScreen, type ChatAvailabilityScreenProps, ChatAwayLine, type ChatAwayLineProps, ChatBroadcastSheet, type ChatBroadcastSheetProps, ChatCardContext, ChatComposer, type ChatComposerHandle, type ChatComposerProps, ChatEmojiPicker, type ChatEmojiPickerProps, ChatEmojiPickerSheet, type ChatEmojiPickerSheetProps, ChatIconButton, type ChatIconButtonProps, ChatInboxScreen, type ChatInboxScreenProps, ChatLinkPreviewCard, type ChatLinkPreviewCardProps, ChatMediaViewer, type ChatMediaViewerProps, type ChatNativeContextValue, type ChatNativeCopy, type ChatNativeCopyOverrides, type ChatNativeModules, ChatNativeProvider, type ChatNativeProviderProps, type ChatOrganiseCopy, type ChatPerson, type ChatPhoto, ChatPhotoViewer, type ChatPhotoViewerProps, ChatScheduleSheet, type ChatScheduleSheetProps, ChatScheduledBar, type ChatScheduledBarProps, ChatScheduledList, type ChatScheduledListProps, ChatSearchScreen, type ChatSearchScreenProps, ChatStartButton, type ChatStartPerson, ChatStartSheet, type ChatStartSheetProps, ChatThreadScreen, type ChatThreadScreenProps, type ChatThreadScreenSlots, type ChatThreadStackOptionsProps, ChatTopicBar, type ChatTopicBarProps, ChatVideoPlayer, type ChatVideoPlayerProps, ChatVideoRecorder, type ChatVideoRecorderProps, type ChatVideoState, type ChunkFileLike, type ChunkedPutOptions, type ClipboardLike, type ComposerAction, type ComposerAttachment, type ComposerDraft, type ComposerState, DISMISS_DISTANCE, DISMISS_VELOCITY, type DayHours, type DraftStorageLike, EMOJI_CATEGORIES, type EmojiCategoryId, type EmojiEntry, type ExpoAudioLike, type ExpoCameraLike, type ExpoVideoLike, type HapticEvent, type HapticsLike, type ImagePickerLike, type JumpTarget, type KeyboardAvoidingLike, MAX_ZOOM, type MediaLibraryLike, type MessageActionContext, type MessageActionId, MessageActionsSheet, type MessageActionsSheetProps, MessageAttachments, MessageBubble, type MessageBubbleProps, type MintedUpload, ModerationMarker, type ModerationNote, type NetInfoLike, type OpenAttachment, type OutboxSend, type PermissionLike, type PickedAssetLike, type PickerResultLike, QUICK_REACTIONS, RECENT_EMOJI_MAX, type RecordedVideo, type RecorderConfig, type RecorderEffect, type RecorderEvent, type RecorderNotice, type RecorderPhase, type RecorderState, type RecorderStateLike, type ReplyTarget, SearchSnippet, type SharingLike, type StartVideoInput, TRANSCRIPT_LINES, TUS_CHUNK_BYTES, type ThreadRow, type TopicMenuAction, type TusUploadOptions, type UseJumpOptions, type UseVoiceRecorderOptions, VIDEO_CHUNK_BYTES, VIDEO_HOLD_MS, VIDEO_MIN_MS, type VideoPlayerLike, type VideoRecorderEffect, type VideoRecorderEvent, type VideoRecorderPhase, type VideoRecorderState, type VideoUploadError, type VideoUploadTask, VideoUploadTray, type VideoUploadTrayProps, type VideoUploads, type VideoViewHandleLike, VoiceNotePlayer, type VoiceNotePlayerProps, VoiceTranscript, type VoiceTranscriptProps, type WebBrowserLike, type WeekHours, activePlaybackId, attachmentKindOf, attachmentPaths, attachmentPreview, availabilityInput, awayLineFor, barsThatFit, base64ToBytes, base64Utf8, broadcastOutcome, broadcastRows, buildThreadRows, canManageTopics, canReactTo, canSend, cardAction, cardTitle, chatNativeCopy, chatOrganiseCopy, chatThreadStackOptions, checkTopicName, chunkedPut, claimPlayback, clearDrafts, clockToDate, composerDisabledReason, composerReducer, createDraftSaver, createTusUpload, createVideoUploads, cycleVideoRate, cycleVoiceNoteRate, dateToClock, defaultScheduleAt, defaultWeek, deviceTimeZone, displayBody, draftKey, emojiEntry, emojiInCategory, emptyComposer, fileFromDataUri, fileSource, filesFromAssets, fill, forgetRecentEmoji, formFrom, formatClock, fullScreenVideo, galleryFor, haptic, hoursFromWeek, idleRecorder, inboxRow, initialVideoRecorder, initials, insertAtSelection, invertedRows, isLocalUri, isOnline, isOpenableHref, isVideoPlaying, linkHost, linkPreviewIds, liveBars, loadDraft, loadRecentEmoji, memoryDraftStorage, messageActionsFor, messagePreview, moderationNote, moderationText, muxPosterUrl, muxStreamUrl, nearBottom, nextOffset, openChatLink, panLimit, pauseChatPlayback, pinchScale, previewToShow, pushRecentEmoji, recentEmojiKey, recordedVideoFile, recorderStep, recordingType, releasePlayback, replyTargetFor, resolveChatCopy, rowIndexOf, rowKey, sameTimeDays, saveRecentEmoji, scheduleInputFrom, scrubSeconds, searchEmoji, shouldDismiss, slotUrl, snippetText, splitCardAttachments, threadListMode, timeZones, toSend, toggleVideo, toggleVideoMute, toggleVoiceNote, topicClosedFor, topicMenuFor, transcriptIsLong, useAwayLine, useCardRuns, useChatAutoRetry, useChatComposer, useChatNative, useChatThreadStackOptions, useJumpToMessage, usePlayingVideo, usePlayingVoiceNote, useScheduleSend, useVideoUploads, useVoiceRecorder, videoRecorderStep, videoSource, videoState, videoUploads, voiceNoteFile, waveformBars, weekFromHours, withDay, withTime };
|