@marktiderman/genesis-chat 0.2.0 → 0.2.1
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 +82 -7
- package/dist/{chunk-5D5A7I4Q.js → chunk-A4YJX7KT.js} +130 -16
- package/dist/chunk-A4YJX7KT.js.map +1 -0
- package/dist/chunk-AZS3HNLM.js +30 -0
- package/dist/chunk-AZS3HNLM.js.map +1 -0
- package/dist/{chunk-7S6HYNWW.js → chunk-GBJ3YI4E.js} +72 -5
- package/dist/chunk-GBJ3YI4E.js.map +1 -0
- package/dist/{chunk-PZTOY2LY.js → chunk-JU2FAPBI.js} +46 -13
- package/dist/chunk-JU2FAPBI.js.map +1 -0
- package/dist/{client-DMa2j7kz.d.ts → client-DUIG1hum.d.ts} +36 -1
- package/dist/index.d.ts +4 -4
- package/dist/index.js +2 -2
- package/dist/native.d.ts +36 -7
- package/dist/native.js +239 -116
- package/dist/native.js.map +1 -1
- package/dist/{outbox-B0y3phE0.d.ts → outbox-B9NAWQ58.d.ts} +74 -6
- package/dist/push.d.ts +2 -2
- package/dist/react.d.ts +48 -21
- package/dist/react.js +3 -3
- package/dist/server.d.ts +43 -2
- package/dist/server.js +115 -15
- package/dist/server.js.map +1 -1
- package/dist/{thread-DWXHKPdw.d.ts → thread-oPra7pkW.d.ts} +1 -1
- package/dist/web.d.ts +31 -11
- package/dist/web.js +97 -48
- package/dist/web.js.map +1 -1
- package/migrations/0003_genesis_chat_search_threads.sql +85 -0
- package/migrations/tests/0002_genesis_chat_coaching.test.sql +7 -3
- package/migrations/tests/0003_genesis_chat_search_threads.test.sql +50 -0
- package/package.json +7 -3
- package/src/__tests__/coaching-core.test.ts +3 -1
- package/src/__tests__/coaching-react.test.tsx +73 -2
- package/src/__tests__/coaching-web.test.tsx +78 -6
- package/src/__tests__/fake-xhr.ts +54 -0
- package/src/__tests__/outbox-hosted.test.ts +269 -0
- package/src/__tests__/review-279.test.ts +41 -0
- package/src/__tests__/review-fixes-web.test.tsx +13 -10
- package/src/__tests__/server-fake-video.test.ts +81 -0
- package/src/__tests__/server-fakes.ts +7 -1
- package/src/__tests__/server-safety.test.ts +17 -4
- package/src/__tests__/web.test.tsx +16 -0
- package/src/core/client.ts +28 -2
- package/src/core/outbox.ts +222 -16
- package/src/core/transfer.ts +71 -0
- package/src/core/types.ts +17 -0
- package/src/index.ts +1 -0
- package/src/native/__tests__/emoji.test.tsx +16 -0
- package/src/native/__tests__/organise-screens.test.tsx +80 -0
- package/src/native/__tests__/video-media.test.tsx +81 -4
- package/src/native/attachment-cards.tsx +22 -6
- package/src/native/inbox-screen.tsx +12 -6
- package/src/native/index.ts +2 -2
- package/src/native/message-actions-sheet.tsx +10 -5
- package/src/native/message-bubble.tsx +3 -11
- package/src/native/modules.ts +2 -0
- package/src/native/schedule-sheet.tsx +23 -9
- package/src/native/search-screen.tsx +26 -5
- package/src/native/thread-screen.tsx +30 -3
- package/src/native/topics.tsx +70 -15
- package/src/native/video-player.tsx +46 -6
- package/src/native/video-recorder.tsx +6 -3
- package/src/native/voice-player.tsx +18 -0
- package/src/react/index.tsx +103 -19
- package/src/react/previews.ts +51 -0
- package/src/server/fake-video.ts +171 -0
- package/src/server/index.ts +1 -0
- package/src/web/attachments.tsx +6 -6
- package/src/web/bubble.tsx +22 -0
- package/src/web/inbox.tsx +7 -6
- package/src/web/memory-client.ts +11 -3
- package/src/web/panel.tsx +2 -2
- package/src/web/schedule.tsx +14 -2
- package/src/web/thread.tsx +36 -8
- package/src/web/video.tsx +28 -34
- package/dist/chunk-5D5A7I4Q.js.map +0 -1
- package/dist/chunk-7S6HYNWW.js.map +0 -1
- package/dist/chunk-PZTOY2LY.js.map +0 -1
|
@@ -0,0 +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"]}
|
|
@@ -193,6 +193,20 @@ interface PendingFile {
|
|
|
193
193
|
meta?: Partial<AttachmentInput>;
|
|
194
194
|
/** Not kept between launches (bytes with nowhere to save them): attach it again. */
|
|
195
195
|
lost?: boolean;
|
|
196
|
+
/** How much of it has uploaded, 0 to 1, once the upload reports progress. */
|
|
197
|
+
progress?: number;
|
|
198
|
+
/** Going to the hosted video provider (Mux, Cloudflare) rather than storage. */
|
|
199
|
+
hosted?: boolean;
|
|
200
|
+
}
|
|
201
|
+
/**
|
|
202
|
+
* A hosted video upload that has started: the provider's upload id, sent with the message as
|
|
203
|
+
* `{ provider, providerId, status: "pending" }` while the bytes still go up. The provider's
|
|
204
|
+
* webhook marks the attachment ready.
|
|
205
|
+
*/
|
|
206
|
+
interface HostedAttachment {
|
|
207
|
+
provider: "mux" | "cloudflare";
|
|
208
|
+
providerId: string;
|
|
209
|
+
status: "pending";
|
|
196
210
|
}
|
|
197
211
|
/** A live hint from Realtime: something changed; fetch to see what. */
|
|
198
212
|
type ChatSignal = {
|
|
@@ -287,6 +301,8 @@ interface ChatSearchHit {
|
|
|
287
301
|
snippet: string;
|
|
288
302
|
/** Found in a voice note's or video's transcript, not the text. */
|
|
289
303
|
inTranscript: boolean;
|
|
304
|
+
/** The thread the message is a reply in (open that thread to show it); null on the main timeline. */
|
|
305
|
+
threadRootId: string | null;
|
|
290
306
|
}
|
|
291
307
|
/** Open Graph data for a link (fetched by the server's runner). Plain text: never render it as HTML. */
|
|
292
308
|
interface ChatLinkPreview {
|
|
@@ -300,6 +316,18 @@ interface ChatLinkPreview {
|
|
|
300
316
|
fetchedAt: string;
|
|
301
317
|
}
|
|
302
318
|
|
|
319
|
+
type UploadProgress = (sent: number, total: number) => void;
|
|
320
|
+
interface SendBytesOptions {
|
|
321
|
+
method?: "PUT" | "POST";
|
|
322
|
+
headers?: Record<string, string>;
|
|
323
|
+
signal?: AbortSignal;
|
|
324
|
+
onProgress?: UploadProgress;
|
|
325
|
+
/** For tests and runtimes without XMLHttpRequest. */
|
|
326
|
+
fetch?: typeof fetch;
|
|
327
|
+
}
|
|
328
|
+
/** Sends `body` to `url`; resolves with the response text, throws a ChatError on a non-2xx answer. */
|
|
329
|
+
declare function sendBytes(url: string, body: Blob | ArrayBuffer, opts?: SendBytesOptions): Promise<string>;
|
|
330
|
+
|
|
303
331
|
/**
|
|
304
332
|
* @feat:chat
|
|
305
333
|
* The chat client: the app's own Supabase (migrations 0001 and 0002, the genesis_chat
|
|
@@ -467,11 +495,18 @@ declare function createChatClient(supabase: ChatSupabase, options?: ChatClientOp
|
|
|
467
495
|
* Uploads a file into the conversation's folder for the signed-in person and
|
|
468
496
|
* returns its path, ready to attach. Resumable for big files is the native
|
|
469
497
|
* renderer's job (Supabase TUS); this is the plain upload.
|
|
498
|
+
*
|
|
499
|
+
* With `onProgress(sent, total)`, where XMLHttpRequest exists (browsers, React Native), the
|
|
500
|
+
* bytes go to a signed upload URL (`createSignedUploadUrl`, which checks the same storage
|
|
501
|
+
* policy as a plain upload) through XMLHttpRequest, which reports progress; elsewhere the
|
|
502
|
+
* plain upload runs and reports once, at the end. `signal` cancels it.
|
|
470
503
|
*/
|
|
471
504
|
upload(conversationId: string, userId: string, file: Blob | ArrayBuffer, opts: {
|
|
472
505
|
name: string;
|
|
473
506
|
contentType: string;
|
|
474
507
|
id?: string;
|
|
508
|
+
onProgress?: UploadProgress;
|
|
509
|
+
signal?: AbortSignal;
|
|
475
510
|
}): Promise<string>;
|
|
476
511
|
/** Signed links for files, cached until shortly before they expire. */
|
|
477
512
|
fileUrls(paths: string[]): Promise<Record<string, string>>;
|
|
@@ -487,4 +522,4 @@ declare function createChatClient(supabase: ChatSupabase, options?: ChatClientOp
|
|
|
487
522
|
};
|
|
488
523
|
type ChatClient = ReturnType<typeof createChatClient>;
|
|
489
524
|
|
|
490
|
-
export { type AttachmentInput as A, type PendingMessage as B, type ChatAvailability as C, type ScheduledMessage as D, type
|
|
525
|
+
export { type AttachmentInput as A, type PendingMessage as B, type ChatAvailability as C, type ScheduledMessage as D, type SendBytesOptions as E, type SendInput as F, type Subscription as G, type HostedAttachment as H, conversationTopic as I, createChatClient as J, sendBytes as K, toAttachment as L, type MessagePage as M, toAvailability as N, toLinkPreview as O, type PendingFile as P, toMessage as Q, toScheduled as R, type ScheduleInput as S, type TopicInput as T, type UploadProgress as U, toSearchHit as V, type Weekday as W, toTopic as X, userTopic as Y, type WorkingHours as a, type AttachmentKind as b, type AttachmentProvider as c, type AvailabilityInput as d, CHAT_BUCKET as e, CHAT_SCHEMA as f, type ChatActivity as g, type ChatAttachment as h, type ChatClient as i, type ChatClientOptions as j, type ChatConversation as k, ChatError as l, type ChatInboxItem as m, type ChatKindRules as n, type ChatLinkPreview as o, type ChatMember as p, type ChatMessage as q, type ChatPreview as r, type ChatReaction as s, type ChatRole as t, type ChatSearchHit as u, type ChatSignal as v, type ChatSupabase as w, type ChatTopic as x, type ConversationChannel as y, type ConversationHandlers as z };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { W as Weekday, C as ChatAvailability, a as WorkingHours } from './client-
|
|
2
|
-
export { A as AttachmentInput, b as AttachmentKind, c as AttachmentProvider, d as AvailabilityInput, e as CHAT_BUCKET, f as CHAT_SCHEMA, g as ChatActivity, h as ChatAttachment, i as ChatClient, j as ChatClientOptions, k as ChatConversation, l as ChatError, m as ChatInboxItem, n as ChatKindRules, o as ChatLinkPreview, p as ChatMember, q as ChatMessage, r as ChatPreview, s as ChatReaction, t as ChatRole, u as ChatSearchHit, v as ChatSignal, w as ChatSupabase, x as ChatTopic, y as ConversationChannel, z as ConversationHandlers, M as MessagePage, P as PendingFile, B as PendingMessage, S as ScheduleInput, D as ScheduledMessage, E as
|
|
3
|
-
export { A as ALLOWED_EXTENSIONS, C as CHAT_LIMITS, L as LocalFile, O as Outbox,
|
|
4
|
-
export { R as ReactionSummary, T as ThreadItem, a as activityLine, c as currentActivity, d as dayLabel, f as firstUnreadId, i as itemSender, b as itemTime, m as mergeThread, p as parseMentions, e as previewText, s as sameDay, g as startsDay, h as startsGroup, j as summarizeReactions, t as throttle, u as upsertMessages } from './thread-
|
|
1
|
+
import { W as Weekday, C as ChatAvailability, a as WorkingHours } from './client-DUIG1hum.js';
|
|
2
|
+
export { A as AttachmentInput, b as AttachmentKind, c as AttachmentProvider, d as AvailabilityInput, e as CHAT_BUCKET, f as CHAT_SCHEMA, g as ChatActivity, h as ChatAttachment, i as ChatClient, j as ChatClientOptions, k as ChatConversation, l as ChatError, m as ChatInboxItem, n as ChatKindRules, o as ChatLinkPreview, p as ChatMember, q as ChatMessage, r as ChatPreview, s as ChatReaction, t as ChatRole, u as ChatSearchHit, v as ChatSignal, w as ChatSupabase, x as ChatTopic, y as ConversationChannel, z as ConversationHandlers, H as HostedAttachment, M as MessagePage, P as PendingFile, B as PendingMessage, S as ScheduleInput, D as ScheduledMessage, E as SendBytesOptions, F as SendInput, G as Subscription, T as TopicInput, U as UploadProgress, I as conversationTopic, J as createChatClient, K as sendBytes, L as toAttachment, N as toAvailability, O as toLinkPreview, Q as toMessage, R as toScheduled, V as toSearchHit, X as toTopic, Y as userTopic } from './client-DUIG1hum.js';
|
|
3
|
+
export { A as ALLOWED_EXTENSIONS, C as CHAT_LIMITS, H as HostedUpload, a as HostedUploadOptions, b as HostedUploadRecord, c as HostedUploadStart, L as LocalFile, O as Outbox, d as OutboxOptions, e as OutboxStore, P as PLAYBACK_RATES, Q as QueuedMessage, S as StorageUpload, f as attachmentKindFor, g as createOutbox, h as fileExtension, i as formatDuration, j as isAllowedExtension, m as memoryOutboxStore, n as nextPlaybackRate, r as randomId, k as recordingLimitMs, l as releaseObjectUrl, w as waveformFromMetering, o as waveformPeaks } from './outbox-B9NAWQ58.js';
|
|
4
|
+
export { R as ReactionSummary, T as ThreadItem, a as activityLine, c as currentActivity, d as dayLabel, f as firstUnreadId, i as itemSender, b as itemTime, m as mergeThread, p as parseMentions, e as previewText, s as sameDay, g as startsDay, h as startsGroup, j as summarizeReactions, t as throttle, u as upsertMessages } from './thread-oPra7pkW.js';
|
|
5
5
|
import '@supabase/supabase-js';
|
|
6
6
|
|
|
7
7
|
/**
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export { extractLinks, isHttpsUrl, isSchedulable, scheduleLabel, scheduleQuickPicks, snippetParts, topicKey } from './chunk-BJCE5O7V.js';
|
|
2
|
-
export { activityLine, createOutbox, currentActivity, dayLabel, firstUnreadId, itemSender, itemTime, memoryOutboxStore, mergeThread, parseMentions, previewText, releaseObjectUrl, sameDay, startsDay, startsGroup, summarizeReactions, throttle, upsertMessages } from './chunk-
|
|
3
|
-
export { ALLOWED_EXTENSIONS, CHAT_BUCKET, CHAT_LIMITS, CHAT_SCHEMA, ChatError, MAX_RANGES_PER_DAY, PLAYBACK_RATES, WEEKDAYS, attachmentKindFor, awayLine, awaySummary, conversationTopic, createChatClient, fileExtension, formatDuration, hoursSummary, isAllowedExtension, isAway, isWithinWorkingHours, localClock, minutesOf, namesLine, nextPlaybackRate, normalizeHours, randomId, recordingLimitMs, timeZoneLabel, toAttachment, toAvailability, toLinkPreview, toMessage, toScheduled, toSearchHit, toTopic, untilLabel, userTopic, waveformFromMetering, waveformPeaks } from './chunk-
|
|
2
|
+
export { activityLine, createOutbox, currentActivity, dayLabel, firstUnreadId, itemSender, itemTime, memoryOutboxStore, mergeThread, parseMentions, previewText, releaseObjectUrl, sameDay, startsDay, startsGroup, summarizeReactions, throttle, upsertMessages } from './chunk-A4YJX7KT.js';
|
|
3
|
+
export { ALLOWED_EXTENSIONS, CHAT_BUCKET, CHAT_LIMITS, CHAT_SCHEMA, ChatError, MAX_RANGES_PER_DAY, PLAYBACK_RATES, WEEKDAYS, attachmentKindFor, awayLine, awaySummary, conversationTopic, createChatClient, fileExtension, formatDuration, hoursSummary, isAllowedExtension, isAway, isWithinWorkingHours, localClock, minutesOf, namesLine, nextPlaybackRate, normalizeHours, randomId, recordingLimitMs, sendBytes, timeZoneLabel, toAttachment, toAvailability, toLinkPreview, toMessage, toScheduled, toSearchHit, toTopic, untilLabel, userTopic, waveformFromMetering, waveformPeaks } from './chunk-GBJ3YI4E.js';
|
|
4
4
|
//# sourceMappingURL=index.js.map
|
|
5
5
|
//# sourceMappingURL=index.js.map
|
package/dist/native.d.ts
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import * as react from 'react';
|
|
2
2
|
import { ComponentType, ReactNode } from 'react';
|
|
3
3
|
import { InboxPageProps, InboxItem, ScreenHeaderProps } from '@marktiderman/genesis-ui-native/layouts';
|
|
4
|
-
import { m as ChatInboxItem, h as ChatAttachment, q as ChatMessage, k as ChatConversation, t as ChatRole, P as PendingFile, o as ChatLinkPreview,
|
|
5
|
-
import { ChatAttachmentKind, ChatVideoUpload } from './react.js';
|
|
6
|
-
import { T as ThreadItem } from './thread-
|
|
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
|
+
import { ChatAttachmentKind, ChatCardContext, ChatVideoUpload } from './react.js';
|
|
6
|
+
import { T as ThreadItem } from './thread-oPra7pkW.js';
|
|
7
7
|
import { ColorValue } from 'react-native';
|
|
8
|
-
import { L as LocalFile } from './outbox-
|
|
8
|
+
import { L as LocalFile } from './outbox-B9NAWQ58.js';
|
|
9
9
|
export { CHAT_MARK_READ_ACTION, CHAT_PUSH_CATEGORY, CHAT_REPLY_ACTION, ChatPushCopy, ChatPushData, ChatPushOutboxDeps, ChatPushOutcome, ChatPushPayload, ChatPushPayloadInput, ChatPushResponseLike, NotificationCategoriesLike, PUSH_REPLY_WAIT_MS, chatNotificationActions, chatPath, chatPushCategory, chatPushCopy, chatPushPayload, chatThreadMatch, conversationIdFromData, failedReply, handleChatPushResponse, registerChatNotificationActions, replyClientId, replyClientIdFor } from './push.js';
|
|
10
10
|
import { NativeIconName } from '@marktiderman/genesis-ui-native/components';
|
|
11
11
|
import '@supabase/supabase-js';
|
|
@@ -502,6 +502,8 @@ interface ExpoVideoLike {
|
|
|
502
502
|
contentFit?: "contain" | "cover" | "fill";
|
|
503
503
|
nativeControls?: boolean;
|
|
504
504
|
allowsPictureInPicture?: boolean;
|
|
505
|
+
onFullscreenEnter?: () => void;
|
|
506
|
+
onFullscreenExit?: () => void;
|
|
505
507
|
testID?: string;
|
|
506
508
|
}>;
|
|
507
509
|
}
|
|
@@ -596,9 +598,22 @@ declare function inboxRow(item: ChatInboxItem, ctx: {
|
|
|
596
598
|
me: string;
|
|
597
599
|
copy: ChatNativeCopy;
|
|
598
600
|
person: (id: string | null) => ChatPerson | undefined;
|
|
601
|
+
/** The app's attachment kinds: a last message that is a card reads as its title ("Check-in"). */
|
|
602
|
+
kinds?: Record<string, ChatAttachmentKind>;
|
|
599
603
|
}): Omit<InboxItem, "onPress" | "swipeActions">;
|
|
600
604
|
declare function ChatInboxScreen({ onOpen, onStart, kind, kinds, excludeKinds, archived, pageProps, testID }: ChatInboxScreenProps): react.JSX.Element;
|
|
601
605
|
|
|
606
|
+
/** A card's title (the kind's, else the file's name, else the kind); an app kind that throws reads as its name. */
|
|
607
|
+
declare function cardTitle(kind: ChatAttachmentKind | undefined, a: ChatAttachment, ctx?: ChatCardContext): string;
|
|
608
|
+
/**
|
|
609
|
+
* A message's one-line preview: its text, else what it carries, where an app kind reads as its
|
|
610
|
+
* title ("Check-in") instead of "Attachment". `attachment` is the kind alone (the inbox) or the
|
|
611
|
+
* attachment itself.
|
|
612
|
+
*/
|
|
613
|
+
declare function attachmentPreview(body: string, attachment: string | ChatAttachment | null | undefined, kinds: Record<string, ChatAttachmentKind> | undefined, deleted?: boolean): string;
|
|
614
|
+
/** The long-press sheet's caption for a message. */
|
|
615
|
+
declare function messagePreview(message: ChatMessage, kinds: Record<string, ChatAttachmentKind> | undefined): string;
|
|
616
|
+
|
|
602
617
|
type OpenAttachment = (attachment: ChatAttachment, message: ChatMessage) => void;
|
|
603
618
|
/** A message's attachments split into the app's cards and the rest (photos, voice, video, files). */
|
|
604
619
|
declare function splitCardAttachments<T extends {
|
|
@@ -614,7 +629,7 @@ declare function splitCardAttachments<T extends {
|
|
|
614
629
|
*/
|
|
615
630
|
declare function isOpenableHref(href: string | null | undefined): href is string;
|
|
616
631
|
/** What a card does: the kind's own handler, else the app's, else an https href; null without a button. */
|
|
617
|
-
declare function cardAction(kind: ChatAttachmentKind | undefined, attachment: ChatAttachment, message: ChatMessage, onOpenAttachment?: OpenAttachment): {
|
|
632
|
+
declare function cardAction(kind: ChatAttachmentKind | undefined, attachment: ChatAttachment, message: ChatMessage, onOpenAttachment?: OpenAttachment, ctx?: ChatCardContext): {
|
|
618
633
|
label: string;
|
|
619
634
|
run: () => void;
|
|
620
635
|
} | null;
|
|
@@ -730,6 +745,12 @@ interface ChatThreadScreenProps {
|
|
|
730
745
|
availability?: boolean;
|
|
731
746
|
/** An app attachment card's button (a form, a check-in), when its kind gives no `onPress`. */
|
|
732
747
|
onOpenAttachment?: OpenAttachment;
|
|
748
|
+
/**
|
|
749
|
+
* Whether the screen is the one shown (the navigator's `useIsFocused()`). When it turns false a
|
|
750
|
+
* video or voice note of this thread that is playing pauses: switching tab keeps the screen
|
|
751
|
+
* mounted. Default true.
|
|
752
|
+
*/
|
|
753
|
+
focused?: boolean;
|
|
733
754
|
testID?: string;
|
|
734
755
|
}
|
|
735
756
|
/** Points from the bottom that still count as "at the bottom" (FlatList, which follows by hand). */
|
|
@@ -1034,9 +1055,11 @@ interface MessageActionsSheetProps {
|
|
|
1034
1055
|
onClose: () => void;
|
|
1035
1056
|
onReact: (message: ChatMessage, emoji: string, on: boolean) => void;
|
|
1036
1057
|
onAction: (message: ChatMessage, action: MessageActionId) => void;
|
|
1058
|
+
/** The app's attachment kinds (`ChatProvider attachmentKinds`): the caption names a card by its title. */
|
|
1059
|
+
attachmentKinds?: Record<string, ChatAttachmentKind>;
|
|
1037
1060
|
testID?: string;
|
|
1038
1061
|
}
|
|
1039
|
-
declare function MessageActionsSheet({ message, context, onClose, onReact, onAction, testID }: MessageActionsSheetProps): react.JSX.Element;
|
|
1062
|
+
declare function MessageActionsSheet({ message, context, onClose, onReact, onAction, attachmentKinds, testID }: MessageActionsSheetProps): react.JSX.Element;
|
|
1040
1063
|
|
|
1041
1064
|
/** Called when a voice note starts: pauses whichever other one was playing. */
|
|
1042
1065
|
declare function claimPlayback(id: string, pause: () => void): void;
|
|
@@ -1048,6 +1071,12 @@ declare function usePlayingVoiceNote(ids: readonly string[]): string | null;
|
|
|
1048
1071
|
declare function toggleVoiceNote(id: string): boolean;
|
|
1049
1072
|
/** Moves the voice note with this id to its next speed; false when none is on screen with playback. */
|
|
1050
1073
|
declare function cycleVoiceNoteRate(id: string): boolean;
|
|
1074
|
+
/**
|
|
1075
|
+
* Pauses the voice note or video playing, if any; with `ids` (or a test of an id), only when it
|
|
1076
|
+
* is one of them (a screen's own attachments). For a screen losing focus: a tab switch keeps it mounted, so its
|
|
1077
|
+
* player would play on. Returns whether one was paused.
|
|
1078
|
+
*/
|
|
1079
|
+
declare function pauseChatPlayback(ids?: Iterable<string> | ((id: string) => boolean)): boolean;
|
|
1051
1080
|
/** The playing voice note's id, for tests. */
|
|
1052
1081
|
declare function activePlaybackId(): string | null;
|
|
1053
1082
|
/** Where a finger at `x` across a waveform `width` wide puts the playhead, in seconds. */
|
|
@@ -1908,4 +1937,4 @@ declare function ModerationMarker({ note, mine, testID }: {
|
|
|
1908
1937
|
testID?: string;
|
|
1909
1938
|
}): react.JSX.Element;
|
|
1910
1939
|
|
|
1911
|
-
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, 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, availabilityInput, awayLineFor, barsThatFit, base64ToBytes, base64Utf8, broadcastOutcome, broadcastRows, buildThreadRows, canManageTopics, canReactTo, canSend, cardAction, 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, moderationNote, moderationText, muxPosterUrl, muxStreamUrl, nearBottom, nextOffset, openChatLink, panLimit, 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 };
|
|
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 };
|