@ai-matrx/messaging 0.2.0 → 0.3.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 +32 -0
- package/README.md +21 -0
- package/dist/react.cjs +62 -24
- package/dist/react.cjs.map +1 -1
- package/dist/react.d.cts +63 -4
- package/dist/react.d.ts +63 -4
- package/dist/react.js +62 -24
- package/dist/react.js.map +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,37 @@
|
|
|
1
1
|
# Changelog — `@ai-matrx/messaging`
|
|
2
2
|
|
|
3
|
+
## 0.3.0 — 2026-09-07
|
|
4
|
+
|
|
5
|
+
**Three more seams the first adoption needed** — each one a case where the host
|
|
6
|
+
would otherwise have kept a piece of its own messaging UI beside this package's,
|
|
7
|
+
which is the failure this package exists to prevent. Same session as 0.2.0.
|
|
8
|
+
|
|
9
|
+
### Added
|
|
10
|
+
|
|
11
|
+
- **`wrapMessage` / `wrapConversationRow` — app chrome around a bubble and a row.**
|
|
12
|
+
The reason is the right-click menu: a platform whose every surface answers a right-click with
|
|
13
|
+
copy / export / attach / hand-to-an-agent cannot have messaging be the one surface that does
|
|
14
|
+
not, and that menu needs the app's surface name, entity tokens and clipboard primitive — none
|
|
15
|
+
of which a package can own. The wrapper WRAPS the package's bubble; it cannot replace it.
|
|
16
|
+
- **`renderReference` — the host's own reference renderer.** References are the one part of a
|
|
17
|
+
bubble an app is most likely to already render everywhere else (this platform resolves a
|
|
18
|
+
```matrx fence through a kind registry into a live chip). Two treatments of one fence in one
|
|
19
|
+
app is the second-renderer defect. Omit it and the package's card is used, unchanged.
|
|
20
|
+
- **`onIncomingMessage` now receives an `IncomingMessageContext`** —
|
|
21
|
+
`{ isActiveConversation, conversation }`. "Do not interrupt someone for the conversation they
|
|
22
|
+
are looking at" is the rule every chat app needs and only this package can answer, and a
|
|
23
|
+
desktop notification names the SENDER, whose display name lives on a conversation the host
|
|
24
|
+
cannot see from above the provider. (The origin surface had `sender_id.substring(0, 8)` and a
|
|
25
|
+
`// Placeholder` comment where the name belonged.)
|
|
26
|
+
|
|
27
|
+
### Consumer action (C28)
|
|
28
|
+
|
|
29
|
+
- `onIncomingMessage` gains a SECOND argument. Existing one-argument callbacks keep compiling and
|
|
30
|
+
keep working — but if you were suppressing notifications for the open conversation by reading
|
|
31
|
+
your own state, delete that and read `context.isActiveConversation`.
|
|
32
|
+
- Hosts with their own reference chips or per-row context menus: pass `renderReference` /
|
|
33
|
+
`wrapMessage` / `wrapConversationRow` and DELETE the host-side message list.
|
|
34
|
+
|
|
3
35
|
## 0.2.0 — 2026-09-07
|
|
4
36
|
|
|
5
37
|
**Both fixes came from the first real adoption** (matrx-frontend, the C9 full-elimination swap).
|
package/README.md
CHANGED
|
@@ -241,6 +241,27 @@ rule that matters: an unknown kind — or a known kind at a version this build d
|
|
|
241
241
|
renders NOTHING. Use `actions` for decisions, `actionRenderers` for surfaces; a kind may have
|
|
242
242
|
both a handler (for `summarize`, used by previews) and a renderer.
|
|
243
243
|
|
|
244
|
+
### Your app's chrome around our bubbles
|
|
245
|
+
|
|
246
|
+
A platform whose surfaces all answer a right-click, or that already renders references through
|
|
247
|
+
its own registry, hands those in rather than rebuilding the thread:
|
|
248
|
+
|
|
249
|
+
```tsx
|
|
250
|
+
<MessagingProvider …
|
|
251
|
+
wrapMessage={({ message, children }) => (
|
|
252
|
+
<MessageContextMenu message={message}>{children}</MessageContextMenu>
|
|
253
|
+
)}
|
|
254
|
+
wrapConversationRow={({ conversation, children }) => (
|
|
255
|
+
<ConversationContextMenu conversation={conversation}>{children}</ConversationContextMenu>
|
|
256
|
+
)}
|
|
257
|
+
renderReference={({ reference }) => <AppReferenceChip reference={reference} />}
|
|
258
|
+
/>
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
`wrapMessage` and `wrapConversationRow` WRAP; they never replace. `renderReference` replaces the
|
|
262
|
+
package's card — deliberately, because an app that draws references everywhere else must not
|
|
263
|
+
draw them two ways.
|
|
264
|
+
|
|
244
265
|
### Theming
|
|
245
266
|
|
|
246
267
|
Structural CSS ships in the package; the token **contract** is enforced; token **values** are
|
package/dist/react.cjs
CHANGED
|
@@ -1831,7 +1831,8 @@ function MessagingRuntime(props) {
|
|
|
1831
1831
|
identity,
|
|
1832
1832
|
...props.resolveSession !== void 0 ? { resolveSession: props.resolveSession } : {}
|
|
1833
1833
|
});
|
|
1834
|
-
|
|
1834
|
+
let built = null;
|
|
1835
|
+
built = createMessagingEngine({
|
|
1835
1836
|
repository,
|
|
1836
1837
|
manager,
|
|
1837
1838
|
identity,
|
|
@@ -1840,8 +1841,18 @@ function MessagingRuntime(props) {
|
|
|
1840
1841
|
onFallback: (message) => report({ level: "warn", message })
|
|
1841
1842
|
}),
|
|
1842
1843
|
onDiagnostic: report,
|
|
1843
|
-
onIncoming: (message) =>
|
|
1844
|
+
onIncoming: (message) => {
|
|
1845
|
+
const snapshot = built?.store.snapshot();
|
|
1846
|
+
if (snapshot === void 0) return;
|
|
1847
|
+
incomingRef.current?.(message, {
|
|
1848
|
+
isActiveConversation: snapshot.activeConversationId === message.conversationId,
|
|
1849
|
+
conversation: snapshot.conversations.find(
|
|
1850
|
+
(item) => item.conversation.id === message.conversationId
|
|
1851
|
+
) ?? null
|
|
1852
|
+
});
|
|
1853
|
+
}
|
|
1844
1854
|
});
|
|
1855
|
+
return built;
|
|
1845
1856
|
}, [ready, manager, userId, organizationId]);
|
|
1846
1857
|
(0, import_react.useEffect)(() => {
|
|
1847
1858
|
if (engine === null) return void 0;
|
|
@@ -1874,6 +1885,9 @@ function MessagingRuntime(props) {
|
|
|
1874
1885
|
});
|
|
1875
1886
|
return map;
|
|
1876
1887
|
}, [renderers]);
|
|
1888
|
+
const renderReference = props.renderReference ?? null;
|
|
1889
|
+
const wrapMessage = props.wrapMessage ?? null;
|
|
1890
|
+
const wrapConversationRow = props.wrapConversationRow ?? null;
|
|
1877
1891
|
const host = (0, import_react.useMemo)(() => {
|
|
1878
1892
|
if (engine === null) return null;
|
|
1879
1893
|
return {
|
|
@@ -1882,9 +1896,12 @@ function MessagingRuntime(props) {
|
|
|
1882
1896
|
ai,
|
|
1883
1897
|
identity: engine.identity,
|
|
1884
1898
|
openReference: referenceRef.current ?? null,
|
|
1885
|
-
actionRenderers: rendererMap
|
|
1899
|
+
actionRenderers: rendererMap,
|
|
1900
|
+
renderReference,
|
|
1901
|
+
wrapMessage,
|
|
1902
|
+
wrapConversationRow
|
|
1886
1903
|
};
|
|
1887
|
-
}, [engine, actionRegistry, ai, rendererMap]);
|
|
1904
|
+
}, [engine, actionRegistry, ai, rendererMap, renderReference, wrapMessage, wrapConversationRow]);
|
|
1888
1905
|
const MessagingContext = messagingContext();
|
|
1889
1906
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(MessagingContext.Provider, { value: host, children });
|
|
1890
1907
|
}
|
|
@@ -2555,6 +2572,7 @@ var AI_LABELS = {
|
|
|
2555
2572
|
};
|
|
2556
2573
|
function ConversationList(props) {
|
|
2557
2574
|
const { conversations, hasMore, isInitialLoading, loadMore, select, activeConversationId } = useConversations();
|
|
2575
|
+
const RowChrome = useMessagingHost()?.wrapConversationRow ?? null;
|
|
2558
2576
|
const [query, setQuery] = (0, import_react5.useState)("");
|
|
2559
2577
|
const visible = (0, import_react5.useMemo)(() => {
|
|
2560
2578
|
const needle = query.trim().toLowerCase();
|
|
@@ -2595,17 +2613,20 @@ function ConversationList(props) {
|
|
|
2595
2613
|
title: query.length > 0 ? "No matches" : "No conversations yet",
|
|
2596
2614
|
body: query.length > 0 ? "Try a different name or word." : "Start one and it will appear here."
|
|
2597
2615
|
}
|
|
2598
|
-
) : /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("ul", { className: "mx-msg__rows", children: visible.map((item) =>
|
|
2599
|
-
|
|
2600
|
-
|
|
2601
|
-
|
|
2602
|
-
|
|
2603
|
-
|
|
2604
|
-
|
|
2605
|
-
|
|
2616
|
+
) : /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("ul", { className: "mx-msg__rows", children: visible.map((item) => {
|
|
2617
|
+
const row = /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
2618
|
+
ConversationRow,
|
|
2619
|
+
{
|
|
2620
|
+
summary: item,
|
|
2621
|
+
isActive: item.conversation.id === activeConversationId,
|
|
2622
|
+
onSelect: () => {
|
|
2623
|
+
select(item.conversation.id);
|
|
2624
|
+
props.onSelect?.(item.conversation.id);
|
|
2625
|
+
}
|
|
2606
2626
|
}
|
|
2607
|
-
|
|
2608
|
-
|
|
2627
|
+
);
|
|
2628
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("li", { children: RowChrome !== null ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(RowChrome, { conversation: item, children: row }) : row }, item.conversation.id);
|
|
2629
|
+
}) }),
|
|
2609
2630
|
hasMore && !isInitialLoading ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
2610
2631
|
"button",
|
|
2611
2632
|
{
|
|
@@ -2834,6 +2855,8 @@ function MessageGroupView(props) {
|
|
|
2834
2855
|
function MessageBubble(props) {
|
|
2835
2856
|
const { message, isMine } = props;
|
|
2836
2857
|
const host = useMessagingHost();
|
|
2858
|
+
const HostReference = host?.renderReference ?? null;
|
|
2859
|
+
const MessageChrome = host?.wrapMessage ?? null;
|
|
2837
2860
|
if (message.deletedAt !== null) {
|
|
2838
2861
|
return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "mx-msg__bubble mx-msg__bubble--deleted", children: "Message deleted" });
|
|
2839
2862
|
}
|
|
@@ -2844,10 +2867,16 @@ function MessageBubble(props) {
|
|
|
2844
2867
|
message.deliveryState === "sending" ? "mx-msg__bubble--pending" : "",
|
|
2845
2868
|
message.deliveryState === "failed" ? "mx-msg__bubble--failed" : ""
|
|
2846
2869
|
].filter(Boolean).join(" ");
|
|
2847
|
-
|
|
2870
|
+
const bubble = /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_jsx_runtime4.Fragment, { children: [
|
|
2848
2871
|
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: classes, children: [
|
|
2849
2872
|
splitText(message.content).map(
|
|
2850
|
-
(segment, index) => segment.type === "text" ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { children: segment.value }, index) : /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
2873
|
+
(segment, index) => segment.type === "text" ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { children: segment.value }, index) : HostReference !== null ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
2874
|
+
HostReference,
|
|
2875
|
+
{
|
|
2876
|
+
reference: segment.reference
|
|
2877
|
+
},
|
|
2878
|
+
`${segment.reference.entityType}:${segment.reference.entityId}`
|
|
2879
|
+
) : /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
2851
2880
|
ReferenceCard,
|
|
2852
2881
|
{
|
|
2853
2882
|
reference: segment.reference,
|
|
@@ -2856,14 +2885,22 @@ function MessageBubble(props) {
|
|
|
2856
2885
|
`${segment.reference.entityType}:${segment.reference.entityId}`
|
|
2857
2886
|
)
|
|
2858
2887
|
),
|
|
2859
|
-
message.references.map(
|
|
2860
|
-
|
|
2861
|
-
|
|
2862
|
-
|
|
2863
|
-
|
|
2864
|
-
|
|
2865
|
-
|
|
2866
|
-
|
|
2888
|
+
message.references.map(
|
|
2889
|
+
(reference) => HostReference !== null ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
2890
|
+
HostReference,
|
|
2891
|
+
{
|
|
2892
|
+
reference
|
|
2893
|
+
},
|
|
2894
|
+
`structured:${reference.entityType}:${reference.entityId}`
|
|
2895
|
+
) : /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
2896
|
+
ReferenceCard,
|
|
2897
|
+
{
|
|
2898
|
+
reference,
|
|
2899
|
+
onOpen: host?.openReference ?? null
|
|
2900
|
+
},
|
|
2901
|
+
`structured:${reference.entityType}:${reference.entityId}`
|
|
2902
|
+
)
|
|
2903
|
+
),
|
|
2867
2904
|
message.action !== null ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(MessageActionChips, { message }) : null
|
|
2868
2905
|
] }),
|
|
2869
2906
|
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
|
|
@@ -2899,6 +2936,7 @@ function MessageBubble(props) {
|
|
|
2899
2936
|
}
|
|
2900
2937
|
)
|
|
2901
2938
|
] });
|
|
2939
|
+
return MessageChrome !== null ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(MessageChrome, { message, isMine, children: bubble }) : bubble;
|
|
2902
2940
|
}
|
|
2903
2941
|
function MessageActionChips(props) {
|
|
2904
2942
|
const host = useRequiredMessagingHost();
|