@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
|
@@ -2,7 +2,7 @@ import { SupabaseClient } from '@supabase/supabase-js';
|
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* @feat:chat
|
|
5
|
-
* The chat contract: what the genesis_chat schema (
|
|
5
|
+
* The chat contract: what the genesis_chat schema (migrations 0001 and 0002) stores, in
|
|
6
6
|
* the app's words. Everything here is plain data, shared by web, native and
|
|
7
7
|
* the server.
|
|
8
8
|
*/
|
|
@@ -64,6 +64,11 @@ interface ChatMessage {
|
|
|
64
64
|
createdAt: string;
|
|
65
65
|
editedAt: string | null;
|
|
66
66
|
deletedAt: string | null;
|
|
67
|
+
/**
|
|
68
|
+
* What moderation said (migration 0002): `hidden` messages reach only their sender and the
|
|
69
|
+
* conversation's observers; `flagged` ones are visible to everyone and reported to observers.
|
|
70
|
+
*/
|
|
71
|
+
moderation?: "flagged" | "hidden" | null;
|
|
67
72
|
attachments: ChatAttachment[];
|
|
68
73
|
reactions: ChatReaction[];
|
|
69
74
|
}
|
|
@@ -174,6 +179,8 @@ interface PendingMessage {
|
|
|
174
179
|
createdAt: string;
|
|
175
180
|
status: "sending" | "failed";
|
|
176
181
|
error?: string;
|
|
182
|
+
/** The server refused it (not allowed, bad data): only a manual retry sends it again. */
|
|
183
|
+
permanent?: boolean;
|
|
177
184
|
/** Local previews for files still uploading (object URLs or file URIs). */
|
|
178
185
|
previews?: Record<number, string>;
|
|
179
186
|
/** What each file is, in order, so a pending bubble can draw it (a voice note's duration and waveform, a file's name). */
|
|
@@ -215,10 +222,87 @@ interface ChatActivity {
|
|
|
215
222
|
activity: "typing" | "recording-voice" | "recording-video";
|
|
216
223
|
at: number;
|
|
217
224
|
}
|
|
225
|
+
/** A named sub-thread of a conversation (a cohort's lesson threads). Messages join one through `topic`. */
|
|
226
|
+
interface ChatTopic {
|
|
227
|
+
conversationId: string;
|
|
228
|
+
/** The key messages carry in `topic`. */
|
|
229
|
+
topic: string;
|
|
230
|
+
title: string;
|
|
231
|
+
position: number;
|
|
232
|
+
/** Set when closed: only owners, admins and observers post in it then. */
|
|
233
|
+
closedAt: string | null;
|
|
234
|
+
createdBy: string | null;
|
|
235
|
+
createdAt: string;
|
|
236
|
+
}
|
|
237
|
+
/** What `setTopic` changes; anything left out keeps its value (a new topic's title is its key). */
|
|
238
|
+
interface TopicInput {
|
|
239
|
+
title?: string;
|
|
240
|
+
position?: number;
|
|
241
|
+
closed?: boolean;
|
|
242
|
+
}
|
|
243
|
+
/** A message to send later, as its sender. Only its sender reads it. */
|
|
244
|
+
interface ScheduledMessage {
|
|
245
|
+
id: string;
|
|
246
|
+
conversationId: string;
|
|
247
|
+
clientId: string;
|
|
248
|
+
body: string;
|
|
249
|
+
attachments: AttachmentInput[];
|
|
250
|
+
replyToId: string | null;
|
|
251
|
+
topic: string | null;
|
|
252
|
+
mentions: string[];
|
|
253
|
+
silent: boolean;
|
|
254
|
+
sendAt: string;
|
|
255
|
+
sentMessageId: string | null;
|
|
256
|
+
cancelledAt: string | null;
|
|
257
|
+
/** Why it couldn't be sent when due (the sender left the conversation, say). */
|
|
258
|
+
error: string | null;
|
|
259
|
+
createdAt: string;
|
|
260
|
+
status: "scheduled" | "sent" | "cancelled" | "failed";
|
|
261
|
+
}
|
|
262
|
+
/** Between a minute and a year ahead. Files in `attachments` are uploaded first, as for `send`. */
|
|
263
|
+
interface ScheduleInput extends Omit<SendInput, "threadRootId" | "visibility"> {
|
|
264
|
+
sendAt: string | Date;
|
|
265
|
+
}
|
|
266
|
+
type Weekday = "mon" | "tue" | "wed" | "thu" | "fri" | "sat" | "sun";
|
|
267
|
+
/** Working hours per weekday as `[["09:00","17:00"]]`, 24-hour local times; a missing day is not working. An end at or before its start runs past midnight. */
|
|
268
|
+
type WorkingHours = Partial<Record<Weekday, [string, string][]>>;
|
|
269
|
+
/** A person's away message and working hours. */
|
|
270
|
+
interface ChatAvailability {
|
|
271
|
+
userId: string;
|
|
272
|
+
awayMessage: string | null;
|
|
273
|
+
/** Away until then; with an away message and no date, away until they clear it. */
|
|
274
|
+
awayUntil: string | null;
|
|
275
|
+
/** An IANA zone (`America/New_York`); hours are read in it. */
|
|
276
|
+
timeZone: string | null;
|
|
277
|
+
hours: WorkingHours | null;
|
|
278
|
+
}
|
|
279
|
+
type AvailabilityInput = Partial<Omit<ChatAvailability, "userId">>;
|
|
280
|
+
/** One search result. `snippet` marks the matched words with « and » (the text's own « and » arrive as ‹ and ›, so marks are always real). */
|
|
281
|
+
interface ChatSearchHit {
|
|
282
|
+
messageId: string;
|
|
283
|
+
conversationId: string;
|
|
284
|
+
seq: number;
|
|
285
|
+
senderId: string | null;
|
|
286
|
+
createdAt: string;
|
|
287
|
+
snippet: string;
|
|
288
|
+
/** Found in a voice note's or video's transcript, not the text. */
|
|
289
|
+
inTranscript: boolean;
|
|
290
|
+
}
|
|
291
|
+
/** Open Graph data for a link (fetched by the server's runner). Plain text: never render it as HTML. */
|
|
292
|
+
interface ChatLinkPreview {
|
|
293
|
+
url: string;
|
|
294
|
+
status: "ok" | "failed" | "blocked";
|
|
295
|
+
title: string | null;
|
|
296
|
+
description: string | null;
|
|
297
|
+
/** Always https when present. */
|
|
298
|
+
imageUrl: string | null;
|
|
299
|
+
siteName: string | null;
|
|
300
|
+
fetchedAt: string;
|
|
301
|
+
}
|
|
218
302
|
|
|
219
303
|
/**
|
|
220
304
|
* @feat:chat
|
|
221
|
-
* The chat client: the app's own Supabase (
|
|
305
|
+
* The chat client: the app's own Supabase (migrations 0001 and 0002, the genesis_chat
|
|
222
306
|
* schema) under row level security. Reads are table selects; every write is a
|
|
223
307
|
* genesis_chat function. Live updates are hints on private Realtime topics,
|
|
224
308
|
* after which the client fetches again, so nothing is trusted from the wire.
|
|
@@ -239,10 +323,21 @@ declare class ChatError extends Error {
|
|
|
239
323
|
get rateLimited(): boolean;
|
|
240
324
|
/** Worth trying again: the network, not the database, said no. */
|
|
241
325
|
get transient(): boolean;
|
|
326
|
+
/**
|
|
327
|
+
* Sending it again won't help: the database refused what was sent (not allowed 42501, bad
|
|
328
|
+
* data 22xxx such as 22023, a conflict 23xxx such as 23505, another refusal 42xxx, or a
|
|
329
|
+
* function's own `raise` P0001). A person may still retry by hand; nothing retries it alone.
|
|
330
|
+
*/
|
|
331
|
+
get permanent(): boolean;
|
|
242
332
|
}
|
|
243
333
|
type Row = Record<string, unknown>;
|
|
244
334
|
declare function toAttachment(r: Row): ChatAttachment;
|
|
245
335
|
declare function toMessage(r: Row): ChatMessage;
|
|
336
|
+
declare function toTopic(r: Row): ChatTopic;
|
|
337
|
+
declare function toScheduled(r: Row): ScheduledMessage;
|
|
338
|
+
declare function toAvailability(r: Row): ChatAvailability;
|
|
339
|
+
declare function toSearchHit(r: Row): ChatSearchHit;
|
|
340
|
+
declare function toLinkPreview(r: Row): ChatLinkPreview;
|
|
246
341
|
interface MessagePage {
|
|
247
342
|
messages: ChatMessage[];
|
|
248
343
|
/** More, older messages exist before the first one. */
|
|
@@ -255,14 +350,25 @@ interface ChatClientOptions {
|
|
|
255
350
|
interface Subscription {
|
|
256
351
|
unsubscribe(): void;
|
|
257
352
|
}
|
|
353
|
+
interface ConversationHandlers {
|
|
354
|
+
onSignal: (s: ChatSignal) => void;
|
|
355
|
+
onActivity?: (a: ChatActivity) => void;
|
|
356
|
+
/** Every join, the first included: catch up on what arrived before the channel was live. */
|
|
357
|
+
onJoin?: () => void;
|
|
358
|
+
/** Re-joins only. Prefer `onJoin`. */
|
|
359
|
+
onReconnect?: () => void;
|
|
360
|
+
}
|
|
258
361
|
interface ConversationChannel extends Subscription {
|
|
259
362
|
/** Tell the others you are typing or recording (throttle to once every 3 seconds). */
|
|
260
363
|
signal(activity: ChatActivity["activity"]): void;
|
|
261
364
|
}
|
|
262
365
|
declare function createChatClient(supabase: ChatSupabase, options?: ChatClientOptions): {
|
|
263
366
|
supabase: ChatSupabase;
|
|
367
|
+
/** Your conversations: one `kind`, several `kinds`, or all but `excludeKinds` (e.g. Messages without `support`). */
|
|
264
368
|
inbox(opts?: {
|
|
265
369
|
kind?: string;
|
|
370
|
+
kinds?: string[];
|
|
371
|
+
excludeKinds?: string[];
|
|
266
372
|
archived?: boolean;
|
|
267
373
|
limit?: number;
|
|
268
374
|
before?: string;
|
|
@@ -272,7 +378,10 @@ declare function createChatClient(supabase: ChatSupabase, options?: ChatClientOp
|
|
|
272
378
|
limit?: number;
|
|
273
379
|
before?: string;
|
|
274
380
|
}): Promise<Row[]>;
|
|
275
|
-
|
|
381
|
+
/** Unread across your conversations (for a badge), leaving out `excludeKinds` to match an inbox that does. */
|
|
382
|
+
unreadTotal(opts?: {
|
|
383
|
+
excludeKinds?: string[];
|
|
384
|
+
}): Promise<number>;
|
|
276
385
|
conversation(id: string): Promise<ChatConversation | null>;
|
|
277
386
|
/** A kind's rules (how many members, who posts, threads), for what the UI offers. */
|
|
278
387
|
kind(kind: string): Promise<ChatKindRules | null>;
|
|
@@ -320,6 +429,40 @@ declare function createChatClient(supabase: ChatSupabase, options?: ChatClientOp
|
|
|
320
429
|
pins(conversationId: string): Promise<string[]>;
|
|
321
430
|
save(messageId: string, on?: boolean, note?: string): Promise<void>;
|
|
322
431
|
report(messageId: string, reason: "spam" | "harassment" | "safety" | "other", note?: string): Promise<string>;
|
|
432
|
+
/** A conversation's topics, in order (position, then key). */
|
|
433
|
+
topics(conversationId: string): Promise<ChatTopic[]>;
|
|
434
|
+
/** Adds a topic, or renames, reorders, closes (`closed: true`) or reopens it. Owners and admins. */
|
|
435
|
+
setTopic(conversationId: string, topic: string, input?: TopicInput): Promise<void>;
|
|
436
|
+
/** Schedules a message (a minute to a year ahead) and returns its id. Safe to retry with the same clientId. */
|
|
437
|
+
schedule(input: ScheduleInput): Promise<string>;
|
|
438
|
+
/** Your messages still waiting to go (and ones that failed when due), soonest first; in one conversation or all. */
|
|
439
|
+
scheduled(conversationId?: string): Promise<ScheduledMessage[]>;
|
|
440
|
+
cancelScheduled(id: string): Promise<void>;
|
|
441
|
+
/** The away message and hours of a conversation's members who set them (not observers). */
|
|
442
|
+
availabilityFor(conversationId: string): Promise<ChatAvailability[]>;
|
|
443
|
+
/** Your own away message and hours, or null when never set. */
|
|
444
|
+
myAvailability(): Promise<ChatAvailability | null>;
|
|
445
|
+
/** Replaces your away message and hours (a field left out is cleared). */
|
|
446
|
+
setAvailability(input: AvailabilityInput): Promise<void>;
|
|
447
|
+
/**
|
|
448
|
+
* Sends one text message into each of these conversations where you may post (a coach to
|
|
449
|
+
* each client's direct conversation), so replies come back privately. Text only. Safe to
|
|
450
|
+
* retry with the same clientId. Returns the ids of the messages sent.
|
|
451
|
+
*/
|
|
452
|
+
broadcast(conversationIds: string[], clientId: string, body: string, opts?: {
|
|
453
|
+
silent?: boolean;
|
|
454
|
+
}): Promise<string[]>;
|
|
455
|
+
/** Messages (and transcripts) you can read that match, newest first: in one conversation or all of yours. Two characters at least. */
|
|
456
|
+
search(query: string, conversationId?: string | null, opts?: {
|
|
457
|
+
limit?: number;
|
|
458
|
+
}): Promise<ChatSearchHit[]>;
|
|
459
|
+
/**
|
|
460
|
+
* The previews the server has fetched for the links in these messages, by message id (only
|
|
461
|
+
* `ok` ones; links not fetched yet are left out). Read through link_previews_for, one call
|
|
462
|
+
* per message (up to 6 at once), which answers only for messages you can read: the preview
|
|
463
|
+
* table itself is closed, since a URL can carry a secret.
|
|
464
|
+
*/
|
|
465
|
+
linkPreviewsFor(messageIds: string[]): Promise<Record<string, ChatLinkPreview[]>>;
|
|
323
466
|
/**
|
|
324
467
|
* Uploads a file into the conversation's folder for the signed-in person and
|
|
325
468
|
* returns its path, ready to attach. Resumable for big files is the native
|
|
@@ -335,15 +478,13 @@ declare function createChatClient(supabase: ChatSupabase, options?: ChatClientOp
|
|
|
335
478
|
/** Your inbox's live hints (a new message anywhere you are, a membership change). */
|
|
336
479
|
subscribeInbox(userId: string, onSignal: (s: ChatSignal) => void): Subscription;
|
|
337
480
|
/**
|
|
338
|
-
* A conversation's live hints, plus who is typing or recording. `
|
|
339
|
-
*
|
|
481
|
+
* A conversation's live hints, plus who is typing or recording. `onJoin` runs every
|
|
482
|
+
* time the channel joins, the first time included: the moment to fetch what arrived
|
|
483
|
+
* before the subscription was live. `onReconnect` (kept for older callers) runs on
|
|
484
|
+
* re-joins only.
|
|
340
485
|
*/
|
|
341
|
-
subscribeConversation(conversationId: string, me: string, handlers:
|
|
342
|
-
onSignal: (s: ChatSignal) => void;
|
|
343
|
-
onActivity?: (a: ChatActivity) => void;
|
|
344
|
-
onReconnect?: () => void;
|
|
345
|
-
}): ConversationChannel;
|
|
486
|
+
subscribeConversation(conversationId: string, me: string, handlers: ConversationHandlers): ConversationChannel;
|
|
346
487
|
};
|
|
347
488
|
type ChatClient = ReturnType<typeof createChatClient>;
|
|
348
489
|
|
|
349
|
-
export { type
|
|
490
|
+
export { type AttachmentInput as A, type PendingMessage as B, type ChatAvailability as C, type ScheduledMessage as D, type SendInput as E, type Subscription as F, conversationTopic as G, createChatClient as H, toAttachment as I, toAvailability as J, toLinkPreview as K, toMessage as L, type MessagePage as M, toScheduled as N, toSearchHit as O, type PendingFile as P, toTopic as Q, userTopic as R, type ScheduleInput as S, type TopicInput as T, type Weekday as W, 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,185 +1,100 @@
|
|
|
1
|
-
import {
|
|
2
|
-
export {
|
|
1
|
+
import { W as Weekday, C as ChatAvailability, a as WorkingHours } from './client-DMa2j7kz.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, M as MessagePage, P as PendingFile, B as PendingMessage, S as ScheduleInput, D as ScheduledMessage, E as SendInput, F as Subscription, T as TopicInput, G as conversationTopic, H as createChatClient, I as toAttachment, J as toAvailability, K as toLinkPreview, L as toMessage, N as toScheduled, O as toSearchHit, Q as toTopic, R as userTopic } from './client-DMa2j7kz.js';
|
|
3
|
+
export { A as ALLOWED_EXTENSIONS, C as CHAT_LIMITS, L as LocalFile, O as Outbox, a as OutboxOptions, b as OutboxStore, P as PLAYBACK_RATES, Q as QueuedMessage, c as attachmentKindFor, d as createOutbox, f as fileExtension, e as formatDuration, i as isAllowedExtension, m as memoryOutboxStore, n as nextPlaybackRate, r as randomId, g as recordingLimitMs, h as releaseObjectUrl, w as waveformFromMetering, j as waveformPeaks } from './outbox-B0y3phE0.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-DWXHKPdw.js';
|
|
3
5
|
import '@supabase/supabase-js';
|
|
4
6
|
|
|
5
7
|
/**
|
|
6
8
|
* @feat:chat
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
9
|
+
* Availability, the same on every platform: is someone inside their working hours (read in
|
|
10
|
+
* their own time zone), are they away, and the one line a thread shows about it ("Mark
|
|
11
|
+
* replies Mon–Fri, 9–5 (Eastern)", "Away until Monday: Back Monday"). Pure: `now` is passed
|
|
12
|
+
* in, and time zones come from Intl.
|
|
10
13
|
*/
|
|
11
14
|
|
|
15
|
+
declare const WEEKDAYS: readonly Weekday[];
|
|
16
|
+
/** "09:30" → 570; a bad value (anything but such a string) → null. "24:00" is allowed as the end of a day. */
|
|
17
|
+
declare function minutesOf(hhmm: unknown): number | null;
|
|
18
|
+
/** At most this many ranges a day, as the database allows. */
|
|
19
|
+
declare const MAX_RANGES_PER_DAY = 4;
|
|
12
20
|
/**
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
21
|
+
* Working hours as they may safely be read: only mon..sun, each an array of `["HH:MM", "HH:MM"]`
|
|
22
|
+
* string pairs (at most four a day); every other day, range or value is dropped. Null when
|
|
23
|
+
* nothing is left. Hours come from other people, so they are never trusted as typed.
|
|
16
24
|
*/
|
|
17
|
-
declare function
|
|
18
|
-
/**
|
|
19
|
-
declare
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
declare function isAllowedExtension(ext: string): boolean;
|
|
23
|
-
/** What an upload becomes in a message. */
|
|
24
|
-
declare function attachmentKindFor(contentType: string, opts?: {
|
|
25
|
-
recordedVoice?: boolean;
|
|
26
|
-
}): AttachmentKind;
|
|
27
|
-
/** Default limits (decision 5): an app may lower them, not raise them past the bucket's 100 MB. */
|
|
28
|
-
declare const CHAT_LIMITS: {
|
|
29
|
-
/** Voice notes and videos, for members. */
|
|
30
|
-
readonly recordingMs: number;
|
|
31
|
-
/** For owners, admins and observers (coaches, staff). */
|
|
32
|
-
readonly staffRecordingMs: number;
|
|
33
|
-
readonly fileBytes: number;
|
|
34
|
-
readonly videoBytes: number;
|
|
35
|
-
readonly attachmentsPerMessage: 20;
|
|
36
|
-
readonly bodyChars: 10000;
|
|
25
|
+
declare function normalizeHours(raw: unknown): WorkingHours | null;
|
|
26
|
+
/** The weekday and minute of the day at `now` in `timeZone` (the device's zone when null or unknown). */
|
|
27
|
+
declare function localClock(now: Date, timeZone?: string | null): {
|
|
28
|
+
day: Weekday;
|
|
29
|
+
minutes: number;
|
|
37
30
|
};
|
|
38
|
-
/** The longest recording this role may make. */
|
|
39
|
-
declare function recordingLimitMs(role: string | null | undefined): number;
|
|
40
31
|
/**
|
|
41
|
-
*
|
|
42
|
-
*
|
|
43
|
-
*
|
|
32
|
+
* Is `now` inside these working hours, read in `timeZone`? No hours set means always.
|
|
33
|
+
* A range whose end is at or before its start runs overnight into the next day
|
|
34
|
+
* (`fri: [["22:00","02:00"]]` covers Friday 22:00 to Saturday 02:00).
|
|
44
35
|
*/
|
|
45
|
-
declare function
|
|
36
|
+
declare function isWithinWorkingHours(raw: WorkingHours | null | undefined, timeZone: string | null | undefined, now?: Date): boolean;
|
|
37
|
+
/** Away now: an away message with no end date, or an end date still ahead. */
|
|
38
|
+
declare function isAway(a: Pick<ChatAvailability, "awayMessage" | "awayUntil"> | null | undefined, now?: Date): boolean;
|
|
39
|
+
/** "Mon–Fri, 9–5", "Mon–Thu, 9–5; Fri, 9–1". Days with the same hours are grouped. Empty when none. */
|
|
40
|
+
declare function hoursSummary(raw: WorkingHours | null | undefined): string;
|
|
41
|
+
/** "Eastern" for America/New_York (the zone's generic name, less " Time"); the city when Intl has no name. */
|
|
42
|
+
declare function timeZoneLabel(timeZone: string | null | undefined, locale?: string): string;
|
|
43
|
+
/** "3:00 PM" today, "Monday" within the week, else "12 Mar". */
|
|
44
|
+
declare function untilLabel(iso: string, now?: Date, locale?: string, timeZone?: string | null): string;
|
|
45
|
+
interface AwayLineOptions {
|
|
46
|
+
now?: Date;
|
|
47
|
+
locale?: string;
|
|
48
|
+
/** Show the hours line even inside working hours (a profile, not a banner). */
|
|
49
|
+
always?: boolean;
|
|
50
|
+
}
|
|
46
51
|
/**
|
|
47
|
-
*
|
|
48
|
-
*
|
|
52
|
+
* The line a thread shows about someone, or null when they are around:
|
|
53
|
+
* - away with a date: "Away until Monday: Back Monday" (the away message after the colon);
|
|
54
|
+
* - away with no date: "Mark is away: On a retreat";
|
|
55
|
+
* - outside working hours: "Mark replies Mon–Fri, 9–5 (Eastern)".
|
|
49
56
|
*/
|
|
50
|
-
declare function
|
|
51
|
-
/**
|
|
52
|
-
declare function
|
|
53
|
-
/** Playback speeds offered for voice and video (free for everyone, decision 5). */
|
|
54
|
-
declare const PLAYBACK_RATES: readonly [1, 1.5, 2];
|
|
55
|
-
declare function nextPlaybackRate(rate: number): number;
|
|
56
|
-
|
|
57
|
-
/**
|
|
58
|
-
* @feat:chat
|
|
59
|
-
* Pure thread logic, the same on every platform: merging the server's messages
|
|
60
|
-
* with ones still on their way, grouping a run of messages from one sender,
|
|
61
|
-
* day dividers, the unread line, reactions by emoji, and the typing line.
|
|
62
|
-
*/
|
|
63
|
-
|
|
64
|
-
type ThreadItem = {
|
|
65
|
-
type: "message";
|
|
66
|
-
message: ChatMessage;
|
|
67
|
-
pending?: undefined;
|
|
68
|
-
} | {
|
|
69
|
-
type: "pending";
|
|
70
|
-
pending: PendingMessage;
|
|
71
|
-
message?: undefined;
|
|
72
|
-
};
|
|
57
|
+
declare function awayLine(a: ChatAvailability | null | undefined, name: string, opts?: AwayLineOptions): string | null;
|
|
58
|
+
/** "Sam", "Sam and Lee", "Sam, Lee and 3 others": at most two names. */
|
|
59
|
+
declare function namesLine(names: string[]): string;
|
|
73
60
|
/**
|
|
74
|
-
* The
|
|
75
|
-
*
|
|
76
|
-
*
|
|
61
|
+
* The line for several people (a group's members): one person's full `awayLine`, or for more
|
|
62
|
+
* "Sam and Lee are away", "Sam, Lee and 2 others are outside their hours", or "… are away or
|
|
63
|
+
* outside their hours" when it's a mix. Null when everyone is around.
|
|
77
64
|
*/
|
|
78
|
-
declare function
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
declare function itemTime(item: ThreadItem): string;
|
|
83
|
-
/** Runs of one sender within five minutes share a header (name, avatar). */
|
|
84
|
-
declare function startsGroup(items: ThreadItem[], index: number, gapMs?: number): boolean;
|
|
85
|
-
declare function sameDay(a: string, b: string): boolean;
|
|
86
|
-
/** A day divider goes before this item. */
|
|
87
|
-
declare function startsDay(items: ThreadItem[], index: number): boolean;
|
|
88
|
-
/** "Today", "Yesterday", "Monday", or "12 Mar 2026". */
|
|
89
|
-
declare function dayLabel(iso: string, now?: Date, locale?: string): string;
|
|
90
|
-
/** The first message after what you had read, from someone else: where "New" goes. */
|
|
91
|
-
declare function firstUnreadId(messages: ChatMessage[], lastReadSeq: number, me: string): string | null;
|
|
92
|
-
interface ReactionSummary {
|
|
93
|
-
emoji: string;
|
|
94
|
-
count: number;
|
|
95
|
-
mine: boolean;
|
|
96
|
-
userIds: string[];
|
|
97
|
-
}
|
|
98
|
-
/** Reactions by emoji, most first, then in first-used order. */
|
|
99
|
-
declare function summarizeReactions(message: ChatMessage, me: string): ReactionSummary[];
|
|
100
|
-
/** Who is doing what now: activity older than six seconds has stopped. */
|
|
101
|
-
declare function currentActivity(activity: ChatActivity[], now?: number, staleMs?: number): ChatActivity[];
|
|
102
|
-
/** "Sam is typing…", "Sam and Lee are typing…", "Sam is recording a voice message…". */
|
|
103
|
-
declare function activityLine(activity: ChatActivity[], nameOf: (userId: string) => string): string | null;
|
|
104
|
-
/** Sends activity at most once every `everyMs`. */
|
|
105
|
-
declare function throttle(fn: () => void, everyMs?: number): () => void;
|
|
106
|
-
/** The ids @mentioned in markdown written as `@[Name](user:<uuid>)`. */
|
|
107
|
-
declare function parseMentions(body: string): string[];
|
|
108
|
-
/** A one-line preview: text, or what was attached. */
|
|
109
|
-
declare function previewText(body: string, attachment: string | null | undefined, deleted?: boolean): string;
|
|
65
|
+
declare function awaySummary(people: {
|
|
66
|
+
availability: ChatAvailability | null | undefined;
|
|
67
|
+
name: string;
|
|
68
|
+
}[], opts?: AwayLineOptions): string | null;
|
|
110
69
|
|
|
111
70
|
/**
|
|
112
71
|
* @feat:chat
|
|
113
|
-
*
|
|
114
|
-
*
|
|
115
|
-
*
|
|
116
|
-
*
|
|
117
|
-
* localStorage on web, MMKV or SQLite on native), behind OutboxStore.
|
|
72
|
+
* Small pure helpers for migration 0002's features, shared by every platform: the links a
|
|
73
|
+
* message's text carries (the same rule the database uses to queue previews), https checks
|
|
74
|
+
* for preview images, search snippets split at their « » marks, scheduling quick picks, and
|
|
75
|
+
* topic keys.
|
|
118
76
|
*/
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
/** A preview to show while it uploads (an object URL, a file URI). */
|
|
127
|
-
previewUrl?: string;
|
|
128
|
-
/** Known up front: a voice note's duration and waveform, a photo's size. */
|
|
129
|
-
meta?: Partial<Omit<AttachmentInput, "path" | "kind">> & {
|
|
130
|
-
kind?: AttachmentInput["kind"];
|
|
131
|
-
};
|
|
77
|
+
/** The https links in a message's text that get a preview, at most three, as genesis_chat.message_links finds them. */
|
|
78
|
+
declare function extractLinks(body: string, max?: number): string[];
|
|
79
|
+
/** An absolute https URL with a host: the only kind a preview image may load from. */
|
|
80
|
+
declare function isHttpsUrl(url: string | null | undefined): url is string;
|
|
81
|
+
interface SnippetPart {
|
|
82
|
+
text: string;
|
|
83
|
+
match: boolean;
|
|
132
84
|
}
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
lostFiles?: number;
|
|
139
|
-
attempts: number;
|
|
85
|
+
/** "a «word» here" → [{a }, {word, match}, { here}]. Unbalanced marks are kept as text. */
|
|
86
|
+
declare function snippetParts(snippet: string): SnippetPart[];
|
|
87
|
+
interface QuickPick {
|
|
88
|
+
label: string;
|
|
89
|
+
at: Date;
|
|
140
90
|
}
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
store?: OutboxStore;
|
|
150
|
-
/** Reads a native file URI into bytes for upload. */
|
|
151
|
-
readFile?: (uri: string) => Promise<Blob | ArrayBuffer>;
|
|
152
|
-
/** Upload hook, e.g. resumable uploads on native. Defaults to client.upload. */
|
|
153
|
-
upload?: (conversationId: string, file: LocalFile) => Promise<string>;
|
|
154
|
-
/** Called with every change, for the UI. */
|
|
155
|
-
onChange?: (queue: QueuedMessage[]) => void;
|
|
156
|
-
/** Called when a message lands. */
|
|
157
|
-
onSent?: (message: ChatMessage, clientId: string) => void;
|
|
158
|
-
/** Makes client ids. Default: a random UUID (works where crypto.randomUUID is missing). */
|
|
159
|
-
newId?: () => string;
|
|
160
|
-
/**
|
|
161
|
-
* Keeps a file held as bytes (a pasted image, a recording) between launches: write it
|
|
162
|
-
* somewhere and return a URI `readFile` can read (native: the app's cache directory).
|
|
163
|
-
* Without it, such a file isn't saved, and after a relaunch its message asks for it again.
|
|
164
|
-
*/
|
|
165
|
-
persistFile?: (file: LocalFile) => Promise<string>;
|
|
166
|
-
}
|
|
167
|
-
declare function createOutbox(opts: OutboxOptions): {
|
|
168
|
-
/** Queues a message; it shows at once and sends in order. Returns its clientId. */
|
|
169
|
-
send(input: Omit<SendInput, "clientId"> & {
|
|
170
|
-
clientId?: string;
|
|
171
|
-
}, files?: LocalFile[]): Promise<string>;
|
|
172
|
-
retry(clientId: string): Promise<void>;
|
|
173
|
-
/** Gives a message whose files were lost on a relaunch its files again, and sends it. */
|
|
174
|
-
reattach(clientId: string, files: LocalFile[]): Promise<void>;
|
|
175
|
-
/** Retries every failed message (after the connection comes back). */
|
|
176
|
-
retryAll(): Promise<void>;
|
|
177
|
-
discard(clientId: string): Promise<void>;
|
|
178
|
-
pending(conversationId?: string): PendingMessage[];
|
|
179
|
-
/** A new client id, made the way this outbox makes them. */
|
|
180
|
-
newId: typeof randomId;
|
|
181
|
-
load: () => Promise<void>;
|
|
182
|
-
};
|
|
183
|
-
type Outbox = ReturnType<typeof createOutbox>;
|
|
91
|
+
/** "Tomorrow, 9:00 AM" and "Monday, 9:00 AM" (the next Monday after tomorrow; one pick when they're the same day). */
|
|
92
|
+
declare function scheduleQuickPicks(now?: Date, locale?: string): QuickPick[];
|
|
93
|
+
/** When a scheduled message goes: "Tomorrow, 9:00 AM", "Mon 12 Oct, 9:00 AM". */
|
|
94
|
+
declare function scheduleLabel(iso: string | Date, now?: Date, locale?: string): string;
|
|
95
|
+
/** The send time the database accepts: at least a minute and at most a year ahead. */
|
|
96
|
+
declare function isSchedulable(at: Date, now?: Date): boolean;
|
|
97
|
+
/** A topic's key from its title: "Week 1: Habits" → "week-1-habits" (at most 120 characters). */
|
|
98
|
+
declare function topicKey(title: string): string;
|
|
184
99
|
|
|
185
|
-
export {
|
|
100
|
+
export { type AwayLineOptions, ChatAvailability, MAX_RANGES_PER_DAY, type QuickPick, type SnippetPart, WEEKDAYS, Weekday, WorkingHours, awayLine, awaySummary, extractLinks, hoursSummary, isAway, isHttpsUrl, isSchedulable, isWithinWorkingHours, localClock, minutesOf, namesLine, normalizeHours, scheduleLabel, scheduleQuickPicks, snippetParts, timeZoneLabel, topicKey, untilLabel };
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
export {
|
|
2
|
-
export {
|
|
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-5D5A7I4Q.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, timeZoneLabel, toAttachment, toAvailability, toLinkPreview, toMessage, toScheduled, toSearchHit, toTopic, untilLabel, userTopic, waveformFromMetering, waveformPeaks } from './chunk-7S6HYNWW.js';
|
|
3
4
|
//# sourceMappingURL=index.js.map
|
|
4
5
|
//# sourceMappingURL=index.js.map
|