@marktiderman/genesis-chat 0.1.0 → 0.2.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 +304 -13
- package/dist/{chunk-SAY24E6V.js → chunk-5D5A7I4Q.js} +166 -45
- package/dist/chunk-5D5A7I4Q.js.map +1 -0
- package/dist/{chunk-JQXZUEEL.js → chunk-7S6HYNWW.js} +382 -8
- package/dist/chunk-7S6HYNWW.js.map +1 -0
- package/dist/chunk-BJCE5O7V.js +70 -0
- package/dist/chunk-BJCE5O7V.js.map +1 -0
- package/dist/chunk-PZTOY2LY.js +576 -0
- package/dist/chunk-PZTOY2LY.js.map +1 -0
- package/dist/chunk-VEPZROQB.js +187 -0
- package/dist/chunk-VEPZROQB.js.map +1 -0
- package/dist/{client-BtdALFCx.d.ts → client-DMa2j7kz.d.ts} +152 -11
- package/dist/index.d.ts +78 -163
- package/dist/index.js +3 -2
- package/dist/native.d.ts +1910 -1
- package/dist/native.js +4900 -0
- package/dist/native.js.map +1 -1
- package/dist/outbox-B0y3phE0.d.ts +151 -0
- package/dist/push.d.ts +206 -0
- package/dist/push.js +3 -0
- package/dist/push.js.map +1 -0
- package/dist/react.d.ts +149 -7
- package/dist/react.js +3 -3
- package/dist/server.d.ts +510 -21
- package/dist/server.js +863 -21
- package/dist/server.js.map +1 -1
- package/dist/thread-DWXHKPdw.d.ts +57 -0
- package/dist/web.d.ts +313 -10
- package/dist/web.js +1731 -60
- package/dist/web.js.map +1 -1
- package/migrations/0002_genesis_chat_coaching.sql +934 -0
- package/migrations/tests/0002_genesis_chat_coaching.test.sql +265 -0
- package/package.json +74 -6
- package/src/__tests__/coaching-core.test.ts +332 -0
- package/src/__tests__/coaching-react.test.tsx +248 -0
- package/src/__tests__/coaching-web.test.tsx +449 -0
- package/src/__tests__/core.test.ts +91 -0
- package/src/__tests__/outbox.test.ts +122 -0
- package/src/__tests__/realtime.test.ts +70 -0
- package/src/__tests__/review-fixes-core.test.ts +193 -0
- package/src/__tests__/review-fixes-web.test.tsx +402 -0
- package/src/__tests__/server-effects.test.ts +158 -0
- package/src/__tests__/server-fakes.ts +90 -0
- package/src/__tests__/server-integrations.test.ts +247 -0
- package/src/__tests__/server-providers.test.ts +246 -0
- package/src/__tests__/server-runner.test.ts +277 -0
- package/src/__tests__/server-safety.test.ts +290 -0
- package/src/__tests__/web-markdown.test.tsx +88 -0
- package/src/__tests__/web.test.tsx +333 -0
- package/src/core/availability.ts +223 -0
- package/src/core/client.ts +757 -0
- package/src/core/extras.ts +106 -0
- package/src/core/media.ts +144 -0
- package/src/core/outbox.ts +429 -0
- package/src/core/thread.ts +171 -0
- package/src/core/types.ts +311 -0
- package/src/index.ts +13 -0
- package/src/native/__tests__/auto-retry.test.tsx +128 -0
- package/src/native/__tests__/composer-mic-lock.test.tsx +115 -0
- package/src/native/__tests__/composer-state.test.ts +188 -0
- package/src/native/__tests__/composer.test.tsx +133 -0
- package/src/native/__tests__/emoji.test.tsx +238 -0
- package/src/native/__tests__/inbox-screen.test.tsx +48 -0
- package/src/native/__tests__/message-bubble.test.tsx +127 -0
- package/src/native/__tests__/organise-logic.test.ts +164 -0
- package/src/native/__tests__/organise-screens.test.tsx +344 -0
- package/src/native/__tests__/photo-viewer.test.tsx +226 -0
- package/src/native/__tests__/push-payload.test.ts +66 -0
- package/src/native/__tests__/push.test.ts +209 -0
- package/src/native/__tests__/recorder-machine.test.ts +96 -0
- package/src/native/__tests__/rows-actions.test.ts +76 -0
- package/src/native/__tests__/thread-layout.test.ts +41 -0
- package/src/native/__tests__/thread-screen.test.tsx +116 -0
- package/src/native/__tests__/tus.test.ts +154 -0
- package/src/native/__tests__/use-voice-recorder.test.tsx +316 -0
- package/src/native/__tests__/video-media.test.tsx +421 -0
- package/src/native/__tests__/video-recorder-state.test.ts +87 -0
- package/src/native/__tests__/video-upload.test.ts +227 -0
- package/src/native/access-error.tsx +31 -0
- package/src/native/actions.ts +42 -0
- package/src/native/attachment-cards.tsx +116 -0
- package/src/native/auto-retry.ts +69 -0
- package/src/native/availability.tsx +376 -0
- package/src/native/broadcast-sheet.tsx +193 -0
- package/src/native/composer-state.ts +302 -0
- package/src/native/composer.tsx +453 -0
- package/src/native/context.tsx +70 -0
- package/src/native/copy.ts +296 -0
- package/src/native/emoji-data.ts +21 -0
- package/src/native/emoji-picker.tsx +229 -0
- package/src/native/emoji.ts +118 -0
- package/src/native/icon-button.tsx +40 -0
- package/src/native/inbox-screen.tsx +116 -0
- package/src/native/index.ts +184 -0
- package/src/native/link-preview.tsx +104 -0
- package/src/native/media-colors.ts +15 -0
- package/src/native/media.tsx +187 -0
- package/src/native/message-actions-sheet.tsx +121 -0
- package/src/native/message-bubble.tsx +374 -0
- package/src/native/moderation.tsx +42 -0
- package/src/native/modules.ts +275 -0
- package/src/native/organise-copy.ts +195 -0
- package/src/native/photo-viewer.tsx +531 -0
- package/src/native/push.ts +375 -0
- package/src/native/recorder-machine.ts +176 -0
- package/src/native/rows.ts +81 -0
- package/src/native/schedule-sheet.tsx +314 -0
- package/src/native/search-screen.tsx +168 -0
- package/src/native/stack-options.ts +36 -0
- package/src/native/start-sheet.tsx +87 -0
- package/src/native/thread-screen.tsx +620 -0
- package/src/native/topics.tsx +179 -0
- package/src/native/tus.ts +282 -0
- package/src/native/use-composer.ts +71 -0
- package/src/native/use-jump.ts +91 -0
- package/src/native/use-voice-recorder.ts +234 -0
- package/src/native/video-player.tsx +370 -0
- package/src/native/video-recorder-state.ts +140 -0
- package/src/native/video-recorder.tsx +271 -0
- package/src/native/video-upload-tray.tsx +77 -0
- package/src/native/video-upload.ts +432 -0
- package/src/native/voice-player.tsx +283 -0
- package/src/react/index.tsx +810 -0
- package/src/server/assistant.ts +235 -0
- package/src/server/crypto.ts +86 -0
- package/src/server/expo.ts +119 -0
- package/src/server/handler.ts +32 -0
- package/src/server/index.ts +57 -0
- package/src/server/moderation.ts +155 -0
- package/src/server/mux.ts +290 -0
- package/src/server/notifications.ts +130 -0
- package/src/server/runner.ts +468 -0
- package/src/server/transcribers.ts +111 -0
- package/src/server/types.ts +171 -0
- package/src/server/unfurl.ts +480 -0
- package/src/server/upload.ts +158 -0
- package/src/web/attachments.tsx +379 -0
- package/src/web/availability.tsx +299 -0
- package/src/web/broadcast.tsx +166 -0
- package/src/web/bubble.tsx +563 -0
- package/src/web/cards.tsx +136 -0
- package/src/web/composer.tsx +571 -0
- package/src/web/emoji-picker.tsx +84 -0
- package/src/web/error-boundary.tsx +33 -0
- package/src/web/format.ts +55 -0
- package/src/web/inbox.tsx +195 -0
- package/src/web/index.ts +75 -0
- package/src/web/markdown.tsx +245 -0
- package/src/web/memory-client.ts +706 -0
- package/src/web/panel.tsx +135 -0
- package/src/web/schedule.tsx +192 -0
- package/src/web/search.tsx +129 -0
- package/src/web/thread-context.ts +64 -0
- package/src/web/thread.tsx +802 -0
- package/src/web/topics.tsx +160 -0
- package/src/web/use-voice-recorder.ts +264 -0
- package/src/web/video.tsx +522 -0
- package/src/web/voice-note.tsx +197 -0
- package/dist/chunk-27UTR5FW.js +0 -322
- package/dist/chunk-27UTR5FW.js.map +0 -1
- package/dist/chunk-JQXZUEEL.js.map +0 -1
- package/dist/chunk-SAY24E6V.js.map +0 -1
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
import { b as AttachmentKind, A as AttachmentInput, i as ChatClient, B as PendingMessage, P as PendingFile, q as ChatMessage, E as SendInput } from './client-DMa2j7kz.js';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @feat:chat
|
|
5
|
+
* Media rules shared by every platform: which files may be sent (the same list
|
|
6
|
+
* migration 0001 checks), what kind an upload becomes, the default limits, and
|
|
7
|
+
* the waveform a voice note carries so its bubble draws before the audio loads.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* A random UUID (v4): `crypto.randomUUID` where the platform has it (some React Native
|
|
12
|
+
* runtimes don't), else `crypto.getRandomValues`, else Math.random as a last resort. Ids
|
|
13
|
+
* only need to be unique per sender: the server checks (sender, client_id).
|
|
14
|
+
*/
|
|
15
|
+
declare function randomId(): string;
|
|
16
|
+
/** Mirrors genesis_chat.allowed_extension. Never SVG or HTML, which a browser runs as a page. */
|
|
17
|
+
declare const ALLOWED_EXTENSIONS: readonly ["png", "jpg", "jpeg", "webp", "gif", "heic", "heif", "m4a", "aac", "mp3", "ogg", "oga", "opus", "weba", "webm", "mp4", "mov", "pdf", "txt", "csv", "docx", "xlsx", "pptx"];
|
|
18
|
+
/** The extension a file is stored under: from its content type, else its name. */
|
|
19
|
+
declare function fileExtension(name: string, contentType?: string): string;
|
|
20
|
+
declare function isAllowedExtension(ext: string): boolean;
|
|
21
|
+
/** What an upload becomes in a message. */
|
|
22
|
+
declare function attachmentKindFor(contentType: string, opts?: {
|
|
23
|
+
recordedVoice?: boolean;
|
|
24
|
+
}): AttachmentKind;
|
|
25
|
+
/** Default limits (decision 5): an app may lower them, not raise them past the bucket's 100 MB. */
|
|
26
|
+
declare const CHAT_LIMITS: {
|
|
27
|
+
/** Voice notes and videos, for members. */
|
|
28
|
+
readonly recordingMs: number;
|
|
29
|
+
/** For owners, admins and observers (coaches, staff). */
|
|
30
|
+
readonly staffRecordingMs: number;
|
|
31
|
+
readonly fileBytes: number;
|
|
32
|
+
readonly videoBytes: number;
|
|
33
|
+
readonly attachmentsPerMessage: 20;
|
|
34
|
+
readonly bodyChars: 10000;
|
|
35
|
+
};
|
|
36
|
+
/** The longest recording this role may make. */
|
|
37
|
+
declare function recordingLimitMs(role: string | null | undefined): number;
|
|
38
|
+
/**
|
|
39
|
+
* Peaks for a waveform: `count` values 0–100 from raw samples (-1…1), the loudest
|
|
40
|
+
* in each bucket, scaled so the loudest bucket is 100. Quiet recordings still show
|
|
41
|
+
* a shape; silence shows a flat line.
|
|
42
|
+
*/
|
|
43
|
+
declare function waveformPeaks(samples: ArrayLike<number>, count?: number): number[];
|
|
44
|
+
/**
|
|
45
|
+
* Peaks from a level meter read while recording (expo-audio's `metering`, in dB,
|
|
46
|
+
* about -160…0): resampled to `count` values 0–100.
|
|
47
|
+
*/
|
|
48
|
+
declare function waveformFromMetering(levelsDb: number[], count?: number): number[];
|
|
49
|
+
/** 0:42, 1:05:09. */
|
|
50
|
+
declare function formatDuration(ms: number | null | undefined): string;
|
|
51
|
+
/** Playback speeds offered for voice and video (free for everyone, decision 5). */
|
|
52
|
+
declare const PLAYBACK_RATES: readonly [1, 1.5, 2];
|
|
53
|
+
declare function nextPlaybackRate(rate: number): number;
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* @feat:chat
|
|
57
|
+
* The send queue: a message shows at once as pending, its files upload, then it
|
|
58
|
+
* is sent with the clientId made when it was written, so a retry (after a lost
|
|
59
|
+
* connection, a closed app) never posts twice. Messages to one conversation go
|
|
60
|
+
* in the order they were written: the first that can't go (a lost file, a refusal)
|
|
61
|
+
* holds back the ones after it. A refusal (not allowed, bad data) is `permanent`
|
|
62
|
+
* and only sent again by hand. `clear()` (sign-out) stops sends in flight: none
|
|
63
|
+
* posts, or saves anything, afterwards. Storage is the platform's (memory by default;
|
|
64
|
+
* localStorage on web, MMKV or SQLite on native), behind OutboxStore.
|
|
65
|
+
*/
|
|
66
|
+
|
|
67
|
+
/** A file still on the device, uploaded when its message is sent. */
|
|
68
|
+
interface LocalFile {
|
|
69
|
+
/** The bytes, or (native) a file URI the platform reads in `readFile`. */
|
|
70
|
+
data: Blob | ArrayBuffer | string;
|
|
71
|
+
name: string;
|
|
72
|
+
contentType: string;
|
|
73
|
+
/** A preview to show while it uploads (an object URL, a file URI). The outbox owns it from here: see `releasePreview`. */
|
|
74
|
+
previewUrl?: string;
|
|
75
|
+
/** Known up front: a voice note's duration and waveform, a photo's size. */
|
|
76
|
+
meta?: Partial<Omit<AttachmentInput, "path" | "kind">> & {
|
|
77
|
+
kind?: AttachmentInput["kind"];
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
interface QueuedMessage extends Omit<PendingMessage, "files"> {
|
|
81
|
+
files: LocalFile[];
|
|
82
|
+
/** What each file is, kept with the saved copy (PendingMessage.files). */
|
|
83
|
+
pendingFiles?: PendingFile[];
|
|
84
|
+
/** Files lost on a relaunch (bytes that weren't persisted). */
|
|
85
|
+
lostFiles?: number;
|
|
86
|
+
attempts: number;
|
|
87
|
+
}
|
|
88
|
+
interface OutboxStore {
|
|
89
|
+
load(): Promise<QueuedMessage[]>;
|
|
90
|
+
save(queue: QueuedMessage[]): Promise<void>;
|
|
91
|
+
}
|
|
92
|
+
declare const memoryOutboxStore: () => OutboxStore;
|
|
93
|
+
interface OutboxOptions {
|
|
94
|
+
client: ChatClient;
|
|
95
|
+
userId: string;
|
|
96
|
+
store?: OutboxStore;
|
|
97
|
+
/** Reads a native file URI into bytes for upload. */
|
|
98
|
+
readFile?: (uri: string) => Promise<Blob | ArrayBuffer>;
|
|
99
|
+
/** Upload hook, e.g. resumable uploads on native. Defaults to client.upload. `signal` aborts when the message is discarded or the outbox cleared. */
|
|
100
|
+
upload?: (conversationId: string, file: LocalFile, opts?: {
|
|
101
|
+
signal?: AbortSignal;
|
|
102
|
+
}) => Promise<string>;
|
|
103
|
+
/** Called with every change, for the UI. */
|
|
104
|
+
onChange?: (queue: QueuedMessage[]) => void;
|
|
105
|
+
/** Called when a message lands. */
|
|
106
|
+
onSent?: (message: ChatMessage, clientId: string) => void;
|
|
107
|
+
/** Makes client ids. Default: a random UUID (works where crypto.randomUUID is missing). */
|
|
108
|
+
newId?: () => string;
|
|
109
|
+
/**
|
|
110
|
+
* Keeps a file held as bytes (a pasted image, a recording) between launches: write it
|
|
111
|
+
* somewhere and return a URI `readFile` can read (native: the app's cache directory).
|
|
112
|
+
* Without it, such a file isn't saved, and after a relaunch its message asks for it again.
|
|
113
|
+
*/
|
|
114
|
+
persistFile?: (file: LocalFile) => Promise<string>;
|
|
115
|
+
/**
|
|
116
|
+
* Lets go of a file's `previewUrl` once its message has landed, been discarded or cleared.
|
|
117
|
+
* Default: revokes `blob:` object URLs (the web's), and leaves everything else alone.
|
|
118
|
+
*/
|
|
119
|
+
releasePreview?: (url: string) => void;
|
|
120
|
+
}
|
|
121
|
+
/** Revokes a `blob:` object URL; anything else (a native file URI) is left alone. */
|
|
122
|
+
declare function releaseObjectUrl(url: string): void;
|
|
123
|
+
declare function createOutbox(opts: OutboxOptions): {
|
|
124
|
+
/** Queues a message; it shows at once and sends in order. Returns its clientId. */
|
|
125
|
+
send(input: Omit<SendInput, "clientId"> & {
|
|
126
|
+
clientId?: string;
|
|
127
|
+
}, files?: LocalFile[]): Promise<string>;
|
|
128
|
+
retry(clientId: string): Promise<void>;
|
|
129
|
+
/**
|
|
130
|
+
* Gives a message the files it lost on a relaunch and sends it. `files` fill the lost
|
|
131
|
+
* slots in order (`PendingMessage.files[i].lost`); the files that were kept stay. Pass
|
|
132
|
+
* one per lost slot; with fewer, the message keeps waiting for the rest.
|
|
133
|
+
*/
|
|
134
|
+
reattach(clientId: string, files: LocalFile[]): Promise<void>;
|
|
135
|
+
/**
|
|
136
|
+
* Retries failed messages (after the connection comes back), in order per conversation,
|
|
137
|
+
* stopping at the first that can't go on its own: one waiting for a lost file, or one the
|
|
138
|
+
* server refused (`permanent`, retried only by hand). The ones after it keep waiting.
|
|
139
|
+
*/
|
|
140
|
+
retryAll(): Promise<void>;
|
|
141
|
+
/** Forgets every queued message, here and in the store (call it on sign-out). */
|
|
142
|
+
clear(): Promise<void>;
|
|
143
|
+
discard(clientId: string): Promise<void>;
|
|
144
|
+
pending(conversationId?: string): PendingMessage[];
|
|
145
|
+
/** A new client id, made the way this outbox makes them. */
|
|
146
|
+
newId: typeof randomId;
|
|
147
|
+
load: () => Promise<void>;
|
|
148
|
+
};
|
|
149
|
+
type Outbox = ReturnType<typeof createOutbox>;
|
|
150
|
+
|
|
151
|
+
export { ALLOWED_EXTENSIONS as A, CHAT_LIMITS as C, type LocalFile as L, type Outbox as O, PLAYBACK_RATES as P, type QueuedMessage as Q, type OutboxOptions as a, type OutboxStore as b, attachmentKindFor as c, createOutbox as d, formatDuration as e, fileExtension as f, recordingLimitMs as g, releaseObjectUrl as h, isAllowedExtension as i, waveformPeaks as j, memoryOutboxStore as m, nextPlaybackRate as n, randomId as r, waveformFromMetering as w };
|
package/dist/push.d.ts
ADDED
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
import { i as ChatClient } from './client-DMa2j7kz.js';
|
|
2
|
+
import { O as Outbox, b as OutboxStore, Q as QueuedMessage } from './outbox-B0y3phE0.js';
|
|
3
|
+
import '@supabase/supabase-js';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* @feat:chat
|
|
7
|
+
* Push glue for genesis-native's push block, data only: the `messages`
|
|
8
|
+
* category (a switch in Notification settings and an Android channel), its
|
|
9
|
+
* notification actions (Reply with a text field, Mark read), what a tap opens
|
|
10
|
+
* (`data.url` = `/messages/<conversationId>`), the reply and mark-read
|
|
11
|
+
* handlers for the block's `onResponse`, and the match that keeps a thread's
|
|
12
|
+
* own pushes out of the foreground while it is open (the block's `suppress`).
|
|
13
|
+
*
|
|
14
|
+
* const push = createPush({ …, categories: [...yours, chatPushCategory()],
|
|
15
|
+
* onResponse: (r) => void handleChatPushResponse(r, { client: chatClient, notifications: Notifications }) });
|
|
16
|
+
* void registerChatNotificationActions(Notifications); // once, at start
|
|
17
|
+
* useSuppressNotifications(chatThreadMatch(conversationId)); // in the thread screen
|
|
18
|
+
*
|
|
19
|
+
* The sender sets `categoryId: "messages"` (iOS) / the `messages` channel
|
|
20
|
+
* (Android) and `data: { url: "/messages/<id>", conversationId, seq, messageId }`;
|
|
21
|
+
* `chatPushPayload` builds those and the fields iOS rich push reads (the
|
|
22
|
+
* sender's name and photo, the group, a photo), and it is server safe: import
|
|
23
|
+
* it from `@marktiderman/genesis-chat/push`.
|
|
24
|
+
*
|
|
25
|
+
* A reply goes through the outbox, so a phone that is offline keeps it: pass
|
|
26
|
+
* the live one (`useChat().outbox`) when the chat screens are mounted, and the
|
|
27
|
+
* persisted store and user id (`ChatProvider outboxStore`) for when they
|
|
28
|
+
* aren't. A reply that can't be sent then waits there, failed, with Retry in
|
|
29
|
+
* its thread.
|
|
30
|
+
*/
|
|
31
|
+
|
|
32
|
+
declare const CHAT_PUSH_CATEGORY = "messages";
|
|
33
|
+
declare const CHAT_REPLY_ACTION = "reply";
|
|
34
|
+
declare const CHAT_MARK_READ_ACTION = "mark-read";
|
|
35
|
+
interface ChatPushCopy {
|
|
36
|
+
title: string;
|
|
37
|
+
description: string;
|
|
38
|
+
reply: string;
|
|
39
|
+
replySubmit: string;
|
|
40
|
+
replyPlaceholder: string;
|
|
41
|
+
markRead: string;
|
|
42
|
+
}
|
|
43
|
+
declare const chatPushCopy: ChatPushCopy;
|
|
44
|
+
/** The path a message's push opens. */
|
|
45
|
+
declare function chatPath(conversationId: string): string;
|
|
46
|
+
/** The category for createPush's `categories` (genesis-native's NotificationCategory). */
|
|
47
|
+
declare function chatPushCategory(copy?: Partial<ChatPushCopy>): {
|
|
48
|
+
id: string;
|
|
49
|
+
title: string;
|
|
50
|
+
description: string;
|
|
51
|
+
importance: "high";
|
|
52
|
+
};
|
|
53
|
+
/** expo-notifications' `setNotificationCategoryAsync`, the one call this needs. */
|
|
54
|
+
interface NotificationCategoriesLike {
|
|
55
|
+
setNotificationCategoryAsync(identifier: string, actions: {
|
|
56
|
+
identifier: string;
|
|
57
|
+
buttonTitle: string;
|
|
58
|
+
textInput?: {
|
|
59
|
+
submitButtonTitle: string;
|
|
60
|
+
placeholder: string;
|
|
61
|
+
};
|
|
62
|
+
options?: {
|
|
63
|
+
opensAppToForeground?: boolean;
|
|
64
|
+
isDestructive?: boolean;
|
|
65
|
+
isAuthenticationRequired?: boolean;
|
|
66
|
+
};
|
|
67
|
+
}[], options?: Record<string, unknown>): Promise<unknown>;
|
|
68
|
+
dismissNotificationAsync?(identifier: string): Promise<void>;
|
|
69
|
+
}
|
|
70
|
+
/** The actions on a message's notification: Reply (a text field) and Mark read, neither opening the app. */
|
|
71
|
+
declare function chatNotificationActions(copy?: Partial<ChatPushCopy>): ({
|
|
72
|
+
identifier: string;
|
|
73
|
+
buttonTitle: string;
|
|
74
|
+
textInput: {
|
|
75
|
+
submitButtonTitle: string;
|
|
76
|
+
placeholder: string;
|
|
77
|
+
};
|
|
78
|
+
options: {
|
|
79
|
+
opensAppToForeground: boolean;
|
|
80
|
+
};
|
|
81
|
+
} | {
|
|
82
|
+
identifier: string;
|
|
83
|
+
buttonTitle: string;
|
|
84
|
+
options: {
|
|
85
|
+
opensAppToForeground: boolean;
|
|
86
|
+
};
|
|
87
|
+
textInput?: undefined;
|
|
88
|
+
})[];
|
|
89
|
+
/** Registers the actions with the OS (once, at start; it is idempotent). */
|
|
90
|
+
declare function registerChatNotificationActions(notifications: NotificationCategoriesLike, copy?: Partial<ChatPushCopy>, onError?: (error: unknown) => void): Promise<unknown>;
|
|
91
|
+
/** The conversation a push is about: `data.conversationId`, else the id in `data.url`. */
|
|
92
|
+
declare function conversationIdFromData(data: Record<string, unknown> | null | undefined): string | null;
|
|
93
|
+
/**
|
|
94
|
+
* The client id a reply from this notification sends with: the notification's
|
|
95
|
+
* own id, as a uuid (it already is one on iOS; anything else is hashed into
|
|
96
|
+
* one), so the same reply delivered twice posts once.
|
|
97
|
+
*/
|
|
98
|
+
declare function replyClientId(notificationId: string): string;
|
|
99
|
+
/**
|
|
100
|
+
* The client id for one reply: from the notification's id, the message it is
|
|
101
|
+
* about (`data.messageId`) and the reply's text. The same reply delivered
|
|
102
|
+
* twice posts once; two replies to one conversation never share an id, even
|
|
103
|
+
* when iOS reuses the notification's id for a collapsed push.
|
|
104
|
+
*/
|
|
105
|
+
declare function replyClientIdFor(notificationId: string, data: Record<string, unknown> | null | undefined, body: string): string;
|
|
106
|
+
/** The part of a notification response this reads (expo-notifications' `NotificationResponse`). */
|
|
107
|
+
interface ChatPushResponseLike {
|
|
108
|
+
actionIdentifier: string;
|
|
109
|
+
/** The text typed into Reply. */
|
|
110
|
+
userText?: string;
|
|
111
|
+
notification: {
|
|
112
|
+
request: {
|
|
113
|
+
identifier: string;
|
|
114
|
+
content: {
|
|
115
|
+
data?: Record<string, unknown> | null;
|
|
116
|
+
};
|
|
117
|
+
};
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
/** "queued": the reply couldn't go now and waits in the outbox, failed, for Retry. */
|
|
121
|
+
type ChatPushOutcome = "replied" | "queued" | "marked-read" | "ignored" | "failed";
|
|
122
|
+
type LiveOutbox = Pick<Outbox, "send" | "pending"> & Partial<Pick<Outbox, "load">>;
|
|
123
|
+
/** How long a reply queued in the live outbox is waited for before it counts as queued, not sent. */
|
|
124
|
+
declare const PUSH_REPLY_WAIT_MS = 15000;
|
|
125
|
+
/** Where a reply waits when it can't go now. */
|
|
126
|
+
interface ChatPushOutboxDeps {
|
|
127
|
+
/** The live outbox (`useChat().outbox`), or a getter for it (read again after a slow failure): the reply is queued there and sent in order. */
|
|
128
|
+
outbox?: LiveOutbox | null | (() => LiveOutbox | null | undefined);
|
|
129
|
+
/** Without a live outbox: the persisted store (`ChatProvider outboxStore`) a reply that failed is added to. */
|
|
130
|
+
store?: OutboxStore | null;
|
|
131
|
+
/** Whose store it is (the signed-in user's id). */
|
|
132
|
+
userId?: string | null;
|
|
133
|
+
}
|
|
134
|
+
/** A reply that couldn't be sent, as the outbox keeps it: shown failed in its thread, with Retry. */
|
|
135
|
+
declare function failedReply(input: {
|
|
136
|
+
conversationId: string;
|
|
137
|
+
clientId: string;
|
|
138
|
+
body: string;
|
|
139
|
+
}, userId: string, error?: string): QueuedMessage;
|
|
140
|
+
/**
|
|
141
|
+
* Handles Reply and Mark read from a message's notification (pass it as the
|
|
142
|
+
* push block's `onResponse`). Taps on the notification itself are the block's
|
|
143
|
+
* routing, not this. Never throws: a failure is the outcome "failed" (and
|
|
144
|
+
* `onError`).
|
|
145
|
+
*/
|
|
146
|
+
declare function handleChatPushResponse(response: ChatPushResponseLike, deps: {
|
|
147
|
+
client: Pick<ChatClient, "send" | "markRead">;
|
|
148
|
+
notifications?: Pick<NotificationCategoriesLike, "dismissNotificationAsync">;
|
|
149
|
+
onError?: (error: unknown) => void;
|
|
150
|
+
/** How long to wait for a reply queued in the live outbox to go. Default PUSH_REPLY_WAIT_MS. */
|
|
151
|
+
waitMs?: number;
|
|
152
|
+
} & ChatPushOutboxDeps): Promise<ChatPushOutcome>;
|
|
153
|
+
/** For the push block's `suppress` / `useSuppressNotifications`: this conversation's pushes, while its thread is open. */
|
|
154
|
+
declare function chatThreadMatch(conversationId: string | null | undefined): ((data: Record<string, unknown>) => boolean) | null;
|
|
155
|
+
/** What a message's push says about itself, for `chatPushPayload`. */
|
|
156
|
+
interface ChatPushPayloadInput {
|
|
157
|
+
conversationId: string;
|
|
158
|
+
messageId: string;
|
|
159
|
+
seq?: number | null | undefined;
|
|
160
|
+
/** Who sent it: an opaque id (never an email or phone), the name to show and an https photo. */
|
|
161
|
+
sender?: {
|
|
162
|
+
id: string;
|
|
163
|
+
name: string;
|
|
164
|
+
avatarUrl?: string | null | undefined;
|
|
165
|
+
} | null | undefined;
|
|
166
|
+
/** The conversation's name when it is a group; leave it out for a direct conversation. */
|
|
167
|
+
groupName?: string | null | undefined;
|
|
168
|
+
/** An https photo in the message, attached to the notification. */
|
|
169
|
+
imageUrl?: string | null | undefined;
|
|
170
|
+
/**
|
|
171
|
+
* The recipient hides previews: the push carries the link and ids only (no
|
|
172
|
+
* sender, group or photo) and the service extension doesn't run. Send neutral
|
|
173
|
+
* title and body text with it.
|
|
174
|
+
*/
|
|
175
|
+
hidePreviews?: boolean | undefined;
|
|
176
|
+
}
|
|
177
|
+
/** The `data` of a message's push. Flat strings and numbers, as genesis-notifications' `PushMessage.data` takes. */
|
|
178
|
+
interface ChatPushData {
|
|
179
|
+
[key: string]: string | number;
|
|
180
|
+
url: string;
|
|
181
|
+
conversationId: string;
|
|
182
|
+
messageId: string;
|
|
183
|
+
}
|
|
184
|
+
/** The fields to spread into an Expo push message (with `to`, `title`, `body`, `badge`, `channelId`). */
|
|
185
|
+
interface ChatPushPayload {
|
|
186
|
+
categoryId: typeof CHAT_PUSH_CATEGORY;
|
|
187
|
+
/** Groups the conversation's notifications, and is the conversation iOS files a Communication Notification under. */
|
|
188
|
+
threadId: string;
|
|
189
|
+
/** iOS runs genesis-native's Notification Service Extension only when this is true (`mutable-content: 1`). */
|
|
190
|
+
mutableContent: boolean;
|
|
191
|
+
data: ChatPushData;
|
|
192
|
+
}
|
|
193
|
+
/**
|
|
194
|
+
* The category, thread, `mutableContent` and `data` of a message's push, for
|
|
195
|
+
* the server that sends it:
|
|
196
|
+
*
|
|
197
|
+
* const message = { to, title, body, badge, channelId: "messages", ...chatPushPayload({ conversationId, messageId, seq, sender, groupName, imageUrl, hidePreviews }) };
|
|
198
|
+
*
|
|
199
|
+
* On iOS, with the rich push plugin, a push with a sender is a Communication
|
|
200
|
+
* Notification (the sender's photo; Focus treats it as a message) and `imageUrl`
|
|
201
|
+
* is attached. Fields that aren't usable (a URL that isn't https, an empty
|
|
202
|
+
* name) are left out rather than sent.
|
|
203
|
+
*/
|
|
204
|
+
declare function chatPushPayload(input: ChatPushPayloadInput): ChatPushPayload;
|
|
205
|
+
|
|
206
|
+
export { CHAT_MARK_READ_ACTION, CHAT_PUSH_CATEGORY, CHAT_REPLY_ACTION, type ChatPushCopy, type ChatPushData, type ChatPushOutboxDeps, type ChatPushOutcome, type ChatPushPayload, type ChatPushPayloadInput, type ChatPushResponseLike, type NotificationCategoriesLike, PUSH_REPLY_WAIT_MS, chatNotificationActions, chatPath, chatPushCategory, chatPushCopy, chatPushPayload, chatThreadMatch, conversationIdFromData, failedReply, handleChatPushResponse, registerChatNotificationActions, replyClientId, replyClientIdFor };
|
package/dist/push.js
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
export { CHAT_MARK_READ_ACTION, CHAT_PUSH_CATEGORY, CHAT_REPLY_ACTION, PUSH_REPLY_WAIT_MS, chatNotificationActions, chatPath, chatPushCategory, chatPushCopy, chatPushPayload, chatThreadMatch, conversationIdFromData, failedReply, handleChatPushResponse, registerChatNotificationActions, replyClientId, replyClientIdFor } from './chunk-VEPZROQB.js';
|
|
2
|
+
//# sourceMappingURL=push.js.map
|
|
3
|
+
//# sourceMappingURL=push.js.map
|
package/dist/push.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"names":[],"mappings":"","file":"push.js"}
|
package/dist/react.d.ts
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import * as _tanstack_query_core from '@tanstack/query-core';
|
|
2
|
-
import {
|
|
2
|
+
import { h as ChatAttachment, i as ChatClient, k as ChatConversation, p as ChatMember, t as ChatRole, n as ChatKindRules, q as ChatMessage, g as ChatActivity, E as SendInput, M as MessagePage, C as ChatAvailability, d as AvailabilityInput, v as ChatSignal, m as ChatInboxItem, o as ChatLinkPreview, D as ScheduledMessage, S as ScheduleInput, u as ChatSearchHit, x as ChatTopic, T as TopicInput } from './client-DMa2j7kz.js';
|
|
3
3
|
import * as react from 'react';
|
|
4
4
|
import { ReactNode } from 'react';
|
|
5
|
-
import { OutboxStore, LocalFile,
|
|
5
|
+
import { b as OutboxStore, L as LocalFile, O as Outbox, Q as QueuedMessage } from './outbox-B0y3phE0.js';
|
|
6
|
+
import { T as ThreadItem } from './thread-DWXHKPdw.js';
|
|
6
7
|
import '@supabase/supabase-js';
|
|
7
8
|
|
|
8
9
|
declare const chatKeys: {
|
|
@@ -14,15 +15,58 @@ declare const chatKeys: {
|
|
|
14
15
|
role: (id: string) => readonly ["genesis-chat", "role", string];
|
|
15
16
|
pins: (id: string) => readonly ["genesis-chat", "pins", string];
|
|
16
17
|
files: (paths: string[]) => readonly ["genesis-chat", "files", string[]];
|
|
18
|
+
/** Under the conversation's key, so its `conversation` hint (set_topic broadcasts one) refreshes them. */
|
|
19
|
+
topics: (id: string) => readonly ["genesis-chat", "conversation", string, "topics"];
|
|
20
|
+
scheduled: (conversationId?: string | null) => readonly ["genesis-chat", "scheduled", string | null];
|
|
21
|
+
availability: (conversationId: string) => readonly ["genesis-chat", "conversation", string, "availability"];
|
|
22
|
+
myAvailability: () => readonly ["genesis-chat", "my-availability"];
|
|
23
|
+
search: (query: string, conversationId?: string | null) => readonly ["genesis-chat", "search", string | null, string];
|
|
24
|
+
previews: (messageIds: string[]) => readonly ["genesis-chat", "previews", string[]];
|
|
25
|
+
/** One message's link previews (useLinkPreviews keeps one query per message). */
|
|
26
|
+
preview: (messageId: string) => readonly ["genesis-chat", "preview", string];
|
|
17
27
|
};
|
|
28
|
+
/** How many messages a catch-up asks for at a time, and how many pages before it gives up and jumps to the newest. */
|
|
29
|
+
declare const CATCH_UP_PAGE = 200;
|
|
30
|
+
declare const CATCH_UP_MAX_PAGES = 10;
|
|
31
|
+
/** What a messages list holds in the query cache: the page, and whether older messages exist. */
|
|
32
|
+
type MessagesData = MessagePage;
|
|
18
33
|
/** Does a messages list (`[genesis-chat, conversation, id, messages, threadRootId, topic]`) hold this message? */
|
|
19
34
|
declare function belongsTo(key: readonly unknown[], m: ChatMessage): boolean;
|
|
35
|
+
/**
|
|
36
|
+
* Hosted video uploads (Mux direct uploads): your server makes an upload and returns its URL;
|
|
37
|
+
* the renderer PUTs the recording there and sends `{ kind: "video", provider: "mux", providerId,
|
|
38
|
+
* status: "pending" }`. Without it, videos go to storage as files.
|
|
39
|
+
*/
|
|
40
|
+
interface ChatVideoUpload {
|
|
41
|
+
create(conversationId: string): Promise<{
|
|
42
|
+
url: string;
|
|
43
|
+
providerId: string;
|
|
44
|
+
provider: "mux";
|
|
45
|
+
}>;
|
|
46
|
+
}
|
|
47
|
+
/** What an app attachment kind's card shows (a form, a check-in): plain data, drawn by each renderer. */
|
|
48
|
+
interface ChatAttachmentKind {
|
|
49
|
+
title(attachment: ChatAttachment): string;
|
|
50
|
+
subtitle?(attachment: ChatAttachment): string | null | undefined;
|
|
51
|
+
/** The card's button: a link (`href`) or a handler (`onPress`). */
|
|
52
|
+
action?(attachment: ChatAttachment): {
|
|
53
|
+
label: string;
|
|
54
|
+
href?: string;
|
|
55
|
+
onPress?: () => void;
|
|
56
|
+
} | null | undefined;
|
|
57
|
+
}
|
|
20
58
|
interface ChatContextValue {
|
|
21
59
|
client: ChatClient;
|
|
22
60
|
userId: string;
|
|
23
61
|
outbox: Outbox;
|
|
24
62
|
queue: QueuedMessage[];
|
|
25
63
|
loadPeople?: (userIds: string[]) => Promise<Record<string, ChatPerson>>;
|
|
64
|
+
videoUpload?: ChatVideoUpload;
|
|
65
|
+
attachmentKinds?: Record<string, ChatAttachmentKind>;
|
|
66
|
+
/** Retries every failed message (call it when the connection comes back: AppState, NetInfo). */
|
|
67
|
+
retryAll(): Promise<void>;
|
|
68
|
+
/** Forgets every unsent message, here and in the outbox store (call it on sign-out). */
|
|
69
|
+
clearOutbox(): Promise<void>;
|
|
26
70
|
/** Subscribe to inbox hints (one channel for the app, fanned out here). */
|
|
27
71
|
onInbox(listener: (s: ChatSignal) => void): () => void;
|
|
28
72
|
}
|
|
@@ -34,14 +78,22 @@ interface ChatProviderProps {
|
|
|
34
78
|
outboxStore?: OutboxStore;
|
|
35
79
|
/** Reads a native file URI for upload. */
|
|
36
80
|
readFile?: (uri: string) => Promise<Blob | ArrayBuffer>;
|
|
37
|
-
/** Replaces the plain upload (resumable uploads on native). */
|
|
38
|
-
upload?: (conversationId: string, file: LocalFile
|
|
81
|
+
/** Replaces the plain upload (resumable uploads on native). `signal` aborts when the message is discarded or the outbox cleared. */
|
|
82
|
+
upload?: (conversationId: string, file: LocalFile, opts?: {
|
|
83
|
+
signal?: AbortSignal;
|
|
84
|
+
}) => Promise<string>;
|
|
39
85
|
/** Makes client ids (default: a random UUID that works without crypto.randomUUID). */
|
|
40
86
|
newId?: () => string;
|
|
41
87
|
/** Keeps a byte file (a pasted image, a recording) across launches: write it, return a URI. */
|
|
42
88
|
persistFile?: (file: LocalFile) => Promise<string>;
|
|
89
|
+
/** Lets go of a sent file's preview (default: revokes `blob:` object URLs only). */
|
|
90
|
+
releasePreview?: (url: string) => void;
|
|
43
91
|
/** Names and avatars for user ids, fetched in batches (usePeople, usePerson). */
|
|
44
92
|
loadPeople?: (userIds: string[]) => Promise<Record<string, ChatPerson>>;
|
|
93
|
+
/** Hosted video uploads (Mux); videos go to storage without it. */
|
|
94
|
+
videoUpload?: ChatVideoUpload;
|
|
95
|
+
/** Cards for your own attachment kinds (`{ form: { title, subtitle, action } }`). */
|
|
96
|
+
attachmentKinds?: Record<string, ChatAttachmentKind>;
|
|
45
97
|
children: ReactNode;
|
|
46
98
|
}
|
|
47
99
|
/** How the app shows a person. */
|
|
@@ -50,11 +102,13 @@ interface ChatPerson {
|
|
|
50
102
|
avatarUrl?: string | null;
|
|
51
103
|
}
|
|
52
104
|
/** Puts chat in reach of every hook below it. Needs a TanStack QueryClientProvider above it. */
|
|
53
|
-
declare function ChatProvider({ client, userId, outboxStore, readFile, upload, newId, persistFile, loadPeople, children }: ChatProviderProps): react.JSX.Element;
|
|
105
|
+
declare function ChatProvider({ client, userId, outboxStore, readFile, upload, newId, persistFile, releasePreview, loadPeople, videoUpload, attachmentKinds, children, }: ChatProviderProps): react.JSX.Element;
|
|
54
106
|
declare function useChat(): ChatContextValue;
|
|
55
107
|
/** Your conversations, live. `kind` narrows to one kind; `archived` shows the archived ones. */
|
|
56
108
|
declare function useInbox(opts?: {
|
|
57
109
|
kind?: string;
|
|
110
|
+
kinds?: string[];
|
|
111
|
+
excludeKinds?: string[];
|
|
58
112
|
archived?: boolean;
|
|
59
113
|
limit?: number;
|
|
60
114
|
}): {
|
|
@@ -64,7 +118,9 @@ declare function useInbox(opts?: {
|
|
|
64
118
|
refetch: (options?: _tanstack_query_core.RefetchOptions) => Promise<_tanstack_query_core.QueryObserverResult<NoInfer<ChatInboxItem[]>, Error>>;
|
|
65
119
|
};
|
|
66
120
|
/** How many messages wait for you everywhere (for a badge), live. */
|
|
67
|
-
declare function useUnreadTotal(
|
|
121
|
+
declare function useUnreadTotal(opts?: {
|
|
122
|
+
excludeKinds?: string[];
|
|
123
|
+
}): number;
|
|
68
124
|
interface UseConversationOptions {
|
|
69
125
|
/** Mark messages read as they arrive while this is true (the thread is on screen). Default true. */
|
|
70
126
|
markRead?: boolean;
|
|
@@ -82,6 +138,14 @@ declare function useConversation(conversationId: string | null | undefined, opts
|
|
|
82
138
|
canPost: boolean;
|
|
83
139
|
/** Your role and posting rights are still loading: show the composer as waiting, not refused. */
|
|
84
140
|
accessLoading: boolean;
|
|
141
|
+
/** The conversation itself is still loading (it settles to `null` when you can't see it). */
|
|
142
|
+
conversationLoading: boolean;
|
|
143
|
+
/** Your role couldn't be loaded (offline): offer `refetchAccess`, don't say "can't post". */
|
|
144
|
+
accessError: Error | null;
|
|
145
|
+
refetchAccess: (options?: _tanstack_query_core.RefetchOptions) => Promise<_tanstack_query_core.QueryObserverResult<NoInfer<{
|
|
146
|
+
role: ChatRole | null;
|
|
147
|
+
canPost: boolean;
|
|
148
|
+
}>, Error>>;
|
|
85
149
|
/** The kind's rules (max members, threads, who posts). */
|
|
86
150
|
kind: NonNullable<NoInfer<ChatKindRules | null>> | null;
|
|
87
151
|
/** May you pin here: owners and admins, or anyone in a two-person conversation. */
|
|
@@ -95,11 +159,14 @@ declare function useConversation(conversationId: string | null | undefined, opts
|
|
|
95
159
|
hasEarlier: boolean;
|
|
96
160
|
loadingEarlier: boolean;
|
|
97
161
|
loadEarlier: () => Promise<void>;
|
|
162
|
+
loadUntil: (seq: number) => Promise<boolean>;
|
|
98
163
|
/** Where to draw the "New" line, from what you had read when it opened. */
|
|
99
164
|
firstUnreadId: string | null;
|
|
100
165
|
activity: ChatActivity[];
|
|
101
166
|
signalTyping: () => void;
|
|
102
167
|
signalRecording: () => void;
|
|
168
|
+
/** Tells the others you are recording a video (throttled). */
|
|
169
|
+
signalRecordingVideo: () => void;
|
|
103
170
|
markRead: () => Promise<void>;
|
|
104
171
|
send: (input: Omit<SendInput, "conversationId" | "clientId">, files?: LocalFile[]) => Promise<string>;
|
|
105
172
|
retry: (clientId: string) => Promise<void>;
|
|
@@ -133,5 +200,80 @@ declare function useStartConversation(): (kind: string, memberIds: string[], opt
|
|
|
133
200
|
subjectType?: string;
|
|
134
201
|
subjectId?: string;
|
|
135
202
|
}) => Promise<string>;
|
|
203
|
+
/**
|
|
204
|
+
* A conversation's topics, live (set_topic's hint refreshes them), and `setTopic` for owners
|
|
205
|
+
* and admins: add one (`setTopic("week-1", { title: "Week 1" })`), close or reopen it.
|
|
206
|
+
*/
|
|
207
|
+
declare function useTopics(conversationId: string | null | undefined): {
|
|
208
|
+
topics: ChatTopic[];
|
|
209
|
+
isLoading: boolean;
|
|
210
|
+
error: Error | null;
|
|
211
|
+
setTopic: (topic: string, input?: TopicInput) => Promise<void>;
|
|
212
|
+
refetch: (options?: _tanstack_query_core.RefetchOptions) => Promise<_tanstack_query_core.QueryObserverResult<NoInfer<ChatTopic[]>, Error>>;
|
|
213
|
+
};
|
|
214
|
+
/**
|
|
215
|
+
* Your scheduled messages (in one conversation, or all), soonest first, with `schedule` and
|
|
216
|
+
* `cancel`. `schedule` uploads byte files first (`LocalFile.data` a Blob or ArrayBuffer; a
|
|
217
|
+
* native URI goes through the provider's `readFile`), then schedules them with the message.
|
|
218
|
+
*/
|
|
219
|
+
declare function useScheduled(conversationId?: string | null, opts?: {
|
|
220
|
+
enabled?: boolean;
|
|
221
|
+
}): {
|
|
222
|
+
items: ScheduledMessage[];
|
|
223
|
+
isLoading: boolean;
|
|
224
|
+
error: Error | null;
|
|
225
|
+
schedule: (input: Omit<ScheduleInput, "clientId"> & {
|
|
226
|
+
clientId?: string;
|
|
227
|
+
}, files?: LocalFile[]) => Promise<string>;
|
|
228
|
+
cancel: (id: string) => Promise<void>;
|
|
229
|
+
refetch: (options?: _tanstack_query_core.RefetchOptions) => Promise<_tanstack_query_core.QueryObserverResult<NoInfer<ScheduledMessage[]>, Error>>;
|
|
230
|
+
};
|
|
231
|
+
/**
|
|
232
|
+
* Availability: yours (`mine`, `setMine`) and, given a conversation, its members' (`members`,
|
|
233
|
+
* `forUser`). Pair with `awayLine` and `isWithinWorkingHours` from the core.
|
|
234
|
+
*/
|
|
235
|
+
declare function useAvailability(conversationId?: string | null): {
|
|
236
|
+
mine: NonNullable<NoInfer<ChatAvailability | null>> | null;
|
|
237
|
+
mineLoading: boolean;
|
|
238
|
+
setMine: (input: AvailabilityInput) => Promise<void>;
|
|
239
|
+
members: ChatAvailability[];
|
|
240
|
+
/** Everyone else's, without yours. */
|
|
241
|
+
others: ChatAvailability[];
|
|
242
|
+
forUser: (id: string) => ChatAvailability | null;
|
|
243
|
+
isLoading: boolean;
|
|
244
|
+
};
|
|
245
|
+
/** Sends one message into many conversations (replies come back privately in each). */
|
|
246
|
+
declare function useBroadcast(): {
|
|
247
|
+
send: (conversationIds: string[], body: string, opts?: {
|
|
248
|
+
silent?: boolean;
|
|
249
|
+
clientId?: string;
|
|
250
|
+
}) => Promise<string[]>;
|
|
251
|
+
sending: boolean;
|
|
252
|
+
};
|
|
253
|
+
/** The value, once it has stopped changing for `ms`. */
|
|
254
|
+
declare function useDebouncedValue<T>(value: T, ms: number): T;
|
|
255
|
+
/** Search, debounced (250 ms by default), in one conversation or all of yours. Queries under two characters return nothing. */
|
|
256
|
+
declare function useSearch(query: string, opts?: {
|
|
257
|
+
conversationId?: string | null;
|
|
258
|
+
debounceMs?: number;
|
|
259
|
+
limit?: number;
|
|
260
|
+
}): {
|
|
261
|
+
hits: ChatSearchHit[];
|
|
262
|
+
/** The query the hits are for. */
|
|
263
|
+
query: string;
|
|
264
|
+
/** Typing, or fetching: results are on their way. */
|
|
265
|
+
isSearching: boolean;
|
|
266
|
+
error: Error | null;
|
|
267
|
+
};
|
|
268
|
+
/** At most this many link-preview reads at once, per client. */
|
|
269
|
+
declare const LINK_PREVIEW_CONCURRENCY = 4;
|
|
270
|
+
/**
|
|
271
|
+
* Link previews for these messages, by message id, in link order (only those the server has
|
|
272
|
+
* fetched). Pass the messages whose text has links (`extractLinks(body).length > 0`). One query
|
|
273
|
+
* per message, so a new message asks only for its own, and at most LINK_PREVIEW_CONCURRENCY
|
|
274
|
+
* run at once. One with none yet is asked again a few times, since the runner fills them
|
|
275
|
+
* moments after it lands.
|
|
276
|
+
*/
|
|
277
|
+
declare function useLinkPreviews(messageIds: (string | null | undefined)[]): Record<string, ChatLinkPreview[]>;
|
|
136
278
|
|
|
137
|
-
export { type ChatPerson, ChatProvider, type ChatProviderProps, type ConversationState, LocalFile, QueuedMessage, ThreadItem, type UseConversationOptions, belongsTo, chatKeys, useChat, useConversation, useFileUrls, useInbox, useMessageActions, usePeople, usePerson, usePins, useStartConversation, useUnreadTotal };
|
|
279
|
+
export { CATCH_UP_MAX_PAGES, CATCH_UP_PAGE, type ChatAttachmentKind, type ChatPerson, ChatProvider, type ChatProviderProps, type ChatVideoUpload, type ConversationState, LINK_PREVIEW_CONCURRENCY, LocalFile, type MessagesData, QueuedMessage, ThreadItem, type UseConversationOptions, belongsTo, chatKeys, useAvailability, useBroadcast, useChat, useConversation, useDebouncedValue, useFileUrls, useInbox, useLinkPreviews, useMessageActions, usePeople, usePerson, usePins, useScheduled, useSearch, useStartConversation, useTopics, useUnreadTotal };
|
package/dist/react.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
export { ChatProvider, belongsTo, chatKeys, useChat, useConversation, useFileUrls, useInbox, useMessageActions, usePeople, usePerson, usePins, useStartConversation, useUnreadTotal } from './chunk-
|
|
2
|
-
import './chunk-
|
|
3
|
-
import './chunk-
|
|
1
|
+
export { CATCH_UP_MAX_PAGES, CATCH_UP_PAGE, ChatProvider, LINK_PREVIEW_CONCURRENCY, belongsTo, chatKeys, useAvailability, useBroadcast, useChat, useConversation, useDebouncedValue, useFileUrls, useInbox, useLinkPreviews, useMessageActions, usePeople, usePerson, usePins, useScheduled, useSearch, useStartConversation, useTopics, useUnreadTotal } from './chunk-PZTOY2LY.js';
|
|
2
|
+
import './chunk-5D5A7I4Q.js';
|
|
3
|
+
import './chunk-7S6HYNWW.js';
|
|
4
4
|
//# sourceMappingURL=react.js.map
|
|
5
5
|
//# sourceMappingURL=react.js.map
|