feat(messenger): paged history + scrollback (SDK 0.3.0, kernel-client 0.2.0)
CrmMessagingAdapter.historyPage returns {messages, hasMore}. The socket path
(openThread) serves the newest page since it also joins the room; scrollback has
no socket verb, so `before` goes over the data door — by then the room is already
joined, so nothing live is missed either way.
Opening a long thread now loads one page instead of every message ever sent, and
the SDK renders a "Load older messages" control.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Generated
+9
-9
@@ -11,8 +11,8 @@
|
||||
"@abe-kap/appshell-sdk": "^0.2.6",
|
||||
"@huggingface/transformers": "^4.2.0",
|
||||
"@imgly/background-removal": "^1.7.0",
|
||||
"@insignia/iios-kernel-client": "^0.1.6",
|
||||
"@insignia/iios-messaging-ui": "^0.2.0",
|
||||
"@insignia/iios-kernel-client": "^0.2.0",
|
||||
"@insignia/iios-messaging-ui": "^0.3.0",
|
||||
"@photo-gallery/sdk": "file:./vendor/photo-gallery-sdk",
|
||||
"@tanstack/react-query": "^5.101.4",
|
||||
"@tensorflow-models/coco-ssd": "^2.2.3",
|
||||
@@ -1103,20 +1103,20 @@
|
||||
"integrity": "sha512-+ycbP8ORdwllMtn7dmxIL7lnDpDDkV+gHqT2OKJtMplMivjKU03gsuuEveQxnrE1CMvZ3fcSljmfMs10Cw131g=="
|
||||
},
|
||||
"node_modules/@insignia/iios-kernel-client": {
|
||||
"version": "0.1.6",
|
||||
"resolved": "https://git.lynkedup.cloud/api/packages/insignia/npm/%40insignia%2Fiios-kernel-client/-/0.1.6/iios-kernel-client-0.1.6.tgz",
|
||||
"integrity": "sha512-QfjqaGj8acKfwWQvYsf6Rxj1TeLQN+3fNTTlL+PkAP2usAxcdSkgRKkfHxy9FrhoxLXahQBuOn3wnUzd6Qh39Q==",
|
||||
"version": "0.2.0",
|
||||
"resolved": "https://git.lynkedup.cloud/api/packages/insignia/npm/%40insignia%2Fiios-kernel-client/-/0.2.0/iios-kernel-client-0.2.0.tgz",
|
||||
"integrity": "sha512-/uO/FocOYZpaDvaP08UYX3ISk8bUaSUnNj1mRHfZkE8oBJSBOs1ZPJ21t6V1FFhlFI+FjEMaysJKJi1sRDTl8Q==",
|
||||
"dependencies": {
|
||||
"@insignia/iios-contracts": "0.1.0",
|
||||
"socket.io-client": "^4.8.1"
|
||||
}
|
||||
},
|
||||
"node_modules/@insignia/iios-messaging-ui": {
|
||||
"version": "0.2.0",
|
||||
"resolved": "https://git.lynkedup.cloud/api/packages/insignia/npm/%40insignia%2Fiios-messaging-ui/-/0.2.0/iios-messaging-ui-0.2.0.tgz",
|
||||
"integrity": "sha512-eM3K9CMtPumTvpoL7FrX+RcdKylhIDgMDZ4/7GCGoe6P1lj+HcAMmUX38cyLx7qq21DaDMnUcq3RNMW69gsDNw==",
|
||||
"version": "0.3.0",
|
||||
"resolved": "https://git.lynkedup.cloud/api/packages/insignia/npm/%40insignia%2Fiios-messaging-ui/-/0.3.0/iios-messaging-ui-0.3.0.tgz",
|
||||
"integrity": "sha512-LFxqVk+RY6E2foR38yll2Q18Qd1mNl9YTONENw+fy1Dt2IDAVMcfN73DCJ8AQjwAsZoTqjsWDfMxgGKyLWT2Uw==",
|
||||
"peerDependencies": {
|
||||
"@insignia/iios-kernel-client": "*",
|
||||
"@insignia/iios-kernel-client": ">=0.2.0",
|
||||
"@tanstack/react-query": ">=5",
|
||||
"react": ">=18",
|
||||
"react-dom": ">=18"
|
||||
|
||||
+2
-2
@@ -13,8 +13,8 @@
|
||||
"@abe-kap/appshell-sdk": "^0.2.6",
|
||||
"@huggingface/transformers": "^4.2.0",
|
||||
"@imgly/background-removal": "^1.7.0",
|
||||
"@insignia/iios-kernel-client": "^0.1.6",
|
||||
"@insignia/iios-messaging-ui": "^0.2.0",
|
||||
"@insignia/iios-kernel-client": "^0.2.0",
|
||||
"@insignia/iios-messaging-ui": "^0.3.0",
|
||||
"@photo-gallery/sdk": "file:./vendor/photo-gallery-sdk",
|
||||
"@tanstack/react-query": "^5.101.4",
|
||||
"@tensorflow-models/coco-ssd": "^2.2.3",
|
||||
|
||||
@@ -136,21 +136,39 @@ export class CrmMessagingAdapter implements MessagingAdapter {
|
||||
return { threadId: res.threadId };
|
||||
}
|
||||
|
||||
async history(threadId: string): Promise<Message[]> {
|
||||
if (this.socket) {
|
||||
// openThread both JOINS the room and returns history, so it is the only call needed on a
|
||||
// cache miss. The SDK caches per thread, so this no longer fires on every selection.
|
||||
const res = await this.socket.openThread(threadId);
|
||||
async history(threadId: string, opts?: { limit?: number; before?: string }): Promise<Message[]> {
|
||||
return (await this.historyPage(threadId, opts)).messages;
|
||||
}
|
||||
|
||||
/**
|
||||
* A page of history plus whether older messages exist.
|
||||
*
|
||||
* Socket path: openThread both JOINS the room and returns the newest page, so it is the only call
|
||||
* needed on a cache miss. Scrollback (`before`) has no socket verb, so it goes over the door —
|
||||
* the room is already joined by then, so nothing live is missed.
|
||||
*/
|
||||
async historyPage(
|
||||
threadId: string,
|
||||
opts?: { limit?: number; before?: string },
|
||||
): Promise<{ messages: Message[]; hasMore: boolean }> {
|
||||
if (this.socket && !opts?.before) {
|
||||
const res = await this.socket.openThread(threadId, { ...(opts?.limit ? { limit: opts.limit } : {}) });
|
||||
this.joined.add(threadId);
|
||||
return Promise.all(
|
||||
const messages = await Promise.all(
|
||||
res.history.map((m) => {
|
||||
this.ingestReactions(m);
|
||||
return this.toKernelMessage(m);
|
||||
}),
|
||||
);
|
||||
return { messages, hasMore: res.hasMore ?? false };
|
||||
}
|
||||
const msgs = await this.sdk.query<MessageDTO[]>("crm.messenger.history", { threadId });
|
||||
return Promise.all(msgs.map((m) => this.toDtoMessage(m)));
|
||||
const res = await this.sdk.query<{ messages: MessageDTO[]; hasMore: boolean }>("crm.messenger.history", {
|
||||
threadId,
|
||||
...(opts?.limit ? { limit: opts.limit } : {}),
|
||||
...(opts?.before ? { before: opts.before } : {}),
|
||||
});
|
||||
const messages = await Promise.all(res.messages.map((m) => this.toDtoMessage(m)));
|
||||
return { messages, hasMore: res.hasMore ?? false };
|
||||
}
|
||||
|
||||
async send(threadId: string, content: string, opts?: SendOpts): Promise<Message> {
|
||||
|
||||
Reference in New Issue
Block a user