@ai-matrx/messaging 0.15.14 → 0.15.16
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +12 -0
- package/dist/index.cjs +446 -101
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +90 -50
- package/dist/index.d.ts +90 -50
- package/dist/index.js +446 -101
- package/dist/index.js.map +1 -1
- package/dist/react.cjs +447 -103
- package/dist/react.cjs.map +1 -1
- package/dist/react.d.cts +90 -50
- package/dist/react.d.ts +90 -50
- package/dist/react.js +447 -103
- package/dist/react.js.map +1 -1
- package/package.json +4 -4
package/dist/index.d.cts
CHANGED
|
@@ -552,6 +552,49 @@ declare const MESSAGING_EVENTS: {
|
|
|
552
552
|
readonly actionSettled: "mx.action.settled";
|
|
553
553
|
};
|
|
554
554
|
|
|
555
|
+
/**
|
|
556
|
+
* ONE error classification for the whole package (C22).
|
|
557
|
+
*
|
|
558
|
+
* The banned alternative is the host catching a PostgREST error and deciding
|
|
559
|
+
* for itself whether it was an auth blip, a permission denial, or a real bug —
|
|
560
|
+
* which is how the same three-branch `if` ends up copy-pasted into every
|
|
561
|
+
* consumer and drifts. Everything this package throws is a `MessagingError`
|
|
562
|
+
* with a stable `code`, and the two that hosts genuinely treat differently
|
|
563
|
+
* (`session-unavailable`, `forbidden`) say so in the type.
|
|
564
|
+
*
|
|
565
|
+
* The incident behind `session-unavailable`: a DM reader mounted before the
|
|
566
|
+
* access token existed, every RPC came back `42501`, and the app captured 909
|
|
567
|
+
* errors in 0.6 seconds. A missing session is a NORMAL lifecycle moment — it
|
|
568
|
+
* warns and retries; it is never a red error.
|
|
569
|
+
*/
|
|
570
|
+
type MessagingErrorCode = "session-unavailable" | "contention" | "forbidden" | "not-found" | "conflict" | "transport" | "invalid-response" | "write-not-applied" | "misconfigured"
|
|
571
|
+
/** A NEW conversation needs an organization to land in and none is selected. */
|
|
572
|
+
| "organization-required" | "unknown";
|
|
573
|
+
declare class MessagingError extends Error {
|
|
574
|
+
readonly code: MessagingErrorCode;
|
|
575
|
+
/** The remedy. Nothing fails silently, and nothing fails without saying what to do. */
|
|
576
|
+
readonly remedy: string;
|
|
577
|
+
readonly cause?: unknown;
|
|
578
|
+
constructor(code: MessagingErrorCode, message: string, remedy: string, cause?: unknown);
|
|
579
|
+
/** True when re-running the same call is the fix. */
|
|
580
|
+
get isRetryable(): boolean;
|
|
581
|
+
}
|
|
582
|
+
interface PostgrestErrorLike {
|
|
583
|
+
message: string;
|
|
584
|
+
code?: string | undefined;
|
|
585
|
+
details?: string | null | undefined;
|
|
586
|
+
}
|
|
587
|
+
/**
|
|
588
|
+
* THE ONE PLACE a raw PostgREST/transport error becomes a typed one. Called at
|
|
589
|
+
* every boundary in `repository.ts`; nothing else in the package inspects a raw
|
|
590
|
+
* error, and no consumer should ever have to.
|
|
591
|
+
*/
|
|
592
|
+
declare function normalizeMessagingError(error: PostgrestErrorLike | Error | unknown, operation: string): MessagingError;
|
|
593
|
+
/** A response whose SHAPE is wrong — the ingress boundary, not the wire. */
|
|
594
|
+
declare function invalidResponse(operation: string, detail: string): MessagingError;
|
|
595
|
+
/** A mutation that PostgREST accepted syntactically but applied to no row. */
|
|
596
|
+
declare function writeNotApplied(operation: string, detail: string): MessagingError;
|
|
597
|
+
|
|
555
598
|
/**
|
|
556
599
|
* THE OUTBOX — a message you typed is NEVER lost (R2, table-stakes law).
|
|
557
600
|
*
|
|
@@ -640,47 +683,6 @@ interface Outbox {
|
|
|
640
683
|
}
|
|
641
684
|
declare function createOutbox(options: OutboxOptions): Outbox;
|
|
642
685
|
|
|
643
|
-
/**
|
|
644
|
-
* ONE error classification for the whole package (C22).
|
|
645
|
-
*
|
|
646
|
-
* The banned alternative is the host catching a PostgREST error and deciding
|
|
647
|
-
* for itself whether it was an auth blip, a permission denial, or a real bug —
|
|
648
|
-
* which is how the same three-branch `if` ends up copy-pasted into every
|
|
649
|
-
* consumer and drifts. Everything this package throws is a `MessagingError`
|
|
650
|
-
* with a stable `code`, and the two that hosts genuinely treat differently
|
|
651
|
-
* (`session-unavailable`, `forbidden`) say so in the type.
|
|
652
|
-
*
|
|
653
|
-
* The incident behind `session-unavailable`: a DM reader mounted before the
|
|
654
|
-
* access token existed, every RPC came back `42501`, and the app captured 909
|
|
655
|
-
* errors in 0.6 seconds. A missing session is a NORMAL lifecycle moment — it
|
|
656
|
-
* warns and retries; it is never a red error.
|
|
657
|
-
*/
|
|
658
|
-
type MessagingErrorCode = "session-unavailable" | "contention" | "forbidden" | "not-found" | "conflict" | "transport" | "invalid-response" | "misconfigured"
|
|
659
|
-
/** A NEW conversation needs an organization to land in and none is selected. */
|
|
660
|
-
| "organization-required" | "unknown";
|
|
661
|
-
declare class MessagingError extends Error {
|
|
662
|
-
readonly code: MessagingErrorCode;
|
|
663
|
-
/** The remedy. Nothing fails silently, and nothing fails without saying what to do. */
|
|
664
|
-
readonly remedy: string;
|
|
665
|
-
readonly cause?: unknown;
|
|
666
|
-
constructor(code: MessagingErrorCode, message: string, remedy: string, cause?: unknown);
|
|
667
|
-
/** True when re-running the same call is the fix. */
|
|
668
|
-
get isRetryable(): boolean;
|
|
669
|
-
}
|
|
670
|
-
interface PostgrestErrorLike {
|
|
671
|
-
message: string;
|
|
672
|
-
code?: string | undefined;
|
|
673
|
-
details?: string | null | undefined;
|
|
674
|
-
}
|
|
675
|
-
/**
|
|
676
|
-
* THE ONE PLACE a raw PostgREST/transport error becomes a typed one. Called at
|
|
677
|
-
* every boundary in `repository.ts`; nothing else in the package inspects a raw
|
|
678
|
-
* error, and no consumer should ever have to.
|
|
679
|
-
*/
|
|
680
|
-
declare function normalizeMessagingError(error: PostgrestErrorLike | Error | unknown, operation: string): MessagingError;
|
|
681
|
-
/** A response whose SHAPE is wrong — the ingress boundary, not the wire. */
|
|
682
|
-
declare function invalidResponse(operation: string, detail: string): MessagingError;
|
|
683
|
-
|
|
684
686
|
/**
|
|
685
687
|
* THE STRUCTURAL SUPABASE SHAPE.
|
|
686
688
|
*
|
|
@@ -712,6 +714,7 @@ interface PostgrestLikeResponse<T> {
|
|
|
712
714
|
code?: string;
|
|
713
715
|
details?: string | null;
|
|
714
716
|
} | null;
|
|
717
|
+
count?: number | null;
|
|
715
718
|
}
|
|
716
719
|
interface PostgrestFilterLike<TRow> extends PromiseLike<PostgrestLikeResponse<TRow[]>> {
|
|
717
720
|
eq(column: string, value: unknown): PostgrestFilterLike<TRow>;
|
|
@@ -725,12 +728,17 @@ interface PostgrestFilterLike<TRow> extends PromiseLike<PostgrestLikeResponse<TR
|
|
|
725
728
|
ascending?: boolean;
|
|
726
729
|
}): PostgrestFilterLike<TRow>;
|
|
727
730
|
limit(count: number): PostgrestFilterLike<TRow>;
|
|
728
|
-
|
|
731
|
+
range(from: number, to: number): PostgrestFilterLike<TRow>;
|
|
732
|
+
select(columns?: string, options?: {
|
|
733
|
+
count?: "exact";
|
|
734
|
+
}): PostgrestFilterLike<TRow>;
|
|
729
735
|
single(): PromiseLike<PostgrestLikeResponse<TRow>>;
|
|
730
736
|
maybeSingle(): PromiseLike<PostgrestLikeResponse<TRow>>;
|
|
731
737
|
}
|
|
732
738
|
interface PostgrestTableLike<TRow> {
|
|
733
|
-
select(columns?: string
|
|
739
|
+
select(columns?: string, options?: {
|
|
740
|
+
count?: "exact";
|
|
741
|
+
}): PostgrestFilterLike<TRow>;
|
|
734
742
|
insert(values: unknown): PostgrestFilterLike<TRow>;
|
|
735
743
|
update(values: unknown): PostgrestFilterLike<TRow>;
|
|
736
744
|
upsert(values: unknown, options?: {
|
|
@@ -1023,6 +1031,11 @@ interface MessagingRepository {
|
|
|
1023
1031
|
exact: boolean;
|
|
1024
1032
|
}>;
|
|
1025
1033
|
getConversation(id: ConversationId): Promise<Conversation>;
|
|
1034
|
+
/**
|
|
1035
|
+
* One conversation's complete inbox/header row, independent of inbox paging.
|
|
1036
|
+
* Deep links use this door when their conversation is not in the loaded page.
|
|
1037
|
+
*/
|
|
1038
|
+
getConversationSummary(id: ConversationId): Promise<ConversationSummary>;
|
|
1026
1039
|
listMessages(conversationId: ConversationId, args?: {
|
|
1027
1040
|
limit?: number;
|
|
1028
1041
|
cursor?: MessageCursor | null;
|
|
@@ -1037,7 +1050,8 @@ interface MessagingRepository {
|
|
|
1037
1050
|
insertMessage(draft: DraftMessage, clientMessageId: ClientMessageId): Promise<Message>;
|
|
1038
1051
|
editMessage(id: MessageId, content: string): Promise<Message>;
|
|
1039
1052
|
deleteMessage(id: MessageId, forEveryone: boolean): Promise<void>;
|
|
1040
|
-
|
|
1053
|
+
/** Persists the cutoff, then returns the server's remaining unread count. */
|
|
1054
|
+
markRead(conversationId: ConversationId, at: string): Promise<number>;
|
|
1041
1055
|
setConversationFlags(conversationId: ConversationId, flags: {
|
|
1042
1056
|
isMuted?: boolean;
|
|
1043
1057
|
isArchived?: boolean;
|
|
@@ -1078,10 +1092,10 @@ declare function createMessagingRepository(options: RepositoryOptions): Messagin
|
|
|
1078
1092
|
* 4. **Order is `created_at` then `id`.** The unique tiebreaker is not
|
|
1079
1093
|
* decoration: two messages in the same millisecond otherwise swap places on
|
|
1080
1094
|
* every re-render.
|
|
1081
|
-
* 5. **
|
|
1082
|
-
*
|
|
1083
|
-
*
|
|
1084
|
-
*
|
|
1095
|
+
* 5. **Navigation is not a read receipt.** Active-conversation state never
|
|
1096
|
+
* clears unread counts. Only a confirmed participant write may do that, and
|
|
1097
|
+
* overlapping confirmations apply monotonically so one baseline is never
|
|
1098
|
+
* subtracted twice.
|
|
1085
1099
|
*/
|
|
1086
1100
|
|
|
1087
1101
|
/**
|
|
@@ -1111,6 +1125,12 @@ interface ConversationThread {
|
|
|
1111
1125
|
}
|
|
1112
1126
|
interface MessagingSnapshot {
|
|
1113
1127
|
readonly conversations: readonly ConversationSummary[];
|
|
1128
|
+
/**
|
|
1129
|
+
* Summaries known by id, including a directly opened conversation outside
|
|
1130
|
+
* the current filtered inbox page. Header lookup uses this map; inbox
|
|
1131
|
+
* rendering continues to use `conversations` exactly as returned by its page.
|
|
1132
|
+
*/
|
|
1133
|
+
readonly conversationSummaries: ReadonlyMap<ConversationId, ConversationSummary>;
|
|
1114
1134
|
readonly hasMoreConversations: boolean;
|
|
1115
1135
|
/**
|
|
1116
1136
|
* True once the inbox has actually been READ at least once.
|
|
@@ -1169,6 +1189,7 @@ interface MessagingStore {
|
|
|
1169
1189
|
} | null): void;
|
|
1170
1190
|
appendConversations(items: readonly ConversationSummary[], hasMore: boolean): void;
|
|
1171
1191
|
upsertConversation(item: ConversationSummary): void;
|
|
1192
|
+
setConversationSummary(item: ConversationSummary): void;
|
|
1172
1193
|
removeConversation(id: ConversationId): void;
|
|
1173
1194
|
setActiveConversation(id: ConversationId | null): void;
|
|
1174
1195
|
/** Record (or clear, with `null`) why a conversation could not be read. */
|
|
@@ -1176,12 +1197,19 @@ interface MessagingStore {
|
|
|
1176
1197
|
setThread(id: ConversationId, messages: readonly Message[], args?: {
|
|
1177
1198
|
hasMoreOlder?: boolean;
|
|
1178
1199
|
}): void;
|
|
1200
|
+
clearThread(id: ConversationId): void;
|
|
1179
1201
|
prependOlder(id: ConversationId, messages: readonly Message[], hasMoreOlder: boolean): void;
|
|
1180
1202
|
/** The one door every incoming message uses. Returns what actually happened. */
|
|
1181
1203
|
ingest(message: Message): "added" | "merged" | "dropped-stale" | "dropped-duplicate";
|
|
1182
1204
|
ingestMany(messages: readonly Message[]): void;
|
|
1183
1205
|
removeMessage(conversationId: ConversationId, messageId: MessageId): void;
|
|
1184
|
-
|
|
1206
|
+
captureConversationRead(id: ConversationId, at: string): ConversationReadCutoff;
|
|
1207
|
+
/**
|
|
1208
|
+
* Apply a confirmed read through the exact cutoff persisted by the repository.
|
|
1209
|
+
* `unreadCount` is the portion visible when that write began; arrivals after
|
|
1210
|
+
* `at` remain unread when the confirmation comes back.
|
|
1211
|
+
*/
|
|
1212
|
+
markConversationRead(id: ConversationId, cutoff: ConversationReadCutoff, canonicalUnreadCount?: number): void;
|
|
1185
1213
|
/**
|
|
1186
1214
|
* Move a conversation's preview + sort position to reflect a message, with NO
|
|
1187
1215
|
* refetch. Sending a message must not cost a conversation-list RPC — at a
|
|
@@ -1193,6 +1221,12 @@ interface MessagingStore {
|
|
|
1193
1221
|
}): void;
|
|
1194
1222
|
setUnreadCount(id: ConversationId, count: number): void;
|
|
1195
1223
|
}
|
|
1224
|
+
interface ConversationReadCutoff {
|
|
1225
|
+
readonly at: string;
|
|
1226
|
+
readonly unreadCount: number;
|
|
1227
|
+
/** Per-conversation unread-state revision observed when this read began. */
|
|
1228
|
+
readonly revision: number;
|
|
1229
|
+
}
|
|
1196
1230
|
declare function createMessagingStore(): MessagingStore;
|
|
1197
1231
|
/**
|
|
1198
1232
|
* The optimistic row a composer shows the instant Enter is pressed. It carries
|
|
@@ -1232,6 +1266,12 @@ interface EngineDiagnostic {
|
|
|
1232
1266
|
readonly level: "info" | "warn" | "error";
|
|
1233
1267
|
readonly message: string;
|
|
1234
1268
|
readonly remedy?: string | undefined;
|
|
1269
|
+
/** Stable machine-readable metadata for host diagnostic adapters. */
|
|
1270
|
+
readonly code?: MessagingErrorCode | undefined;
|
|
1271
|
+
readonly operation?: string | undefined;
|
|
1272
|
+
readonly isRetryable?: boolean | undefined;
|
|
1273
|
+
readonly error?: MessagingError | undefined;
|
|
1274
|
+
readonly conversationId?: ConversationId | undefined;
|
|
1235
1275
|
}
|
|
1236
1276
|
interface MessagingEngineOptions {
|
|
1237
1277
|
repository: MessagingRepository;
|
|
@@ -1424,4 +1464,4 @@ declare function summarizeText(content: string, maxLength?: number): string;
|
|
|
1424
1464
|
/** Serialize picked references into a fence the platform's other readers accept. */
|
|
1425
1465
|
declare function composeFence(references: readonly MatrxReference[]): string;
|
|
1426
1466
|
|
|
1427
|
-
export { type ActionChoice, type ActionContext, type ActionHandler, type ActionOutcome, type ActionReceipt, type ActionRegistry, type ActorPresentation, type AiCallArgs, type AiCapability, type AiResult, type Attachment, type ClientMessageId, type Conversation, type ConversationAiContext, type ConversationCursor, type ConversationId, type ConversationReadFailure, type ConversationSummary, type ConversationThread, type ConversationType, DEFAULT_MESSAGING_ARCHIVE_FILTER, type DeliveryState, type DraftMessage, type EngineDiagnostic, type JsonObject, type JsonValue, MESSAGING_EVENTS, MESSAGING_RPC_SCHEMA, MESSAGING_SCHEMA, type MatrxReference, type Message, type MessageAction, type MessageCursor, type MessageGroup, type MessageId, type MessageKind, type MessagingAgentIdentity, type MessagingAgents, type MessagingAi, type MessagingAiOptions, type MessagingArchiveFilter, type MessagingEngine, type MessagingEngineOptions, MessagingError, type MessagingErrorCode, type MessagingIdentity, type MessagingRepository, type MessagingSnapshot, type MessagingStore, type MessagingSupabaseClient, type MessagingSupabaseInternal, type OrganizationId, type Outbox, type OutboxEntry, type OutboxOptions, type OutboxStorage, type Page, type Participant, type ParticipantRole, type PostgrestFilterLike, type PostgrestLikeResponse, type PostgrestTableLike, RPCS, type ReadCache, type ReadCacheOptions, type RepositoryOptions, SERVER_SESSION_IDENTITY, type SchemaLike, type SessionIdentity, type SessionIdentitySnapshot, type SessionResolver, type SupabaseLike, TABLES, type TextSegment, type UserId, type UserSummary, asClientMessageId, asConversationId, asMessageId, asOrganizationId, asUserId, composeFence, conversationContextVariables, conversationTopic, createActionRegistry, createMemoryOutboxStorage, createMessagingAi, createMessagingEngine, createMessagingRepository, createMessagingStore, createOutbox, createReadCache, createSessionIdentity, createWebOutboxStorage, effectiveActorKey, extractReferences, formatConversationTime, formatDateSeparator, formatLastSeen, formatMessageTime, formatTypists, groupMessages, inboxTopic, invalidResponse, isSameDay, messagingClientId, normalizeMessagingError, optimisticMessage, participantNames, projectConversationSummary, projectMessage, projectMessageAction, projectParticipantRole, projectUserSummary, resolveActor, splitText, summarizeText, toMessagingArchiveFilter, unreadCutoff };
|
|
1467
|
+
export { type ActionChoice, type ActionContext, type ActionHandler, type ActionOutcome, type ActionReceipt, type ActionRegistry, type ActorPresentation, type AiCallArgs, type AiCapability, type AiResult, type Attachment, type ClientMessageId, type Conversation, type ConversationAiContext, type ConversationCursor, type ConversationId, type ConversationReadCutoff, type ConversationReadFailure, type ConversationSummary, type ConversationThread, type ConversationType, DEFAULT_MESSAGING_ARCHIVE_FILTER, type DeliveryState, type DraftMessage, type EngineDiagnostic, type JsonObject, type JsonValue, MESSAGING_EVENTS, MESSAGING_RPC_SCHEMA, MESSAGING_SCHEMA, type MatrxReference, type Message, type MessageAction, type MessageCursor, type MessageGroup, type MessageId, type MessageKind, type MessagingAgentIdentity, type MessagingAgents, type MessagingAi, type MessagingAiOptions, type MessagingArchiveFilter, type MessagingEngine, type MessagingEngineOptions, MessagingError, type MessagingErrorCode, type MessagingIdentity, type MessagingRepository, type MessagingSnapshot, type MessagingStore, type MessagingSupabaseClient, type MessagingSupabaseInternal, type OrganizationId, type Outbox, type OutboxEntry, type OutboxOptions, type OutboxStorage, type Page, type Participant, type ParticipantRole, type PostgrestFilterLike, type PostgrestLikeResponse, type PostgrestTableLike, RPCS, type ReadCache, type ReadCacheOptions, type RepositoryOptions, SERVER_SESSION_IDENTITY, type SchemaLike, type SessionIdentity, type SessionIdentitySnapshot, type SessionResolver, type SupabaseLike, TABLES, type TextSegment, type UserId, type UserSummary, asClientMessageId, asConversationId, asMessageId, asOrganizationId, asUserId, composeFence, conversationContextVariables, conversationTopic, createActionRegistry, createMemoryOutboxStorage, createMessagingAi, createMessagingEngine, createMessagingRepository, createMessagingStore, createOutbox, createReadCache, createSessionIdentity, createWebOutboxStorage, effectiveActorKey, extractReferences, formatConversationTime, formatDateSeparator, formatLastSeen, formatMessageTime, formatTypists, groupMessages, inboxTopic, invalidResponse, isSameDay, messagingClientId, normalizeMessagingError, optimisticMessage, participantNames, projectConversationSummary, projectMessage, projectMessageAction, projectParticipantRole, projectUserSummary, resolveActor, splitText, summarizeText, toMessagingArchiveFilter, unreadCutoff, writeNotApplied };
|
package/dist/index.d.ts
CHANGED
|
@@ -552,6 +552,49 @@ declare const MESSAGING_EVENTS: {
|
|
|
552
552
|
readonly actionSettled: "mx.action.settled";
|
|
553
553
|
};
|
|
554
554
|
|
|
555
|
+
/**
|
|
556
|
+
* ONE error classification for the whole package (C22).
|
|
557
|
+
*
|
|
558
|
+
* The banned alternative is the host catching a PostgREST error and deciding
|
|
559
|
+
* for itself whether it was an auth blip, a permission denial, or a real bug —
|
|
560
|
+
* which is how the same three-branch `if` ends up copy-pasted into every
|
|
561
|
+
* consumer and drifts. Everything this package throws is a `MessagingError`
|
|
562
|
+
* with a stable `code`, and the two that hosts genuinely treat differently
|
|
563
|
+
* (`session-unavailable`, `forbidden`) say so in the type.
|
|
564
|
+
*
|
|
565
|
+
* The incident behind `session-unavailable`: a DM reader mounted before the
|
|
566
|
+
* access token existed, every RPC came back `42501`, and the app captured 909
|
|
567
|
+
* errors in 0.6 seconds. A missing session is a NORMAL lifecycle moment — it
|
|
568
|
+
* warns and retries; it is never a red error.
|
|
569
|
+
*/
|
|
570
|
+
type MessagingErrorCode = "session-unavailable" | "contention" | "forbidden" | "not-found" | "conflict" | "transport" | "invalid-response" | "write-not-applied" | "misconfigured"
|
|
571
|
+
/** A NEW conversation needs an organization to land in and none is selected. */
|
|
572
|
+
| "organization-required" | "unknown";
|
|
573
|
+
declare class MessagingError extends Error {
|
|
574
|
+
readonly code: MessagingErrorCode;
|
|
575
|
+
/** The remedy. Nothing fails silently, and nothing fails without saying what to do. */
|
|
576
|
+
readonly remedy: string;
|
|
577
|
+
readonly cause?: unknown;
|
|
578
|
+
constructor(code: MessagingErrorCode, message: string, remedy: string, cause?: unknown);
|
|
579
|
+
/** True when re-running the same call is the fix. */
|
|
580
|
+
get isRetryable(): boolean;
|
|
581
|
+
}
|
|
582
|
+
interface PostgrestErrorLike {
|
|
583
|
+
message: string;
|
|
584
|
+
code?: string | undefined;
|
|
585
|
+
details?: string | null | undefined;
|
|
586
|
+
}
|
|
587
|
+
/**
|
|
588
|
+
* THE ONE PLACE a raw PostgREST/transport error becomes a typed one. Called at
|
|
589
|
+
* every boundary in `repository.ts`; nothing else in the package inspects a raw
|
|
590
|
+
* error, and no consumer should ever have to.
|
|
591
|
+
*/
|
|
592
|
+
declare function normalizeMessagingError(error: PostgrestErrorLike | Error | unknown, operation: string): MessagingError;
|
|
593
|
+
/** A response whose SHAPE is wrong — the ingress boundary, not the wire. */
|
|
594
|
+
declare function invalidResponse(operation: string, detail: string): MessagingError;
|
|
595
|
+
/** A mutation that PostgREST accepted syntactically but applied to no row. */
|
|
596
|
+
declare function writeNotApplied(operation: string, detail: string): MessagingError;
|
|
597
|
+
|
|
555
598
|
/**
|
|
556
599
|
* THE OUTBOX — a message you typed is NEVER lost (R2, table-stakes law).
|
|
557
600
|
*
|
|
@@ -640,47 +683,6 @@ interface Outbox {
|
|
|
640
683
|
}
|
|
641
684
|
declare function createOutbox(options: OutboxOptions): Outbox;
|
|
642
685
|
|
|
643
|
-
/**
|
|
644
|
-
* ONE error classification for the whole package (C22).
|
|
645
|
-
*
|
|
646
|
-
* The banned alternative is the host catching a PostgREST error and deciding
|
|
647
|
-
* for itself whether it was an auth blip, a permission denial, or a real bug —
|
|
648
|
-
* which is how the same three-branch `if` ends up copy-pasted into every
|
|
649
|
-
* consumer and drifts. Everything this package throws is a `MessagingError`
|
|
650
|
-
* with a stable `code`, and the two that hosts genuinely treat differently
|
|
651
|
-
* (`session-unavailable`, `forbidden`) say so in the type.
|
|
652
|
-
*
|
|
653
|
-
* The incident behind `session-unavailable`: a DM reader mounted before the
|
|
654
|
-
* access token existed, every RPC came back `42501`, and the app captured 909
|
|
655
|
-
* errors in 0.6 seconds. A missing session is a NORMAL lifecycle moment — it
|
|
656
|
-
* warns and retries; it is never a red error.
|
|
657
|
-
*/
|
|
658
|
-
type MessagingErrorCode = "session-unavailable" | "contention" | "forbidden" | "not-found" | "conflict" | "transport" | "invalid-response" | "misconfigured"
|
|
659
|
-
/** A NEW conversation needs an organization to land in and none is selected. */
|
|
660
|
-
| "organization-required" | "unknown";
|
|
661
|
-
declare class MessagingError extends Error {
|
|
662
|
-
readonly code: MessagingErrorCode;
|
|
663
|
-
/** The remedy. Nothing fails silently, and nothing fails without saying what to do. */
|
|
664
|
-
readonly remedy: string;
|
|
665
|
-
readonly cause?: unknown;
|
|
666
|
-
constructor(code: MessagingErrorCode, message: string, remedy: string, cause?: unknown);
|
|
667
|
-
/** True when re-running the same call is the fix. */
|
|
668
|
-
get isRetryable(): boolean;
|
|
669
|
-
}
|
|
670
|
-
interface PostgrestErrorLike {
|
|
671
|
-
message: string;
|
|
672
|
-
code?: string | undefined;
|
|
673
|
-
details?: string | null | undefined;
|
|
674
|
-
}
|
|
675
|
-
/**
|
|
676
|
-
* THE ONE PLACE a raw PostgREST/transport error becomes a typed one. Called at
|
|
677
|
-
* every boundary in `repository.ts`; nothing else in the package inspects a raw
|
|
678
|
-
* error, and no consumer should ever have to.
|
|
679
|
-
*/
|
|
680
|
-
declare function normalizeMessagingError(error: PostgrestErrorLike | Error | unknown, operation: string): MessagingError;
|
|
681
|
-
/** A response whose SHAPE is wrong — the ingress boundary, not the wire. */
|
|
682
|
-
declare function invalidResponse(operation: string, detail: string): MessagingError;
|
|
683
|
-
|
|
684
686
|
/**
|
|
685
687
|
* THE STRUCTURAL SUPABASE SHAPE.
|
|
686
688
|
*
|
|
@@ -712,6 +714,7 @@ interface PostgrestLikeResponse<T> {
|
|
|
712
714
|
code?: string;
|
|
713
715
|
details?: string | null;
|
|
714
716
|
} | null;
|
|
717
|
+
count?: number | null;
|
|
715
718
|
}
|
|
716
719
|
interface PostgrestFilterLike<TRow> extends PromiseLike<PostgrestLikeResponse<TRow[]>> {
|
|
717
720
|
eq(column: string, value: unknown): PostgrestFilterLike<TRow>;
|
|
@@ -725,12 +728,17 @@ interface PostgrestFilterLike<TRow> extends PromiseLike<PostgrestLikeResponse<TR
|
|
|
725
728
|
ascending?: boolean;
|
|
726
729
|
}): PostgrestFilterLike<TRow>;
|
|
727
730
|
limit(count: number): PostgrestFilterLike<TRow>;
|
|
728
|
-
|
|
731
|
+
range(from: number, to: number): PostgrestFilterLike<TRow>;
|
|
732
|
+
select(columns?: string, options?: {
|
|
733
|
+
count?: "exact";
|
|
734
|
+
}): PostgrestFilterLike<TRow>;
|
|
729
735
|
single(): PromiseLike<PostgrestLikeResponse<TRow>>;
|
|
730
736
|
maybeSingle(): PromiseLike<PostgrestLikeResponse<TRow>>;
|
|
731
737
|
}
|
|
732
738
|
interface PostgrestTableLike<TRow> {
|
|
733
|
-
select(columns?: string
|
|
739
|
+
select(columns?: string, options?: {
|
|
740
|
+
count?: "exact";
|
|
741
|
+
}): PostgrestFilterLike<TRow>;
|
|
734
742
|
insert(values: unknown): PostgrestFilterLike<TRow>;
|
|
735
743
|
update(values: unknown): PostgrestFilterLike<TRow>;
|
|
736
744
|
upsert(values: unknown, options?: {
|
|
@@ -1023,6 +1031,11 @@ interface MessagingRepository {
|
|
|
1023
1031
|
exact: boolean;
|
|
1024
1032
|
}>;
|
|
1025
1033
|
getConversation(id: ConversationId): Promise<Conversation>;
|
|
1034
|
+
/**
|
|
1035
|
+
* One conversation's complete inbox/header row, independent of inbox paging.
|
|
1036
|
+
* Deep links use this door when their conversation is not in the loaded page.
|
|
1037
|
+
*/
|
|
1038
|
+
getConversationSummary(id: ConversationId): Promise<ConversationSummary>;
|
|
1026
1039
|
listMessages(conversationId: ConversationId, args?: {
|
|
1027
1040
|
limit?: number;
|
|
1028
1041
|
cursor?: MessageCursor | null;
|
|
@@ -1037,7 +1050,8 @@ interface MessagingRepository {
|
|
|
1037
1050
|
insertMessage(draft: DraftMessage, clientMessageId: ClientMessageId): Promise<Message>;
|
|
1038
1051
|
editMessage(id: MessageId, content: string): Promise<Message>;
|
|
1039
1052
|
deleteMessage(id: MessageId, forEveryone: boolean): Promise<void>;
|
|
1040
|
-
|
|
1053
|
+
/** Persists the cutoff, then returns the server's remaining unread count. */
|
|
1054
|
+
markRead(conversationId: ConversationId, at: string): Promise<number>;
|
|
1041
1055
|
setConversationFlags(conversationId: ConversationId, flags: {
|
|
1042
1056
|
isMuted?: boolean;
|
|
1043
1057
|
isArchived?: boolean;
|
|
@@ -1078,10 +1092,10 @@ declare function createMessagingRepository(options: RepositoryOptions): Messagin
|
|
|
1078
1092
|
* 4. **Order is `created_at` then `id`.** The unique tiebreaker is not
|
|
1079
1093
|
* decoration: two messages in the same millisecond otherwise swap places on
|
|
1080
1094
|
* every re-render.
|
|
1081
|
-
* 5. **
|
|
1082
|
-
*
|
|
1083
|
-
*
|
|
1084
|
-
*
|
|
1095
|
+
* 5. **Navigation is not a read receipt.** Active-conversation state never
|
|
1096
|
+
* clears unread counts. Only a confirmed participant write may do that, and
|
|
1097
|
+
* overlapping confirmations apply monotonically so one baseline is never
|
|
1098
|
+
* subtracted twice.
|
|
1085
1099
|
*/
|
|
1086
1100
|
|
|
1087
1101
|
/**
|
|
@@ -1111,6 +1125,12 @@ interface ConversationThread {
|
|
|
1111
1125
|
}
|
|
1112
1126
|
interface MessagingSnapshot {
|
|
1113
1127
|
readonly conversations: readonly ConversationSummary[];
|
|
1128
|
+
/**
|
|
1129
|
+
* Summaries known by id, including a directly opened conversation outside
|
|
1130
|
+
* the current filtered inbox page. Header lookup uses this map; inbox
|
|
1131
|
+
* rendering continues to use `conversations` exactly as returned by its page.
|
|
1132
|
+
*/
|
|
1133
|
+
readonly conversationSummaries: ReadonlyMap<ConversationId, ConversationSummary>;
|
|
1114
1134
|
readonly hasMoreConversations: boolean;
|
|
1115
1135
|
/**
|
|
1116
1136
|
* True once the inbox has actually been READ at least once.
|
|
@@ -1169,6 +1189,7 @@ interface MessagingStore {
|
|
|
1169
1189
|
} | null): void;
|
|
1170
1190
|
appendConversations(items: readonly ConversationSummary[], hasMore: boolean): void;
|
|
1171
1191
|
upsertConversation(item: ConversationSummary): void;
|
|
1192
|
+
setConversationSummary(item: ConversationSummary): void;
|
|
1172
1193
|
removeConversation(id: ConversationId): void;
|
|
1173
1194
|
setActiveConversation(id: ConversationId | null): void;
|
|
1174
1195
|
/** Record (or clear, with `null`) why a conversation could not be read. */
|
|
@@ -1176,12 +1197,19 @@ interface MessagingStore {
|
|
|
1176
1197
|
setThread(id: ConversationId, messages: readonly Message[], args?: {
|
|
1177
1198
|
hasMoreOlder?: boolean;
|
|
1178
1199
|
}): void;
|
|
1200
|
+
clearThread(id: ConversationId): void;
|
|
1179
1201
|
prependOlder(id: ConversationId, messages: readonly Message[], hasMoreOlder: boolean): void;
|
|
1180
1202
|
/** The one door every incoming message uses. Returns what actually happened. */
|
|
1181
1203
|
ingest(message: Message): "added" | "merged" | "dropped-stale" | "dropped-duplicate";
|
|
1182
1204
|
ingestMany(messages: readonly Message[]): void;
|
|
1183
1205
|
removeMessage(conversationId: ConversationId, messageId: MessageId): void;
|
|
1184
|
-
|
|
1206
|
+
captureConversationRead(id: ConversationId, at: string): ConversationReadCutoff;
|
|
1207
|
+
/**
|
|
1208
|
+
* Apply a confirmed read through the exact cutoff persisted by the repository.
|
|
1209
|
+
* `unreadCount` is the portion visible when that write began; arrivals after
|
|
1210
|
+
* `at` remain unread when the confirmation comes back.
|
|
1211
|
+
*/
|
|
1212
|
+
markConversationRead(id: ConversationId, cutoff: ConversationReadCutoff, canonicalUnreadCount?: number): void;
|
|
1185
1213
|
/**
|
|
1186
1214
|
* Move a conversation's preview + sort position to reflect a message, with NO
|
|
1187
1215
|
* refetch. Sending a message must not cost a conversation-list RPC — at a
|
|
@@ -1193,6 +1221,12 @@ interface MessagingStore {
|
|
|
1193
1221
|
}): void;
|
|
1194
1222
|
setUnreadCount(id: ConversationId, count: number): void;
|
|
1195
1223
|
}
|
|
1224
|
+
interface ConversationReadCutoff {
|
|
1225
|
+
readonly at: string;
|
|
1226
|
+
readonly unreadCount: number;
|
|
1227
|
+
/** Per-conversation unread-state revision observed when this read began. */
|
|
1228
|
+
readonly revision: number;
|
|
1229
|
+
}
|
|
1196
1230
|
declare function createMessagingStore(): MessagingStore;
|
|
1197
1231
|
/**
|
|
1198
1232
|
* The optimistic row a composer shows the instant Enter is pressed. It carries
|
|
@@ -1232,6 +1266,12 @@ interface EngineDiagnostic {
|
|
|
1232
1266
|
readonly level: "info" | "warn" | "error";
|
|
1233
1267
|
readonly message: string;
|
|
1234
1268
|
readonly remedy?: string | undefined;
|
|
1269
|
+
/** Stable machine-readable metadata for host diagnostic adapters. */
|
|
1270
|
+
readonly code?: MessagingErrorCode | undefined;
|
|
1271
|
+
readonly operation?: string | undefined;
|
|
1272
|
+
readonly isRetryable?: boolean | undefined;
|
|
1273
|
+
readonly error?: MessagingError | undefined;
|
|
1274
|
+
readonly conversationId?: ConversationId | undefined;
|
|
1235
1275
|
}
|
|
1236
1276
|
interface MessagingEngineOptions {
|
|
1237
1277
|
repository: MessagingRepository;
|
|
@@ -1424,4 +1464,4 @@ declare function summarizeText(content: string, maxLength?: number): string;
|
|
|
1424
1464
|
/** Serialize picked references into a fence the platform's other readers accept. */
|
|
1425
1465
|
declare function composeFence(references: readonly MatrxReference[]): string;
|
|
1426
1466
|
|
|
1427
|
-
export { type ActionChoice, type ActionContext, type ActionHandler, type ActionOutcome, type ActionReceipt, type ActionRegistry, type ActorPresentation, type AiCallArgs, type AiCapability, type AiResult, type Attachment, type ClientMessageId, type Conversation, type ConversationAiContext, type ConversationCursor, type ConversationId, type ConversationReadFailure, type ConversationSummary, type ConversationThread, type ConversationType, DEFAULT_MESSAGING_ARCHIVE_FILTER, type DeliveryState, type DraftMessage, type EngineDiagnostic, type JsonObject, type JsonValue, MESSAGING_EVENTS, MESSAGING_RPC_SCHEMA, MESSAGING_SCHEMA, type MatrxReference, type Message, type MessageAction, type MessageCursor, type MessageGroup, type MessageId, type MessageKind, type MessagingAgentIdentity, type MessagingAgents, type MessagingAi, type MessagingAiOptions, type MessagingArchiveFilter, type MessagingEngine, type MessagingEngineOptions, MessagingError, type MessagingErrorCode, type MessagingIdentity, type MessagingRepository, type MessagingSnapshot, type MessagingStore, type MessagingSupabaseClient, type MessagingSupabaseInternal, type OrganizationId, type Outbox, type OutboxEntry, type OutboxOptions, type OutboxStorage, type Page, type Participant, type ParticipantRole, type PostgrestFilterLike, type PostgrestLikeResponse, type PostgrestTableLike, RPCS, type ReadCache, type ReadCacheOptions, type RepositoryOptions, SERVER_SESSION_IDENTITY, type SchemaLike, type SessionIdentity, type SessionIdentitySnapshot, type SessionResolver, type SupabaseLike, TABLES, type TextSegment, type UserId, type UserSummary, asClientMessageId, asConversationId, asMessageId, asOrganizationId, asUserId, composeFence, conversationContextVariables, conversationTopic, createActionRegistry, createMemoryOutboxStorage, createMessagingAi, createMessagingEngine, createMessagingRepository, createMessagingStore, createOutbox, createReadCache, createSessionIdentity, createWebOutboxStorage, effectiveActorKey, extractReferences, formatConversationTime, formatDateSeparator, formatLastSeen, formatMessageTime, formatTypists, groupMessages, inboxTopic, invalidResponse, isSameDay, messagingClientId, normalizeMessagingError, optimisticMessage, participantNames, projectConversationSummary, projectMessage, projectMessageAction, projectParticipantRole, projectUserSummary, resolveActor, splitText, summarizeText, toMessagingArchiveFilter, unreadCutoff };
|
|
1467
|
+
export { type ActionChoice, type ActionContext, type ActionHandler, type ActionOutcome, type ActionReceipt, type ActionRegistry, type ActorPresentation, type AiCallArgs, type AiCapability, type AiResult, type Attachment, type ClientMessageId, type Conversation, type ConversationAiContext, type ConversationCursor, type ConversationId, type ConversationReadCutoff, type ConversationReadFailure, type ConversationSummary, type ConversationThread, type ConversationType, DEFAULT_MESSAGING_ARCHIVE_FILTER, type DeliveryState, type DraftMessage, type EngineDiagnostic, type JsonObject, type JsonValue, MESSAGING_EVENTS, MESSAGING_RPC_SCHEMA, MESSAGING_SCHEMA, type MatrxReference, type Message, type MessageAction, type MessageCursor, type MessageGroup, type MessageId, type MessageKind, type MessagingAgentIdentity, type MessagingAgents, type MessagingAi, type MessagingAiOptions, type MessagingArchiveFilter, type MessagingEngine, type MessagingEngineOptions, MessagingError, type MessagingErrorCode, type MessagingIdentity, type MessagingRepository, type MessagingSnapshot, type MessagingStore, type MessagingSupabaseClient, type MessagingSupabaseInternal, type OrganizationId, type Outbox, type OutboxEntry, type OutboxOptions, type OutboxStorage, type Page, type Participant, type ParticipantRole, type PostgrestFilterLike, type PostgrestLikeResponse, type PostgrestTableLike, RPCS, type ReadCache, type ReadCacheOptions, type RepositoryOptions, SERVER_SESSION_IDENTITY, type SchemaLike, type SessionIdentity, type SessionIdentitySnapshot, type SessionResolver, type SupabaseLike, TABLES, type TextSegment, type UserId, type UserSummary, asClientMessageId, asConversationId, asMessageId, asOrganizationId, asUserId, composeFence, conversationContextVariables, conversationTopic, createActionRegistry, createMemoryOutboxStorage, createMessagingAi, createMessagingEngine, createMessagingRepository, createMessagingStore, createOutbox, createReadCache, createSessionIdentity, createWebOutboxStorage, effectiveActorKey, extractReferences, formatConversationTime, formatDateSeparator, formatLastSeen, formatMessageTime, formatTypists, groupMessages, inboxTopic, invalidResponse, isSameDay, messagingClientId, normalizeMessagingError, optimisticMessage, participantNames, projectConversationSummary, projectMessage, projectMessageAction, projectParticipantRole, projectUserSummary, resolveActor, splitText, summarizeText, toMessagingArchiveFilter, unreadCutoff, writeNotApplied };
|