@ai-matrx/messaging 0.10.4 → 0.11.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/CHANGELOG.md +64 -0
- package/README.md +33 -0
- package/dist/index.cjs +102 -13
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +101 -1
- package/dist/index.d.ts +101 -1
- package/dist/index.js +102 -13
- package/dist/index.js.map +1 -1
- package/dist/react.cjs +149 -16
- package/dist/react.cjs.map +1 -1
- package/dist/react.d.cts +126 -1
- package/dist/react.d.ts +126 -1
- package/dist/react.js +149 -16
- package/dist/react.js.map +1 -1
- package/dist/styles.css +7 -0
- package/package.json +1 -1
package/dist/index.d.cts
CHANGED
|
@@ -137,6 +137,39 @@ interface Message {
|
|
|
137
137
|
/** Set only while this message is in the outbox and its last send failed. */
|
|
138
138
|
readonly failureReason?: string | undefined;
|
|
139
139
|
}
|
|
140
|
+
/**
|
|
141
|
+
* THE ARCHIVED-ITEMS LAW's three states (Arman, 2026-09-09 —
|
|
142
|
+
* `common-docs/policies/archived-items.md`):
|
|
143
|
+
*
|
|
144
|
+
* > "everything should have an archive filter, and the default should always
|
|
145
|
+
* > hide archived, but seeing archived items should be one or two clicks
|
|
146
|
+
* > away … this is a system wide decision for every single item everywhere in
|
|
147
|
+
* > our system, for every single table and every single page."
|
|
148
|
+
*
|
|
149
|
+
* | value | what the list shows |
|
|
150
|
+
* |------------|--------------------------|
|
|
151
|
+
* | `active` | only un-archived rows |
|
|
152
|
+
* | `archived` | only archived rows |
|
|
153
|
+
* | `all` | every row |
|
|
154
|
+
*
|
|
155
|
+
* The same three words the rest of the platform uses — `ArchivedFilter` in
|
|
156
|
+
* matrx-frontend's `lib/entity-list`, `p_archived` on the `agx_*`/`wfx_*` and
|
|
157
|
+
* DM list RPCs, `ArchiveFilter` in `@ai-matrx/design-system`. A person meets
|
|
158
|
+
* ONE control, not one per app.
|
|
159
|
+
*
|
|
160
|
+
* 🚨 Three states, never a boolean. A boolean cannot say "archived only",
|
|
161
|
+
* which is exactly the view someone looking for a conversation they archived
|
|
162
|
+
* last month needs.
|
|
163
|
+
*/
|
|
164
|
+
type MessagingArchiveFilter = "active" | "archived" | "all";
|
|
165
|
+
/** The platform default: a list hides archived rows until asked. */
|
|
166
|
+
declare const DEFAULT_MESSAGING_ARCHIVE_FILTER: MessagingArchiveFilter;
|
|
167
|
+
/**
|
|
168
|
+
* Narrow an untrusted value (a stored preference, a URL param, a host knob) to
|
|
169
|
+
* the tri-state. Anything unrecognised falls back to the default rather than
|
|
170
|
+
* silently widening a list to archived conversations.
|
|
171
|
+
*/
|
|
172
|
+
declare function toMessagingArchiveFilter(value: unknown, fallback?: MessagingArchiveFilter): MessagingArchiveFilter;
|
|
140
173
|
interface ConversationSummary {
|
|
141
174
|
readonly conversation: Conversation;
|
|
142
175
|
readonly participants: readonly UserSummary[];
|
|
@@ -770,7 +803,30 @@ interface MessagingRepository {
|
|
|
770
803
|
listConversations(args?: {
|
|
771
804
|
limit?: number;
|
|
772
805
|
cursor?: ConversationCursor | null;
|
|
806
|
+
/**
|
|
807
|
+
* THE ARCHIVED-ITEMS LAW. Omitted means `active` — archived conversations
|
|
808
|
+
* are hidden until a caller asks for them. This is a REQUEST to the reader
|
|
809
|
+
* (the RPC's `p_archived`), never a client-side sieve, so `hasMore` and the
|
|
810
|
+
* cursor describe the rows the caller actually asked for.
|
|
811
|
+
*/
|
|
812
|
+
archived?: MessagingArchiveFilter;
|
|
773
813
|
}): Promise<Page<ConversationSummary, ConversationCursor>>;
|
|
814
|
+
/**
|
|
815
|
+
* How many ARCHIVED conversations the caller has — the number a reveal
|
|
816
|
+
* control prints ("Archived (12)").
|
|
817
|
+
*
|
|
818
|
+
* 🚨 It is capped, and it says so. A count is read by listing archived rows
|
|
819
|
+
* up to `limit`; if that many come back the result is `exact: false` and the
|
|
820
|
+
* UI must render "12+", never a confident "12". A screen never lies: a cap
|
|
821
|
+
* silently presented as a total is the same defect as a badge counting rows
|
|
822
|
+
* the list hides.
|
|
823
|
+
*/
|
|
824
|
+
countArchivedConversations(args?: {
|
|
825
|
+
limit?: number;
|
|
826
|
+
}): Promise<{
|
|
827
|
+
count: number;
|
|
828
|
+
exact: boolean;
|
|
829
|
+
}>;
|
|
774
830
|
getConversation(id: ConversationId): Promise<Conversation>;
|
|
775
831
|
listMessages(conversationId: ConversationId, args?: {
|
|
776
832
|
limit?: number;
|
|
@@ -857,11 +913,38 @@ interface MessagingSnapshot {
|
|
|
857
913
|
readonly activeConversationId: ConversationId | null;
|
|
858
914
|
/** Conversations WITH unread, not total unread messages (the origin's semantics). */
|
|
859
915
|
readonly totalUnreadConversations: number;
|
|
916
|
+
/**
|
|
917
|
+
* THE ARCHIVED-ITEMS LAW's state for this inbox. `conversations` above is
|
|
918
|
+
* ALWAYS the rows this filter asked the server for — never a superset a
|
|
919
|
+
* surface is expected to sieve, so counts and pagination cannot disagree
|
|
920
|
+
* with what renders.
|
|
921
|
+
*/
|
|
922
|
+
readonly archiveFilter: MessagingArchiveFilter;
|
|
923
|
+
/**
|
|
924
|
+
* How many archived conversations exist, for the reveal control's label, or
|
|
925
|
+
* `null` before the first count lands. `exact: false` means the count hit its
|
|
926
|
+
* cap and the label must read "N+" — a capped number shown as a total is the
|
|
927
|
+
* same lie as a badge counting hidden rows.
|
|
928
|
+
*/
|
|
929
|
+
readonly archivedCount: {
|
|
930
|
+
readonly count: number;
|
|
931
|
+
readonly exact: boolean;
|
|
932
|
+
} | null;
|
|
860
933
|
}
|
|
861
934
|
interface MessagingStore {
|
|
862
935
|
snapshot(): MessagingSnapshot;
|
|
863
936
|
subscribe(listener: (snapshot: MessagingSnapshot) => void): () => void;
|
|
864
937
|
setConversations(items: readonly ConversationSummary[], hasMore: boolean): void;
|
|
938
|
+
/**
|
|
939
|
+
* Switch the archive axis. Clears the list and marks it UNLOADED: the rows
|
|
940
|
+
* on screen belong to the old filter, and leaving them there while the new
|
|
941
|
+
* page is in flight shows active conversations under an "Archived" heading.
|
|
942
|
+
*/
|
|
943
|
+
setArchiveFilter(next: MessagingArchiveFilter): void;
|
|
944
|
+
setArchivedCount(value: {
|
|
945
|
+
count: number;
|
|
946
|
+
exact: boolean;
|
|
947
|
+
} | null): void;
|
|
865
948
|
appendConversations(items: readonly ConversationSummary[], hasMore: boolean): void;
|
|
866
949
|
upsertConversation(item: ConversationSummary): void;
|
|
867
950
|
removeConversation(id: ConversationId): void;
|
|
@@ -936,6 +1019,15 @@ interface MessagingEngineOptions {
|
|
|
936
1019
|
onIncoming?: ((message: Message) => void) | undefined;
|
|
937
1020
|
conversationPageSize?: number | undefined;
|
|
938
1021
|
messagePageSize?: number | undefined;
|
|
1022
|
+
/**
|
|
1023
|
+
* 🚨 OPINIONS BECOME KNOBS. THE ARCHIVED-ITEMS LAW's clause 6 says the
|
|
1024
|
+
* filter's initial state is an org/user-configurable setting, not code
|
|
1025
|
+
* taste. The PLATFORM default is `active` (hide archived) and a host that
|
|
1026
|
+
* passes nothing gets exactly that; a host wires this to whatever its own
|
|
1027
|
+
* setting resolves to. The person can always change it from the control on
|
|
1028
|
+
* the list.
|
|
1029
|
+
*/
|
|
1030
|
+
archiveFilter?: MessagingArchiveFilter | undefined;
|
|
939
1031
|
}
|
|
940
1032
|
interface MessagingEngine {
|
|
941
1033
|
readonly store: MessagingStore;
|
|
@@ -944,6 +1036,14 @@ interface MessagingEngine {
|
|
|
944
1036
|
/** Load page one of the inbox and start the inbox channel. */
|
|
945
1037
|
start(): Promise<void>;
|
|
946
1038
|
loadMoreConversations(): Promise<void>;
|
|
1039
|
+
/**
|
|
1040
|
+
* THE ARCHIVED-ITEMS LAW's control. Re-reads page one under the new state
|
|
1041
|
+
* (the filter is a REQUEST to the server, never a client-side sieve) and
|
|
1042
|
+
* refreshes the archived count the reveal label prints.
|
|
1043
|
+
*/
|
|
1044
|
+
setArchiveFilter(next: MessagingArchiveFilter): Promise<void>;
|
|
1045
|
+
/** Re-read how many archived conversations exist, for the reveal's label. */
|
|
1046
|
+
refreshArchivedCount(): Promise<void>;
|
|
947
1047
|
/** Open a conversation: load its thread and subscribe to its channel. */
|
|
948
1048
|
openConversation(id: ConversationId): Promise<void>;
|
|
949
1049
|
closeConversation(id: ConversationId): void;
|
|
@@ -1119,4 +1219,4 @@ declare function summarizeText(content: string, maxLength?: number): string;
|
|
|
1119
1219
|
/** Serialize picked references into a fence the platform's other readers accept. */
|
|
1120
1220
|
declare function composeFence(references: readonly MatrxReference[]): string;
|
|
1121
1221
|
|
|
1122
|
-
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 ConversationCursor, type ConversationId, type ConversationSummary, type ConversationThread, type ConversationType, 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 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, type SchemaLike, type SessionResolver, type SupabaseLike, TABLES, type TextSegment, type UserId, type UserSummary, asClientMessageId, asConversationId, asMessageId, asOrganizationId, asUserId, composeFence, conversationTopic, createActionRegistry, createMemoryOutboxStorage, createMessagingAi, createMessagingEngine, createMessagingRepository, createMessagingStore, createOutbox, createReadCache, createWebOutboxStorage, effectiveActorKey, extractReferences, formatConversationTime, formatDateSeparator, formatLastSeen, formatMessageTime, formatTypists, groupMessages, inboxTopic, invalidResponse, isSameDay, messagingClientId, normalizeMessagingError, optimisticMessage, participantNames, projectConversationSummary, projectMessage, projectMessageAction, projectParticipantRole, projectUserSummary, resolveActor, splitText, summarizeText, unreadCutoff };
|
|
1222
|
+
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 ConversationCursor, type ConversationId, 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, type SchemaLike, type SessionResolver, type SupabaseLike, TABLES, type TextSegment, type UserId, type UserSummary, asClientMessageId, asConversationId, asMessageId, asOrganizationId, asUserId, composeFence, conversationTopic, createActionRegistry, createMemoryOutboxStorage, createMessagingAi, createMessagingEngine, createMessagingRepository, createMessagingStore, createOutbox, createReadCache, 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 };
|
package/dist/index.d.ts
CHANGED
|
@@ -137,6 +137,39 @@ interface Message {
|
|
|
137
137
|
/** Set only while this message is in the outbox and its last send failed. */
|
|
138
138
|
readonly failureReason?: string | undefined;
|
|
139
139
|
}
|
|
140
|
+
/**
|
|
141
|
+
* THE ARCHIVED-ITEMS LAW's three states (Arman, 2026-09-09 —
|
|
142
|
+
* `common-docs/policies/archived-items.md`):
|
|
143
|
+
*
|
|
144
|
+
* > "everything should have an archive filter, and the default should always
|
|
145
|
+
* > hide archived, but seeing archived items should be one or two clicks
|
|
146
|
+
* > away … this is a system wide decision for every single item everywhere in
|
|
147
|
+
* > our system, for every single table and every single page."
|
|
148
|
+
*
|
|
149
|
+
* | value | what the list shows |
|
|
150
|
+
* |------------|--------------------------|
|
|
151
|
+
* | `active` | only un-archived rows |
|
|
152
|
+
* | `archived` | only archived rows |
|
|
153
|
+
* | `all` | every row |
|
|
154
|
+
*
|
|
155
|
+
* The same three words the rest of the platform uses — `ArchivedFilter` in
|
|
156
|
+
* matrx-frontend's `lib/entity-list`, `p_archived` on the `agx_*`/`wfx_*` and
|
|
157
|
+
* DM list RPCs, `ArchiveFilter` in `@ai-matrx/design-system`. A person meets
|
|
158
|
+
* ONE control, not one per app.
|
|
159
|
+
*
|
|
160
|
+
* 🚨 Three states, never a boolean. A boolean cannot say "archived only",
|
|
161
|
+
* which is exactly the view someone looking for a conversation they archived
|
|
162
|
+
* last month needs.
|
|
163
|
+
*/
|
|
164
|
+
type MessagingArchiveFilter = "active" | "archived" | "all";
|
|
165
|
+
/** The platform default: a list hides archived rows until asked. */
|
|
166
|
+
declare const DEFAULT_MESSAGING_ARCHIVE_FILTER: MessagingArchiveFilter;
|
|
167
|
+
/**
|
|
168
|
+
* Narrow an untrusted value (a stored preference, a URL param, a host knob) to
|
|
169
|
+
* the tri-state. Anything unrecognised falls back to the default rather than
|
|
170
|
+
* silently widening a list to archived conversations.
|
|
171
|
+
*/
|
|
172
|
+
declare function toMessagingArchiveFilter(value: unknown, fallback?: MessagingArchiveFilter): MessagingArchiveFilter;
|
|
140
173
|
interface ConversationSummary {
|
|
141
174
|
readonly conversation: Conversation;
|
|
142
175
|
readonly participants: readonly UserSummary[];
|
|
@@ -770,7 +803,30 @@ interface MessagingRepository {
|
|
|
770
803
|
listConversations(args?: {
|
|
771
804
|
limit?: number;
|
|
772
805
|
cursor?: ConversationCursor | null;
|
|
806
|
+
/**
|
|
807
|
+
* THE ARCHIVED-ITEMS LAW. Omitted means `active` — archived conversations
|
|
808
|
+
* are hidden until a caller asks for them. This is a REQUEST to the reader
|
|
809
|
+
* (the RPC's `p_archived`), never a client-side sieve, so `hasMore` and the
|
|
810
|
+
* cursor describe the rows the caller actually asked for.
|
|
811
|
+
*/
|
|
812
|
+
archived?: MessagingArchiveFilter;
|
|
773
813
|
}): Promise<Page<ConversationSummary, ConversationCursor>>;
|
|
814
|
+
/**
|
|
815
|
+
* How many ARCHIVED conversations the caller has — the number a reveal
|
|
816
|
+
* control prints ("Archived (12)").
|
|
817
|
+
*
|
|
818
|
+
* 🚨 It is capped, and it says so. A count is read by listing archived rows
|
|
819
|
+
* up to `limit`; if that many come back the result is `exact: false` and the
|
|
820
|
+
* UI must render "12+", never a confident "12". A screen never lies: a cap
|
|
821
|
+
* silently presented as a total is the same defect as a badge counting rows
|
|
822
|
+
* the list hides.
|
|
823
|
+
*/
|
|
824
|
+
countArchivedConversations(args?: {
|
|
825
|
+
limit?: number;
|
|
826
|
+
}): Promise<{
|
|
827
|
+
count: number;
|
|
828
|
+
exact: boolean;
|
|
829
|
+
}>;
|
|
774
830
|
getConversation(id: ConversationId): Promise<Conversation>;
|
|
775
831
|
listMessages(conversationId: ConversationId, args?: {
|
|
776
832
|
limit?: number;
|
|
@@ -857,11 +913,38 @@ interface MessagingSnapshot {
|
|
|
857
913
|
readonly activeConversationId: ConversationId | null;
|
|
858
914
|
/** Conversations WITH unread, not total unread messages (the origin's semantics). */
|
|
859
915
|
readonly totalUnreadConversations: number;
|
|
916
|
+
/**
|
|
917
|
+
* THE ARCHIVED-ITEMS LAW's state for this inbox. `conversations` above is
|
|
918
|
+
* ALWAYS the rows this filter asked the server for — never a superset a
|
|
919
|
+
* surface is expected to sieve, so counts and pagination cannot disagree
|
|
920
|
+
* with what renders.
|
|
921
|
+
*/
|
|
922
|
+
readonly archiveFilter: MessagingArchiveFilter;
|
|
923
|
+
/**
|
|
924
|
+
* How many archived conversations exist, for the reveal control's label, or
|
|
925
|
+
* `null` before the first count lands. `exact: false` means the count hit its
|
|
926
|
+
* cap and the label must read "N+" — a capped number shown as a total is the
|
|
927
|
+
* same lie as a badge counting hidden rows.
|
|
928
|
+
*/
|
|
929
|
+
readonly archivedCount: {
|
|
930
|
+
readonly count: number;
|
|
931
|
+
readonly exact: boolean;
|
|
932
|
+
} | null;
|
|
860
933
|
}
|
|
861
934
|
interface MessagingStore {
|
|
862
935
|
snapshot(): MessagingSnapshot;
|
|
863
936
|
subscribe(listener: (snapshot: MessagingSnapshot) => void): () => void;
|
|
864
937
|
setConversations(items: readonly ConversationSummary[], hasMore: boolean): void;
|
|
938
|
+
/**
|
|
939
|
+
* Switch the archive axis. Clears the list and marks it UNLOADED: the rows
|
|
940
|
+
* on screen belong to the old filter, and leaving them there while the new
|
|
941
|
+
* page is in flight shows active conversations under an "Archived" heading.
|
|
942
|
+
*/
|
|
943
|
+
setArchiveFilter(next: MessagingArchiveFilter): void;
|
|
944
|
+
setArchivedCount(value: {
|
|
945
|
+
count: number;
|
|
946
|
+
exact: boolean;
|
|
947
|
+
} | null): void;
|
|
865
948
|
appendConversations(items: readonly ConversationSummary[], hasMore: boolean): void;
|
|
866
949
|
upsertConversation(item: ConversationSummary): void;
|
|
867
950
|
removeConversation(id: ConversationId): void;
|
|
@@ -936,6 +1019,15 @@ interface MessagingEngineOptions {
|
|
|
936
1019
|
onIncoming?: ((message: Message) => void) | undefined;
|
|
937
1020
|
conversationPageSize?: number | undefined;
|
|
938
1021
|
messagePageSize?: number | undefined;
|
|
1022
|
+
/**
|
|
1023
|
+
* 🚨 OPINIONS BECOME KNOBS. THE ARCHIVED-ITEMS LAW's clause 6 says the
|
|
1024
|
+
* filter's initial state is an org/user-configurable setting, not code
|
|
1025
|
+
* taste. The PLATFORM default is `active` (hide archived) and a host that
|
|
1026
|
+
* passes nothing gets exactly that; a host wires this to whatever its own
|
|
1027
|
+
* setting resolves to. The person can always change it from the control on
|
|
1028
|
+
* the list.
|
|
1029
|
+
*/
|
|
1030
|
+
archiveFilter?: MessagingArchiveFilter | undefined;
|
|
939
1031
|
}
|
|
940
1032
|
interface MessagingEngine {
|
|
941
1033
|
readonly store: MessagingStore;
|
|
@@ -944,6 +1036,14 @@ interface MessagingEngine {
|
|
|
944
1036
|
/** Load page one of the inbox and start the inbox channel. */
|
|
945
1037
|
start(): Promise<void>;
|
|
946
1038
|
loadMoreConversations(): Promise<void>;
|
|
1039
|
+
/**
|
|
1040
|
+
* THE ARCHIVED-ITEMS LAW's control. Re-reads page one under the new state
|
|
1041
|
+
* (the filter is a REQUEST to the server, never a client-side sieve) and
|
|
1042
|
+
* refreshes the archived count the reveal label prints.
|
|
1043
|
+
*/
|
|
1044
|
+
setArchiveFilter(next: MessagingArchiveFilter): Promise<void>;
|
|
1045
|
+
/** Re-read how many archived conversations exist, for the reveal's label. */
|
|
1046
|
+
refreshArchivedCount(): Promise<void>;
|
|
947
1047
|
/** Open a conversation: load its thread and subscribe to its channel. */
|
|
948
1048
|
openConversation(id: ConversationId): Promise<void>;
|
|
949
1049
|
closeConversation(id: ConversationId): void;
|
|
@@ -1119,4 +1219,4 @@ declare function summarizeText(content: string, maxLength?: number): string;
|
|
|
1119
1219
|
/** Serialize picked references into a fence the platform's other readers accept. */
|
|
1120
1220
|
declare function composeFence(references: readonly MatrxReference[]): string;
|
|
1121
1221
|
|
|
1122
|
-
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 ConversationCursor, type ConversationId, type ConversationSummary, type ConversationThread, type ConversationType, 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 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, type SchemaLike, type SessionResolver, type SupabaseLike, TABLES, type TextSegment, type UserId, type UserSummary, asClientMessageId, asConversationId, asMessageId, asOrganizationId, asUserId, composeFence, conversationTopic, createActionRegistry, createMemoryOutboxStorage, createMessagingAi, createMessagingEngine, createMessagingRepository, createMessagingStore, createOutbox, createReadCache, createWebOutboxStorage, effectiveActorKey, extractReferences, formatConversationTime, formatDateSeparator, formatLastSeen, formatMessageTime, formatTypists, groupMessages, inboxTopic, invalidResponse, isSameDay, messagingClientId, normalizeMessagingError, optimisticMessage, participantNames, projectConversationSummary, projectMessage, projectMessageAction, projectParticipantRole, projectUserSummary, resolveActor, splitText, summarizeText, unreadCutoff };
|
|
1222
|
+
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 ConversationCursor, type ConversationId, 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, type SchemaLike, type SessionResolver, type SupabaseLike, TABLES, type TextSegment, type UserId, type UserSummary, asClientMessageId, asConversationId, asMessageId, asOrganizationId, asUserId, composeFence, conversationTopic, createActionRegistry, createMemoryOutboxStorage, createMessagingAi, createMessagingEngine, createMessagingRepository, createMessagingStore, createOutbox, createReadCache, 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 };
|
package/dist/index.js
CHANGED
|
@@ -920,6 +920,17 @@ function projectConversationSummary(row, viewerId, fallbackOrganizationId) {
|
|
|
920
920
|
};
|
|
921
921
|
}
|
|
922
922
|
|
|
923
|
+
// src/core/types.ts
|
|
924
|
+
var asConversationId = (value) => value;
|
|
925
|
+
var asMessageId = (value) => value;
|
|
926
|
+
var asUserId = (value) => value;
|
|
927
|
+
var asOrganizationId = (value) => value;
|
|
928
|
+
var asClientMessageId = (value) => value;
|
|
929
|
+
var DEFAULT_MESSAGING_ARCHIVE_FILTER = "active";
|
|
930
|
+
function toMessagingArchiveFilter(value, fallback = DEFAULT_MESSAGING_ARCHIVE_FILTER) {
|
|
931
|
+
return value === "active" || value === "archived" || value === "all" ? value : fallback;
|
|
932
|
+
}
|
|
933
|
+
|
|
923
934
|
// src/core/store.ts
|
|
924
935
|
function timeOf(message) {
|
|
925
936
|
const stamp = message.editedAt ?? message.createdAt;
|
|
@@ -950,6 +961,8 @@ function createMessagingStore() {
|
|
|
950
961
|
let conversations = [];
|
|
951
962
|
let hasMoreConversations = false;
|
|
952
963
|
let hasLoadedConversations = false;
|
|
964
|
+
let archiveFilter = DEFAULT_MESSAGING_ARCHIVE_FILTER;
|
|
965
|
+
let archivedCount = null;
|
|
953
966
|
let threads = /* @__PURE__ */ new Map();
|
|
954
967
|
let activeConversationId = null;
|
|
955
968
|
const listeners = /* @__PURE__ */ new Set();
|
|
@@ -962,7 +975,9 @@ function createMessagingStore() {
|
|
|
962
975
|
hasLoadedConversations,
|
|
963
976
|
threads,
|
|
964
977
|
activeConversationId,
|
|
965
|
-
totalUnreadConversations: conversations.filter((item) => item.unreadCount > 0).length
|
|
978
|
+
totalUnreadConversations: conversations.filter((item) => item.unreadCount > 0).length,
|
|
979
|
+
archiveFilter,
|
|
980
|
+
archivedCount
|
|
966
981
|
};
|
|
967
982
|
return cached;
|
|
968
983
|
}
|
|
@@ -1009,6 +1024,18 @@ function createMessagingStore() {
|
|
|
1009
1024
|
hasLoadedConversations = true;
|
|
1010
1025
|
emit();
|
|
1011
1026
|
},
|
|
1027
|
+
setArchiveFilter(next) {
|
|
1028
|
+
if (next === archiveFilter) return;
|
|
1029
|
+
archiveFilter = next;
|
|
1030
|
+
conversations = [];
|
|
1031
|
+
hasMoreConversations = false;
|
|
1032
|
+
hasLoadedConversations = false;
|
|
1033
|
+
emit();
|
|
1034
|
+
},
|
|
1035
|
+
setArchivedCount(value) {
|
|
1036
|
+
archivedCount = value;
|
|
1037
|
+
emit();
|
|
1038
|
+
},
|
|
1012
1039
|
appendConversations(items, hasMore) {
|
|
1013
1040
|
const byId = new Map(conversations.map((item) => [item.conversation.id, item]));
|
|
1014
1041
|
items.forEach((item) => byId.set(item.conversation.id, item));
|
|
@@ -1214,10 +1241,21 @@ function createMessagingEngine(options) {
|
|
|
1214
1241
|
openChannels.get(message.conversationId)?.send(MESSAGING_EVENTS.message, message);
|
|
1215
1242
|
}
|
|
1216
1243
|
async function reloadInbox() {
|
|
1217
|
-
|
|
1244
|
+
if (disposed) return;
|
|
1245
|
+
const page = await repository.listConversations({
|
|
1246
|
+
limit: conversationPageSize,
|
|
1247
|
+
archived: store.snapshot().archiveFilter
|
|
1248
|
+
});
|
|
1249
|
+
if (disposed) return;
|
|
1218
1250
|
conversationCursor = page.nextCursor;
|
|
1219
1251
|
store.setConversations(page.items, page.hasMore);
|
|
1220
1252
|
}
|
|
1253
|
+
async function reloadArchivedCount() {
|
|
1254
|
+
if (disposed) return;
|
|
1255
|
+
const value = await repository.countArchivedConversations();
|
|
1256
|
+
if (disposed) return;
|
|
1257
|
+
store.setArchivedCount(value);
|
|
1258
|
+
}
|
|
1221
1259
|
async function backfillConversation(id) {
|
|
1222
1260
|
const thread = store.snapshot().threads.get(id);
|
|
1223
1261
|
const since = thread?.latestAt ?? null;
|
|
@@ -1244,7 +1282,13 @@ function createMessagingEngine(options) {
|
|
|
1244
1282
|
outbox,
|
|
1245
1283
|
identity,
|
|
1246
1284
|
async start() {
|
|
1285
|
+
if (options.archiveFilter !== void 0) {
|
|
1286
|
+
store.setArchiveFilter(options.archiveFilter);
|
|
1287
|
+
}
|
|
1247
1288
|
await reloadInbox();
|
|
1289
|
+
void reloadArchivedCount().catch(
|
|
1290
|
+
(error) => reportError(error, "refreshArchivedCount")
|
|
1291
|
+
);
|
|
1248
1292
|
if (disposed || inboxChannel !== null) return;
|
|
1249
1293
|
inboxChannel = manager.open({
|
|
1250
1294
|
topic: inboxTopic(identity.userId),
|
|
@@ -1259,7 +1303,7 @@ function createMessagingEngine(options) {
|
|
|
1259
1303
|
const message = projectMessage(row, identity.organizationId);
|
|
1260
1304
|
const known = store.snapshot().conversations.some((item) => item.conversation.id === message.conversationId);
|
|
1261
1305
|
if (!known) {
|
|
1262
|
-
void reloadInbox();
|
|
1306
|
+
void reloadInbox().catch((error) => reportError(error, "inboxRefresh"));
|
|
1263
1307
|
return;
|
|
1264
1308
|
}
|
|
1265
1309
|
store.ingest(message);
|
|
@@ -1275,7 +1319,7 @@ function createMessagingEngine(options) {
|
|
|
1275
1319
|
filter: `user_id=eq.${identity.userId}`,
|
|
1276
1320
|
rowId: (row) => typeof row["id"] === "string" ? row["id"] : void 0,
|
|
1277
1321
|
onChange: () => {
|
|
1278
|
-
void reloadInbox();
|
|
1322
|
+
void reloadInbox().catch((error) => reportError(error, "inboxRefresh"));
|
|
1279
1323
|
}
|
|
1280
1324
|
}
|
|
1281
1325
|
],
|
|
@@ -1286,12 +1330,33 @@ function createMessagingEngine(options) {
|
|
|
1286
1330
|
}
|
|
1287
1331
|
});
|
|
1288
1332
|
},
|
|
1333
|
+
async setArchiveFilter(next) {
|
|
1334
|
+
if (next === store.snapshot().archiveFilter) return;
|
|
1335
|
+
store.setArchiveFilter(next);
|
|
1336
|
+
conversationCursor = null;
|
|
1337
|
+
try {
|
|
1338
|
+
await reloadInbox();
|
|
1339
|
+
} catch (error) {
|
|
1340
|
+
reportError(error, "setArchiveFilter");
|
|
1341
|
+
}
|
|
1342
|
+
await reloadArchivedCount().catch(
|
|
1343
|
+
(error) => reportError(error, "refreshArchivedCount")
|
|
1344
|
+
);
|
|
1345
|
+
},
|
|
1346
|
+
async refreshArchivedCount() {
|
|
1347
|
+
try {
|
|
1348
|
+
await reloadArchivedCount();
|
|
1349
|
+
} catch (error) {
|
|
1350
|
+
reportError(error, "refreshArchivedCount");
|
|
1351
|
+
}
|
|
1352
|
+
},
|
|
1289
1353
|
async loadMoreConversations() {
|
|
1290
1354
|
if (conversationCursor === null) return;
|
|
1291
1355
|
try {
|
|
1292
1356
|
const page = await repository.listConversations({
|
|
1293
1357
|
limit: conversationPageSize,
|
|
1294
|
-
cursor: conversationCursor
|
|
1358
|
+
cursor: conversationCursor,
|
|
1359
|
+
archived: store.snapshot().archiveFilter
|
|
1295
1360
|
});
|
|
1296
1361
|
conversationCursor = page.nextCursor;
|
|
1297
1362
|
store.appendConversations(page.items, page.hasMore);
|
|
@@ -1600,6 +1665,7 @@ function createMessagingRepository(options) {
|
|
|
1600
1665
|
identity,
|
|
1601
1666
|
async listConversations(args = {}) {
|
|
1602
1667
|
const limit = args.limit ?? 30;
|
|
1668
|
+
const archived = args.archived ?? DEFAULT_MESSAGING_ARCHIVE_FILTER;
|
|
1603
1669
|
const operation = "listConversations";
|
|
1604
1670
|
const rows = await withSessionRetry(
|
|
1605
1671
|
operation,
|
|
@@ -1609,7 +1675,12 @@ function createMessagingRepository(options) {
|
|
|
1609
1675
|
p_user_id: identity.userId,
|
|
1610
1676
|
p_limit: limit + 1,
|
|
1611
1677
|
p_before_sort_at: args.cursor?.beforeSortAt ?? null,
|
|
1612
|
-
p_before_conversation_id: args.cursor?.beforeConversationId ?? null
|
|
1678
|
+
p_before_conversation_id: args.cursor?.beforeConversationId ?? null,
|
|
1679
|
+
// THE ARCHIVED-ITEMS LAW, SERVER-side. `get_dm_conversations_with_details`
|
|
1680
|
+
// used to hardcode `is_archived IS FALSE` with no parameter at all,
|
|
1681
|
+
// so an archived conversation was not hidden — it was unreachable.
|
|
1682
|
+
// The RPC gained `p_archived` on 2026-09-09 (register row R1).
|
|
1683
|
+
p_archived: archived
|
|
1613
1684
|
},
|
|
1614
1685
|
operation
|
|
1615
1686
|
)
|
|
@@ -1629,6 +1700,29 @@ function createMessagingRepository(options) {
|
|
|
1629
1700
|
nextCursor: hasMore && last !== void 0 ? { beforeSortAt: last.sortAt, beforeConversationId: last.conversation.id } : null
|
|
1630
1701
|
};
|
|
1631
1702
|
},
|
|
1703
|
+
async countArchivedConversations(args = {}) {
|
|
1704
|
+
const limit = args.limit ?? 100;
|
|
1705
|
+
const operation = "countArchivedConversations";
|
|
1706
|
+
const rows = await withSessionRetry(
|
|
1707
|
+
operation,
|
|
1708
|
+
() => rpc(
|
|
1709
|
+
RPCS.conversationsWithDetails,
|
|
1710
|
+
{
|
|
1711
|
+
p_user_id: identity.userId,
|
|
1712
|
+
p_limit: limit + 1,
|
|
1713
|
+
p_before_sort_at: null,
|
|
1714
|
+
p_before_conversation_id: null,
|
|
1715
|
+
p_archived: "archived"
|
|
1716
|
+
},
|
|
1717
|
+
operation
|
|
1718
|
+
)
|
|
1719
|
+
);
|
|
1720
|
+
if (rows !== null && !Array.isArray(rows)) {
|
|
1721
|
+
throw invalidResponse(operation, `${RPCS.conversationsWithDetails} did not return rows`);
|
|
1722
|
+
}
|
|
1723
|
+
const found = (rows ?? []).length;
|
|
1724
|
+
return found > limit ? { count: limit, exact: false } : { count: found, exact: true };
|
|
1725
|
+
},
|
|
1632
1726
|
async getConversation(id) {
|
|
1633
1727
|
const operation = "getConversation";
|
|
1634
1728
|
const { data, error } = await withSessionRetry(
|
|
@@ -1862,14 +1956,8 @@ function createMessagingRepository(options) {
|
|
|
1862
1956
|
};
|
|
1863
1957
|
return repository;
|
|
1864
1958
|
}
|
|
1865
|
-
|
|
1866
|
-
// src/core/types.ts
|
|
1867
|
-
var asConversationId = (value) => value;
|
|
1868
|
-
var asMessageId = (value) => value;
|
|
1869
|
-
var asUserId = (value) => value;
|
|
1870
|
-
var asOrganizationId = (value) => value;
|
|
1871
|
-
var asClientMessageId = (value) => value;
|
|
1872
1959
|
export {
|
|
1960
|
+
DEFAULT_MESSAGING_ARCHIVE_FILTER,
|
|
1873
1961
|
MESSAGING_EVENTS,
|
|
1874
1962
|
MESSAGING_RPC_SCHEMA,
|
|
1875
1963
|
MESSAGING_SCHEMA,
|
|
@@ -1915,6 +2003,7 @@ export {
|
|
|
1915
2003
|
resolveActor,
|
|
1916
2004
|
splitText,
|
|
1917
2005
|
summarizeText,
|
|
2006
|
+
toMessagingArchiveFilter,
|
|
1918
2007
|
unreadCutoff
|
|
1919
2008
|
};
|
|
1920
2009
|
//# sourceMappingURL=index.js.map
|