@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/react.js
CHANGED
|
@@ -821,6 +821,17 @@ function projectConversationSummary(row, viewerId, fallbackOrganizationId) {
|
|
|
821
821
|
};
|
|
822
822
|
}
|
|
823
823
|
|
|
824
|
+
// src/core/types.ts
|
|
825
|
+
var asConversationId = (value) => value;
|
|
826
|
+
var asMessageId = (value) => value;
|
|
827
|
+
var asUserId = (value) => value;
|
|
828
|
+
var asOrganizationId = (value) => value;
|
|
829
|
+
var asClientMessageId = (value) => value;
|
|
830
|
+
var DEFAULT_MESSAGING_ARCHIVE_FILTER = "active";
|
|
831
|
+
function toMessagingArchiveFilter(value, fallback = DEFAULT_MESSAGING_ARCHIVE_FILTER) {
|
|
832
|
+
return value === "active" || value === "archived" || value === "all" ? value : fallback;
|
|
833
|
+
}
|
|
834
|
+
|
|
824
835
|
// src/core/store.ts
|
|
825
836
|
function timeOf(message) {
|
|
826
837
|
const stamp = message.editedAt ?? message.createdAt;
|
|
@@ -851,6 +862,8 @@ function createMessagingStore() {
|
|
|
851
862
|
let conversations = [];
|
|
852
863
|
let hasMoreConversations = false;
|
|
853
864
|
let hasLoadedConversations = false;
|
|
865
|
+
let archiveFilter = DEFAULT_MESSAGING_ARCHIVE_FILTER;
|
|
866
|
+
let archivedCount = null;
|
|
854
867
|
let threads = /* @__PURE__ */ new Map();
|
|
855
868
|
let activeConversationId = null;
|
|
856
869
|
const listeners = /* @__PURE__ */ new Set();
|
|
@@ -863,7 +876,9 @@ function createMessagingStore() {
|
|
|
863
876
|
hasLoadedConversations,
|
|
864
877
|
threads,
|
|
865
878
|
activeConversationId,
|
|
866
|
-
totalUnreadConversations: conversations.filter((item) => item.unreadCount > 0).length
|
|
879
|
+
totalUnreadConversations: conversations.filter((item) => item.unreadCount > 0).length,
|
|
880
|
+
archiveFilter,
|
|
881
|
+
archivedCount
|
|
867
882
|
};
|
|
868
883
|
return cached;
|
|
869
884
|
}
|
|
@@ -910,6 +925,18 @@ function createMessagingStore() {
|
|
|
910
925
|
hasLoadedConversations = true;
|
|
911
926
|
emit();
|
|
912
927
|
},
|
|
928
|
+
setArchiveFilter(next) {
|
|
929
|
+
if (next === archiveFilter) return;
|
|
930
|
+
archiveFilter = next;
|
|
931
|
+
conversations = [];
|
|
932
|
+
hasMoreConversations = false;
|
|
933
|
+
hasLoadedConversations = false;
|
|
934
|
+
emit();
|
|
935
|
+
},
|
|
936
|
+
setArchivedCount(value) {
|
|
937
|
+
archivedCount = value;
|
|
938
|
+
emit();
|
|
939
|
+
},
|
|
913
940
|
appendConversations(items, hasMore) {
|
|
914
941
|
const byId = new Map(conversations.map((item) => [item.conversation.id, item]));
|
|
915
942
|
items.forEach((item) => byId.set(item.conversation.id, item));
|
|
@@ -1115,10 +1142,21 @@ function createMessagingEngine(options) {
|
|
|
1115
1142
|
openChannels.get(message.conversationId)?.send(MESSAGING_EVENTS.message, message);
|
|
1116
1143
|
}
|
|
1117
1144
|
async function reloadInbox() {
|
|
1118
|
-
|
|
1145
|
+
if (disposed) return;
|
|
1146
|
+
const page = await repository.listConversations({
|
|
1147
|
+
limit: conversationPageSize,
|
|
1148
|
+
archived: store.snapshot().archiveFilter
|
|
1149
|
+
});
|
|
1150
|
+
if (disposed) return;
|
|
1119
1151
|
conversationCursor = page.nextCursor;
|
|
1120
1152
|
store.setConversations(page.items, page.hasMore);
|
|
1121
1153
|
}
|
|
1154
|
+
async function reloadArchivedCount() {
|
|
1155
|
+
if (disposed) return;
|
|
1156
|
+
const value = await repository.countArchivedConversations();
|
|
1157
|
+
if (disposed) return;
|
|
1158
|
+
store.setArchivedCount(value);
|
|
1159
|
+
}
|
|
1122
1160
|
async function backfillConversation(id) {
|
|
1123
1161
|
const thread = store.snapshot().threads.get(id);
|
|
1124
1162
|
const since = thread?.latestAt ?? null;
|
|
@@ -1145,7 +1183,13 @@ function createMessagingEngine(options) {
|
|
|
1145
1183
|
outbox,
|
|
1146
1184
|
identity,
|
|
1147
1185
|
async start() {
|
|
1186
|
+
if (options.archiveFilter !== void 0) {
|
|
1187
|
+
store.setArchiveFilter(options.archiveFilter);
|
|
1188
|
+
}
|
|
1148
1189
|
await reloadInbox();
|
|
1190
|
+
void reloadArchivedCount().catch(
|
|
1191
|
+
(error) => reportError(error, "refreshArchivedCount")
|
|
1192
|
+
);
|
|
1149
1193
|
if (disposed || inboxChannel !== null) return;
|
|
1150
1194
|
inboxChannel = manager.open({
|
|
1151
1195
|
topic: inboxTopic(identity.userId),
|
|
@@ -1160,7 +1204,7 @@ function createMessagingEngine(options) {
|
|
|
1160
1204
|
const message = projectMessage(row, identity.organizationId);
|
|
1161
1205
|
const known = store.snapshot().conversations.some((item) => item.conversation.id === message.conversationId);
|
|
1162
1206
|
if (!known) {
|
|
1163
|
-
void reloadInbox();
|
|
1207
|
+
void reloadInbox().catch((error) => reportError(error, "inboxRefresh"));
|
|
1164
1208
|
return;
|
|
1165
1209
|
}
|
|
1166
1210
|
store.ingest(message);
|
|
@@ -1176,7 +1220,7 @@ function createMessagingEngine(options) {
|
|
|
1176
1220
|
filter: `user_id=eq.${identity.userId}`,
|
|
1177
1221
|
rowId: (row) => typeof row["id"] === "string" ? row["id"] : void 0,
|
|
1178
1222
|
onChange: () => {
|
|
1179
|
-
void reloadInbox();
|
|
1223
|
+
void reloadInbox().catch((error) => reportError(error, "inboxRefresh"));
|
|
1180
1224
|
}
|
|
1181
1225
|
}
|
|
1182
1226
|
],
|
|
@@ -1187,12 +1231,33 @@ function createMessagingEngine(options) {
|
|
|
1187
1231
|
}
|
|
1188
1232
|
});
|
|
1189
1233
|
},
|
|
1234
|
+
async setArchiveFilter(next) {
|
|
1235
|
+
if (next === store.snapshot().archiveFilter) return;
|
|
1236
|
+
store.setArchiveFilter(next);
|
|
1237
|
+
conversationCursor = null;
|
|
1238
|
+
try {
|
|
1239
|
+
await reloadInbox();
|
|
1240
|
+
} catch (error) {
|
|
1241
|
+
reportError(error, "setArchiveFilter");
|
|
1242
|
+
}
|
|
1243
|
+
await reloadArchivedCount().catch(
|
|
1244
|
+
(error) => reportError(error, "refreshArchivedCount")
|
|
1245
|
+
);
|
|
1246
|
+
},
|
|
1247
|
+
async refreshArchivedCount() {
|
|
1248
|
+
try {
|
|
1249
|
+
await reloadArchivedCount();
|
|
1250
|
+
} catch (error) {
|
|
1251
|
+
reportError(error, "refreshArchivedCount");
|
|
1252
|
+
}
|
|
1253
|
+
},
|
|
1190
1254
|
async loadMoreConversations() {
|
|
1191
1255
|
if (conversationCursor === null) return;
|
|
1192
1256
|
try {
|
|
1193
1257
|
const page = await repository.listConversations({
|
|
1194
1258
|
limit: conversationPageSize,
|
|
1195
|
-
cursor: conversationCursor
|
|
1259
|
+
cursor: conversationCursor,
|
|
1260
|
+
archived: store.snapshot().archiveFilter
|
|
1196
1261
|
});
|
|
1197
1262
|
conversationCursor = page.nextCursor;
|
|
1198
1263
|
store.appendConversations(page.items, page.hasMore);
|
|
@@ -1456,6 +1521,7 @@ function createMessagingRepository(options) {
|
|
|
1456
1521
|
identity,
|
|
1457
1522
|
async listConversations(args = {}) {
|
|
1458
1523
|
const limit = args.limit ?? 30;
|
|
1524
|
+
const archived = args.archived ?? DEFAULT_MESSAGING_ARCHIVE_FILTER;
|
|
1459
1525
|
const operation = "listConversations";
|
|
1460
1526
|
const rows = await withSessionRetry(
|
|
1461
1527
|
operation,
|
|
@@ -1465,7 +1531,12 @@ function createMessagingRepository(options) {
|
|
|
1465
1531
|
p_user_id: identity.userId,
|
|
1466
1532
|
p_limit: limit + 1,
|
|
1467
1533
|
p_before_sort_at: args.cursor?.beforeSortAt ?? null,
|
|
1468
|
-
p_before_conversation_id: args.cursor?.beforeConversationId ?? null
|
|
1534
|
+
p_before_conversation_id: args.cursor?.beforeConversationId ?? null,
|
|
1535
|
+
// THE ARCHIVED-ITEMS LAW, SERVER-side. `get_dm_conversations_with_details`
|
|
1536
|
+
// used to hardcode `is_archived IS FALSE` with no parameter at all,
|
|
1537
|
+
// so an archived conversation was not hidden — it was unreachable.
|
|
1538
|
+
// The RPC gained `p_archived` on 2026-09-09 (register row R1).
|
|
1539
|
+
p_archived: archived
|
|
1469
1540
|
},
|
|
1470
1541
|
operation
|
|
1471
1542
|
)
|
|
@@ -1485,6 +1556,29 @@ function createMessagingRepository(options) {
|
|
|
1485
1556
|
nextCursor: hasMore && last !== void 0 ? { beforeSortAt: last.sortAt, beforeConversationId: last.conversation.id } : null
|
|
1486
1557
|
};
|
|
1487
1558
|
},
|
|
1559
|
+
async countArchivedConversations(args = {}) {
|
|
1560
|
+
const limit = args.limit ?? 100;
|
|
1561
|
+
const operation = "countArchivedConversations";
|
|
1562
|
+
const rows = await withSessionRetry(
|
|
1563
|
+
operation,
|
|
1564
|
+
() => rpc(
|
|
1565
|
+
RPCS.conversationsWithDetails,
|
|
1566
|
+
{
|
|
1567
|
+
p_user_id: identity.userId,
|
|
1568
|
+
p_limit: limit + 1,
|
|
1569
|
+
p_before_sort_at: null,
|
|
1570
|
+
p_before_conversation_id: null,
|
|
1571
|
+
p_archived: "archived"
|
|
1572
|
+
},
|
|
1573
|
+
operation
|
|
1574
|
+
)
|
|
1575
|
+
);
|
|
1576
|
+
if (rows !== null && !Array.isArray(rows)) {
|
|
1577
|
+
throw invalidResponse(operation, `${RPCS.conversationsWithDetails} did not return rows`);
|
|
1578
|
+
}
|
|
1579
|
+
const found = (rows ?? []).length;
|
|
1580
|
+
return found > limit ? { count: limit, exact: false } : { count: found, exact: true };
|
|
1581
|
+
},
|
|
1488
1582
|
async getConversation(id) {
|
|
1489
1583
|
const operation = "getConversation";
|
|
1490
1584
|
const { data, error } = await withSessionRetry(
|
|
@@ -1793,6 +1887,7 @@ function MessagingRuntime(props) {
|
|
|
1793
1887
|
onFallback: (message) => report({ level: "warn", message })
|
|
1794
1888
|
}),
|
|
1795
1889
|
onDiagnostic: report,
|
|
1890
|
+
...props.archiveFilter !== void 0 ? { archiveFilter: props.archiveFilter } : {},
|
|
1796
1891
|
onIncoming: (message) => {
|
|
1797
1892
|
const snapshot = built?.store.snapshot();
|
|
1798
1893
|
if (snapshot === void 0) return;
|
|
@@ -2023,6 +2118,11 @@ function useConversations() {
|
|
|
2023
2118
|
},
|
|
2024
2119
|
select,
|
|
2025
2120
|
activeConversationId: snapshot?.activeConversationId ?? null,
|
|
2121
|
+
archiveFilter: snapshot?.archiveFilter ?? DEFAULT_MESSAGING_ARCHIVE_FILTER,
|
|
2122
|
+
setArchiveFilter: (next) => {
|
|
2123
|
+
void host?.engine.setArchiveFilter(next);
|
|
2124
|
+
},
|
|
2125
|
+
archivedCount: snapshot?.archivedCount ?? null,
|
|
2026
2126
|
startDirect: async (otherUserId) => {
|
|
2027
2127
|
if (host === null) {
|
|
2028
2128
|
throw new Error("[@ai-matrx/messaging] startDirect called before the host was ready.");
|
|
@@ -2599,9 +2699,37 @@ var AI_LABELS = {
|
|
|
2599
2699
|
draftReply: "Draft a reply"
|
|
2600
2700
|
};
|
|
2601
2701
|
function ConversationList(props) {
|
|
2602
|
-
const {
|
|
2702
|
+
const {
|
|
2703
|
+
conversations,
|
|
2704
|
+
hasMore,
|
|
2705
|
+
isInitialLoading,
|
|
2706
|
+
loadMore,
|
|
2707
|
+
select,
|
|
2708
|
+
activeConversationId,
|
|
2709
|
+
archiveFilter,
|
|
2710
|
+
setArchiveFilter,
|
|
2711
|
+
archivedCount
|
|
2712
|
+
} = useConversations();
|
|
2603
2713
|
const RowChrome = useMessagingHost()?.wrapConversationRow ?? null;
|
|
2604
2714
|
const [query, setQuery] = useState2("");
|
|
2715
|
+
const showingArchive = archiveFilter === "archived";
|
|
2716
|
+
const archiveReveal = useMemo3(() => {
|
|
2717
|
+
if (showingArchive) {
|
|
2718
|
+
return {
|
|
2719
|
+
next: "active",
|
|
2720
|
+
label: "\u2190 Back to active conversations",
|
|
2721
|
+
ariaLabel: "Hide archived conversations"
|
|
2722
|
+
};
|
|
2723
|
+
}
|
|
2724
|
+
if (archivedCount === null) return null;
|
|
2725
|
+
if (archivedCount.count === 0) return null;
|
|
2726
|
+
const printed = archivedCount.exact ? `${archivedCount.count}` : `${archivedCount.count}+`;
|
|
2727
|
+
return {
|
|
2728
|
+
next: "archived",
|
|
2729
|
+
label: `Archived (${printed})`,
|
|
2730
|
+
ariaLabel: "Show archived conversations"
|
|
2731
|
+
};
|
|
2732
|
+
}, [showingArchive, archivedCount]);
|
|
2605
2733
|
const visible = useMemo3(() => {
|
|
2606
2734
|
const needle = query.trim().toLowerCase();
|
|
2607
2735
|
if (needle.length === 0) return conversations;
|
|
@@ -2634,12 +2762,22 @@ function ConversationList(props) {
|
|
|
2634
2762
|
}
|
|
2635
2763
|
) : null
|
|
2636
2764
|
] }),
|
|
2765
|
+
archiveReveal !== null ? /* @__PURE__ */ jsx4("div", { className: "mx-msg__list-archive", children: /* @__PURE__ */ jsx4(
|
|
2766
|
+
"button",
|
|
2767
|
+
{
|
|
2768
|
+
type: "button",
|
|
2769
|
+
className: "mx-msg__chip",
|
|
2770
|
+
onClick: () => setArchiveFilter(archiveReveal.next),
|
|
2771
|
+
"aria-label": archiveReveal.ariaLabel,
|
|
2772
|
+
children: archiveReveal.label
|
|
2773
|
+
}
|
|
2774
|
+
) }) : null,
|
|
2637
2775
|
/* @__PURE__ */ jsxs2("div", { className: "mx-msg__scroll", children: [
|
|
2638
2776
|
isInitialLoading ? /* @__PURE__ */ jsx4(ConversationSkeleton, {}) : visible.length === 0 ? /* @__PURE__ */ jsx4(
|
|
2639
2777
|
EmptyState,
|
|
2640
2778
|
{
|
|
2641
|
-
title: query.length > 0 ? "No matches" : "No conversations yet",
|
|
2642
|
-
body: query.length > 0 ? "Try a different name or word." : "Start one and it will appear here."
|
|
2779
|
+
title: query.length > 0 ? "No matches" : showingArchive ? "No archived conversations" : "No conversations yet",
|
|
2780
|
+
body: query.length > 0 ? "Try a different name or word." : showingArchive ? "Archiving a conversation moves it here." : "Start one and it will appear here."
|
|
2643
2781
|
}
|
|
2644
2782
|
) : /* @__PURE__ */ jsx4("ul", { className: "mx-msg__rows", children: visible.map((item) => {
|
|
2645
2783
|
const row = /* @__PURE__ */ jsx4(
|
|
@@ -3134,13 +3272,6 @@ function MessagingInbox(props) {
|
|
|
3134
3272
|
}
|
|
3135
3273
|
);
|
|
3136
3274
|
}
|
|
3137
|
-
|
|
3138
|
-
// src/core/types.ts
|
|
3139
|
-
var asConversationId = (value) => value;
|
|
3140
|
-
var asMessageId = (value) => value;
|
|
3141
|
-
var asUserId = (value) => value;
|
|
3142
|
-
var asOrganizationId = (value) => value;
|
|
3143
|
-
var asClientMessageId = (value) => value;
|
|
3144
3275
|
export {
|
|
3145
3276
|
AgentTag,
|
|
3146
3277
|
AlertIcon,
|
|
@@ -3154,6 +3285,7 @@ export {
|
|
|
3154
3285
|
ConversationList,
|
|
3155
3286
|
ConversationSkeleton,
|
|
3156
3287
|
ConversationView,
|
|
3288
|
+
DEFAULT_MESSAGING_ARCHIVE_FILTER,
|
|
3157
3289
|
DeliveryTick,
|
|
3158
3290
|
DoubleCheckIcon,
|
|
3159
3291
|
EmptyState,
|
|
@@ -3216,6 +3348,7 @@ export {
|
|
|
3216
3348
|
resolveActor,
|
|
3217
3349
|
splitText,
|
|
3218
3350
|
summarizeText,
|
|
3351
|
+
toMessagingArchiveFilter,
|
|
3219
3352
|
unreadCutoff,
|
|
3220
3353
|
useComposer,
|
|
3221
3354
|
useConversation,
|