@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.cjs
CHANGED
|
@@ -34,6 +34,7 @@ __export(react_exports, {
|
|
|
34
34
|
ConversationList: () => ConversationList,
|
|
35
35
|
ConversationSkeleton: () => ConversationSkeleton,
|
|
36
36
|
ConversationView: () => ConversationView,
|
|
37
|
+
DEFAULT_MESSAGING_ARCHIVE_FILTER: () => DEFAULT_MESSAGING_ARCHIVE_FILTER,
|
|
37
38
|
DeliveryTick: () => DeliveryTick,
|
|
38
39
|
DoubleCheckIcon: () => DoubleCheckIcon,
|
|
39
40
|
EmptyState: () => EmptyState,
|
|
@@ -96,6 +97,7 @@ __export(react_exports, {
|
|
|
96
97
|
resolveActor: () => resolveActor,
|
|
97
98
|
splitText: () => splitText,
|
|
98
99
|
summarizeText: () => summarizeText,
|
|
100
|
+
toMessagingArchiveFilter: () => toMessagingArchiveFilter,
|
|
99
101
|
unreadCutoff: () => unreadCutoff,
|
|
100
102
|
useComposer: () => useComposer,
|
|
101
103
|
useConversation: () => useConversation,
|
|
@@ -914,6 +916,17 @@ function projectConversationSummary(row, viewerId, fallbackOrganizationId) {
|
|
|
914
916
|
};
|
|
915
917
|
}
|
|
916
918
|
|
|
919
|
+
// src/core/types.ts
|
|
920
|
+
var asConversationId = (value) => value;
|
|
921
|
+
var asMessageId = (value) => value;
|
|
922
|
+
var asUserId = (value) => value;
|
|
923
|
+
var asOrganizationId = (value) => value;
|
|
924
|
+
var asClientMessageId = (value) => value;
|
|
925
|
+
var DEFAULT_MESSAGING_ARCHIVE_FILTER = "active";
|
|
926
|
+
function toMessagingArchiveFilter(value, fallback = DEFAULT_MESSAGING_ARCHIVE_FILTER) {
|
|
927
|
+
return value === "active" || value === "archived" || value === "all" ? value : fallback;
|
|
928
|
+
}
|
|
929
|
+
|
|
917
930
|
// src/core/store.ts
|
|
918
931
|
function timeOf(message) {
|
|
919
932
|
const stamp = message.editedAt ?? message.createdAt;
|
|
@@ -944,6 +957,8 @@ function createMessagingStore() {
|
|
|
944
957
|
let conversations = [];
|
|
945
958
|
let hasMoreConversations = false;
|
|
946
959
|
let hasLoadedConversations = false;
|
|
960
|
+
let archiveFilter = DEFAULT_MESSAGING_ARCHIVE_FILTER;
|
|
961
|
+
let archivedCount = null;
|
|
947
962
|
let threads = /* @__PURE__ */ new Map();
|
|
948
963
|
let activeConversationId = null;
|
|
949
964
|
const listeners = /* @__PURE__ */ new Set();
|
|
@@ -956,7 +971,9 @@ function createMessagingStore() {
|
|
|
956
971
|
hasLoadedConversations,
|
|
957
972
|
threads,
|
|
958
973
|
activeConversationId,
|
|
959
|
-
totalUnreadConversations: conversations.filter((item) => item.unreadCount > 0).length
|
|
974
|
+
totalUnreadConversations: conversations.filter((item) => item.unreadCount > 0).length,
|
|
975
|
+
archiveFilter,
|
|
976
|
+
archivedCount
|
|
960
977
|
};
|
|
961
978
|
return cached;
|
|
962
979
|
}
|
|
@@ -1003,6 +1020,18 @@ function createMessagingStore() {
|
|
|
1003
1020
|
hasLoadedConversations = true;
|
|
1004
1021
|
emit();
|
|
1005
1022
|
},
|
|
1023
|
+
setArchiveFilter(next) {
|
|
1024
|
+
if (next === archiveFilter) return;
|
|
1025
|
+
archiveFilter = next;
|
|
1026
|
+
conversations = [];
|
|
1027
|
+
hasMoreConversations = false;
|
|
1028
|
+
hasLoadedConversations = false;
|
|
1029
|
+
emit();
|
|
1030
|
+
},
|
|
1031
|
+
setArchivedCount(value) {
|
|
1032
|
+
archivedCount = value;
|
|
1033
|
+
emit();
|
|
1034
|
+
},
|
|
1006
1035
|
appendConversations(items, hasMore) {
|
|
1007
1036
|
const byId = new Map(conversations.map((item) => [item.conversation.id, item]));
|
|
1008
1037
|
items.forEach((item) => byId.set(item.conversation.id, item));
|
|
@@ -1208,10 +1237,21 @@ function createMessagingEngine(options) {
|
|
|
1208
1237
|
openChannels.get(message.conversationId)?.send(MESSAGING_EVENTS.message, message);
|
|
1209
1238
|
}
|
|
1210
1239
|
async function reloadInbox() {
|
|
1211
|
-
|
|
1240
|
+
if (disposed) return;
|
|
1241
|
+
const page = await repository.listConversations({
|
|
1242
|
+
limit: conversationPageSize,
|
|
1243
|
+
archived: store.snapshot().archiveFilter
|
|
1244
|
+
});
|
|
1245
|
+
if (disposed) return;
|
|
1212
1246
|
conversationCursor = page.nextCursor;
|
|
1213
1247
|
store.setConversations(page.items, page.hasMore);
|
|
1214
1248
|
}
|
|
1249
|
+
async function reloadArchivedCount() {
|
|
1250
|
+
if (disposed) return;
|
|
1251
|
+
const value = await repository.countArchivedConversations();
|
|
1252
|
+
if (disposed) return;
|
|
1253
|
+
store.setArchivedCount(value);
|
|
1254
|
+
}
|
|
1215
1255
|
async function backfillConversation(id) {
|
|
1216
1256
|
const thread = store.snapshot().threads.get(id);
|
|
1217
1257
|
const since = thread?.latestAt ?? null;
|
|
@@ -1238,7 +1278,13 @@ function createMessagingEngine(options) {
|
|
|
1238
1278
|
outbox,
|
|
1239
1279
|
identity,
|
|
1240
1280
|
async start() {
|
|
1281
|
+
if (options.archiveFilter !== void 0) {
|
|
1282
|
+
store.setArchiveFilter(options.archiveFilter);
|
|
1283
|
+
}
|
|
1241
1284
|
await reloadInbox();
|
|
1285
|
+
void reloadArchivedCount().catch(
|
|
1286
|
+
(error) => reportError(error, "refreshArchivedCount")
|
|
1287
|
+
);
|
|
1242
1288
|
if (disposed || inboxChannel !== null) return;
|
|
1243
1289
|
inboxChannel = manager.open({
|
|
1244
1290
|
topic: inboxTopic(identity.userId),
|
|
@@ -1253,7 +1299,7 @@ function createMessagingEngine(options) {
|
|
|
1253
1299
|
const message = projectMessage(row, identity.organizationId);
|
|
1254
1300
|
const known = store.snapshot().conversations.some((item) => item.conversation.id === message.conversationId);
|
|
1255
1301
|
if (!known) {
|
|
1256
|
-
void reloadInbox();
|
|
1302
|
+
void reloadInbox().catch((error) => reportError(error, "inboxRefresh"));
|
|
1257
1303
|
return;
|
|
1258
1304
|
}
|
|
1259
1305
|
store.ingest(message);
|
|
@@ -1269,7 +1315,7 @@ function createMessagingEngine(options) {
|
|
|
1269
1315
|
filter: `user_id=eq.${identity.userId}`,
|
|
1270
1316
|
rowId: (row) => typeof row["id"] === "string" ? row["id"] : void 0,
|
|
1271
1317
|
onChange: () => {
|
|
1272
|
-
void reloadInbox();
|
|
1318
|
+
void reloadInbox().catch((error) => reportError(error, "inboxRefresh"));
|
|
1273
1319
|
}
|
|
1274
1320
|
}
|
|
1275
1321
|
],
|
|
@@ -1280,12 +1326,33 @@ function createMessagingEngine(options) {
|
|
|
1280
1326
|
}
|
|
1281
1327
|
});
|
|
1282
1328
|
},
|
|
1329
|
+
async setArchiveFilter(next) {
|
|
1330
|
+
if (next === store.snapshot().archiveFilter) return;
|
|
1331
|
+
store.setArchiveFilter(next);
|
|
1332
|
+
conversationCursor = null;
|
|
1333
|
+
try {
|
|
1334
|
+
await reloadInbox();
|
|
1335
|
+
} catch (error) {
|
|
1336
|
+
reportError(error, "setArchiveFilter");
|
|
1337
|
+
}
|
|
1338
|
+
await reloadArchivedCount().catch(
|
|
1339
|
+
(error) => reportError(error, "refreshArchivedCount")
|
|
1340
|
+
);
|
|
1341
|
+
},
|
|
1342
|
+
async refreshArchivedCount() {
|
|
1343
|
+
try {
|
|
1344
|
+
await reloadArchivedCount();
|
|
1345
|
+
} catch (error) {
|
|
1346
|
+
reportError(error, "refreshArchivedCount");
|
|
1347
|
+
}
|
|
1348
|
+
},
|
|
1283
1349
|
async loadMoreConversations() {
|
|
1284
1350
|
if (conversationCursor === null) return;
|
|
1285
1351
|
try {
|
|
1286
1352
|
const page = await repository.listConversations({
|
|
1287
1353
|
limit: conversationPageSize,
|
|
1288
|
-
cursor: conversationCursor
|
|
1354
|
+
cursor: conversationCursor,
|
|
1355
|
+
archived: store.snapshot().archiveFilter
|
|
1289
1356
|
});
|
|
1290
1357
|
conversationCursor = page.nextCursor;
|
|
1291
1358
|
store.appendConversations(page.items, page.hasMore);
|
|
@@ -1549,6 +1616,7 @@ function createMessagingRepository(options) {
|
|
|
1549
1616
|
identity,
|
|
1550
1617
|
async listConversations(args = {}) {
|
|
1551
1618
|
const limit = args.limit ?? 30;
|
|
1619
|
+
const archived = args.archived ?? DEFAULT_MESSAGING_ARCHIVE_FILTER;
|
|
1552
1620
|
const operation = "listConversations";
|
|
1553
1621
|
const rows = await withSessionRetry(
|
|
1554
1622
|
operation,
|
|
@@ -1558,7 +1626,12 @@ function createMessagingRepository(options) {
|
|
|
1558
1626
|
p_user_id: identity.userId,
|
|
1559
1627
|
p_limit: limit + 1,
|
|
1560
1628
|
p_before_sort_at: args.cursor?.beforeSortAt ?? null,
|
|
1561
|
-
p_before_conversation_id: args.cursor?.beforeConversationId ?? null
|
|
1629
|
+
p_before_conversation_id: args.cursor?.beforeConversationId ?? null,
|
|
1630
|
+
// THE ARCHIVED-ITEMS LAW, SERVER-side. `get_dm_conversations_with_details`
|
|
1631
|
+
// used to hardcode `is_archived IS FALSE` with no parameter at all,
|
|
1632
|
+
// so an archived conversation was not hidden — it was unreachable.
|
|
1633
|
+
// The RPC gained `p_archived` on 2026-09-09 (register row R1).
|
|
1634
|
+
p_archived: archived
|
|
1562
1635
|
},
|
|
1563
1636
|
operation
|
|
1564
1637
|
)
|
|
@@ -1578,6 +1651,29 @@ function createMessagingRepository(options) {
|
|
|
1578
1651
|
nextCursor: hasMore && last !== void 0 ? { beforeSortAt: last.sortAt, beforeConversationId: last.conversation.id } : null
|
|
1579
1652
|
};
|
|
1580
1653
|
},
|
|
1654
|
+
async countArchivedConversations(args = {}) {
|
|
1655
|
+
const limit = args.limit ?? 100;
|
|
1656
|
+
const operation = "countArchivedConversations";
|
|
1657
|
+
const rows = await withSessionRetry(
|
|
1658
|
+
operation,
|
|
1659
|
+
() => rpc(
|
|
1660
|
+
RPCS.conversationsWithDetails,
|
|
1661
|
+
{
|
|
1662
|
+
p_user_id: identity.userId,
|
|
1663
|
+
p_limit: limit + 1,
|
|
1664
|
+
p_before_sort_at: null,
|
|
1665
|
+
p_before_conversation_id: null,
|
|
1666
|
+
p_archived: "archived"
|
|
1667
|
+
},
|
|
1668
|
+
operation
|
|
1669
|
+
)
|
|
1670
|
+
);
|
|
1671
|
+
if (rows !== null && !Array.isArray(rows)) {
|
|
1672
|
+
throw invalidResponse(operation, `${RPCS.conversationsWithDetails} did not return rows`);
|
|
1673
|
+
}
|
|
1674
|
+
const found = (rows ?? []).length;
|
|
1675
|
+
return found > limit ? { count: limit, exact: false } : { count: found, exact: true };
|
|
1676
|
+
},
|
|
1581
1677
|
async getConversation(id) {
|
|
1582
1678
|
const operation = "getConversation";
|
|
1583
1679
|
const { data, error } = await withSessionRetry(
|
|
@@ -1886,6 +1982,7 @@ function MessagingRuntime(props) {
|
|
|
1886
1982
|
onFallback: (message) => report({ level: "warn", message })
|
|
1887
1983
|
}),
|
|
1888
1984
|
onDiagnostic: report,
|
|
1985
|
+
...props.archiveFilter !== void 0 ? { archiveFilter: props.archiveFilter } : {},
|
|
1889
1986
|
onIncoming: (message) => {
|
|
1890
1987
|
const snapshot = built?.store.snapshot();
|
|
1891
1988
|
if (snapshot === void 0) return;
|
|
@@ -2116,6 +2213,11 @@ function useConversations() {
|
|
|
2116
2213
|
},
|
|
2117
2214
|
select,
|
|
2118
2215
|
activeConversationId: snapshot?.activeConversationId ?? null,
|
|
2216
|
+
archiveFilter: snapshot?.archiveFilter ?? DEFAULT_MESSAGING_ARCHIVE_FILTER,
|
|
2217
|
+
setArchiveFilter: (next) => {
|
|
2218
|
+
void host?.engine.setArchiveFilter(next);
|
|
2219
|
+
},
|
|
2220
|
+
archivedCount: snapshot?.archivedCount ?? null,
|
|
2119
2221
|
startDirect: async (otherUserId) => {
|
|
2120
2222
|
if (host === null) {
|
|
2121
2223
|
throw new Error("[@ai-matrx/messaging] startDirect called before the host was ready.");
|
|
@@ -2687,9 +2789,37 @@ var AI_LABELS = {
|
|
|
2687
2789
|
draftReply: "Draft a reply"
|
|
2688
2790
|
};
|
|
2689
2791
|
function ConversationList(props) {
|
|
2690
|
-
const {
|
|
2792
|
+
const {
|
|
2793
|
+
conversations,
|
|
2794
|
+
hasMore,
|
|
2795
|
+
isInitialLoading,
|
|
2796
|
+
loadMore,
|
|
2797
|
+
select,
|
|
2798
|
+
activeConversationId,
|
|
2799
|
+
archiveFilter,
|
|
2800
|
+
setArchiveFilter,
|
|
2801
|
+
archivedCount
|
|
2802
|
+
} = useConversations();
|
|
2691
2803
|
const RowChrome = useMessagingHost()?.wrapConversationRow ?? null;
|
|
2692
2804
|
const [query, setQuery] = (0, import_react5.useState)("");
|
|
2805
|
+
const showingArchive = archiveFilter === "archived";
|
|
2806
|
+
const archiveReveal = (0, import_react5.useMemo)(() => {
|
|
2807
|
+
if (showingArchive) {
|
|
2808
|
+
return {
|
|
2809
|
+
next: "active",
|
|
2810
|
+
label: "\u2190 Back to active conversations",
|
|
2811
|
+
ariaLabel: "Hide archived conversations"
|
|
2812
|
+
};
|
|
2813
|
+
}
|
|
2814
|
+
if (archivedCount === null) return null;
|
|
2815
|
+
if (archivedCount.count === 0) return null;
|
|
2816
|
+
const printed = archivedCount.exact ? `${archivedCount.count}` : `${archivedCount.count}+`;
|
|
2817
|
+
return {
|
|
2818
|
+
next: "archived",
|
|
2819
|
+
label: `Archived (${printed})`,
|
|
2820
|
+
ariaLabel: "Show archived conversations"
|
|
2821
|
+
};
|
|
2822
|
+
}, [showingArchive, archivedCount]);
|
|
2693
2823
|
const visible = (0, import_react5.useMemo)(() => {
|
|
2694
2824
|
const needle = query.trim().toLowerCase();
|
|
2695
2825
|
if (needle.length === 0) return conversations;
|
|
@@ -2722,12 +2852,22 @@ function ConversationList(props) {
|
|
|
2722
2852
|
}
|
|
2723
2853
|
) : null
|
|
2724
2854
|
] }),
|
|
2855
|
+
archiveReveal !== null ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "mx-msg__list-archive", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
2856
|
+
"button",
|
|
2857
|
+
{
|
|
2858
|
+
type: "button",
|
|
2859
|
+
className: "mx-msg__chip",
|
|
2860
|
+
onClick: () => setArchiveFilter(archiveReveal.next),
|
|
2861
|
+
"aria-label": archiveReveal.ariaLabel,
|
|
2862
|
+
children: archiveReveal.label
|
|
2863
|
+
}
|
|
2864
|
+
) }) : null,
|
|
2725
2865
|
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "mx-msg__scroll", children: [
|
|
2726
2866
|
isInitialLoading ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(ConversationSkeleton, {}) : visible.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
2727
2867
|
EmptyState,
|
|
2728
2868
|
{
|
|
2729
|
-
title: query.length > 0 ? "No matches" : "No conversations yet",
|
|
2730
|
-
body: query.length > 0 ? "Try a different name or word." : "Start one and it will appear here."
|
|
2869
|
+
title: query.length > 0 ? "No matches" : showingArchive ? "No archived conversations" : "No conversations yet",
|
|
2870
|
+
body: query.length > 0 ? "Try a different name or word." : showingArchive ? "Archiving a conversation moves it here." : "Start one and it will appear here."
|
|
2731
2871
|
}
|
|
2732
2872
|
) : /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("ul", { className: "mx-msg__rows", children: visible.map((item) => {
|
|
2733
2873
|
const row = /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
@@ -3222,11 +3362,4 @@ function MessagingInbox(props) {
|
|
|
3222
3362
|
}
|
|
3223
3363
|
);
|
|
3224
3364
|
}
|
|
3225
|
-
|
|
3226
|
-
// src/core/types.ts
|
|
3227
|
-
var asConversationId = (value) => value;
|
|
3228
|
-
var asMessageId = (value) => value;
|
|
3229
|
-
var asUserId = (value) => value;
|
|
3230
|
-
var asOrganizationId = (value) => value;
|
|
3231
|
-
var asClientMessageId = (value) => value;
|
|
3232
3365
|
//# sourceMappingURL=react.cjs.map
|