@pmate/chat-sdk 0.12.0-next.33 → 0.12.0-next.34

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.
@@ -261,7 +261,8 @@ export class ChatSession {
261
261
  return { ...recent, messages: [], hasEarlier: false };
262
262
  if (!edge.before)
263
263
  throw new Error("MESSAGE_SYNC_NO_PROGRESS");
264
- const page = await this.getMessages(threadId, { before: edge.before });
264
+ const page = await this.messages.earlier(threadId, edge.before, 100, true);
265
+ await this.sender.confirm(page.messages.map(message => message.id));
265
266
  this.assertOpen();
266
267
  this.rememberHistoryEdge(threadId, page);
267
268
  return page;
@@ -36,6 +36,7 @@ export declare class MessageClient<T extends StoredMessage> {
36
36
  private options;
37
37
  private storage;
38
38
  private watches;
39
+ private windowEdges;
39
40
  private accessListeners;
40
41
  private allListeners;
41
42
  private reads;
@@ -93,7 +94,7 @@ export declare class MessageClient<T extends StoredMessage> {
93
94
  earlier(thread: string, before: {
94
95
  timestamp: number;
95
96
  id: string;
96
- }, limit?: number): Promise<MessageSnapshot<T>>;
97
+ }, limit?: number, expand?: boolean): Promise<MessageSnapshot<T>>;
97
98
  private fillWindow;
98
99
  private denyView;
99
100
  private denyScope;
@@ -6,6 +6,7 @@ export class MessageClient {
6
6
  options;
7
7
  storage;
8
8
  watches = new Map();
9
+ windowEdges = new Map();
9
10
  accessListeners = new Set();
10
11
  allListeners = new Set();
11
12
  reads = new Map();
@@ -252,7 +253,27 @@ export class MessageClient {
252
253
  async reload(thread, fallback = false) {
253
254
  await this.ensureScope();
254
255
  const limit = 100;
255
- const page = await (fallback ? this.storage.readFallback(thread, limit) : this.storage.read(thread, limit));
256
+ let page = await (fallback ? this.storage.readFallback(thread, limit) : this.storage.read(thread, limit));
257
+ const edge = this.windowEdges.get(thread);
258
+ if (edge && edge.version !== (page.coverage?.resetVersion ?? 0))
259
+ this.windowEdges.delete(thread);
260
+ if (edge && edge.version === (page.coverage?.resetVersion ?? 0)) {
261
+ const pages = [page.messages];
262
+ const beforeEdge = (message) => message.timestamp < edge.timestamp || message.timestamp === edge.timestamp && message.id < edge.id;
263
+ let oldest = page.messages[0];
264
+ while (oldest && !beforeEdge(oldest) && (oldest.timestamp !== edge.timestamp || oldest.id !== edge.id) && page.hasEarlier) {
265
+ const next = await (fallback ? this.storage.readFallback(thread, limit, { timestamp: oldest.timestamp, id: oldest.id }) : this.storage.read(thread, limit, { timestamp: oldest.timestamp, id: oldest.id }));
266
+ if ((next.coverage?.resetVersion ?? 0) !== edge.version || (next.coverage?.scopeVersion ?? 0) !== (page.coverage?.scopeVersion ?? 0)) {
267
+ this.windowEdges.delete(thread);
268
+ return this.reload(thread, fallback);
269
+ }
270
+ pages.push(next.messages);
271
+ page = next;
272
+ oldest = next.messages[0];
273
+ }
274
+ const messages = pages.reverse().flat();
275
+ page = { ...page, messages: messages.filter(message => !beforeEdge(message)), hasEarlier: page.hasEarlier || messages.some(beforeEdge) };
276
+ }
256
277
  if (this.closed)
257
278
  throw new Error("MESSAGE_CLIENT_CLOSED");
258
279
  if ((page.coverage?.scopeVersion ?? 0) !== this.scopeVersion) {
@@ -464,7 +485,7 @@ export class MessageClient {
464
485
  this.syncing.set(thread, task);
465
486
  return task;
466
487
  }
467
- async earlier(thread, before, limit = 100) {
488
+ async earlier(thread, before, limit = 100, expand = false) {
468
489
  await this.ensureScope();
469
490
  if (this.scopeDenied)
470
491
  throw new Error("MESSAGE_ACCESS_REVOKED");
@@ -478,7 +499,14 @@ export class MessageClient {
478
499
  throw new Error("MESSAGE_OFFLINE_UNAVAILABLE");
479
500
  await this.synchronize(thread);
480
501
  }
481
- return await this.fillWindow(thread, limit, before);
502
+ const page = await this.fillWindow(thread, limit, before);
503
+ if (expand && page.complete && page.messages.length) {
504
+ const first = page.messages[0], old = this.windowEdges.get(thread);
505
+ if (!old || old.version !== page.resetVersion || first.timestamp < old.timestamp || first.timestamp === old.timestamp && first.id < old.id)
506
+ this.windowEdges.set(thread, { timestamp: first.timestamp, id: first.id, version: page.resetVersion });
507
+ await this.reload(thread);
508
+ }
509
+ return page;
482
510
  }
483
511
  catch (error) {
484
512
  if (String(error).includes("MESSAGE_SCOPE_CHANGED")) {
@@ -538,6 +566,7 @@ export class MessageClient {
538
566
  return { messages: page.messages, hasEarlier: page.hasEarlier || Boolean(page.coverage?.nextBefore), resetVersion: page.coverage?.resetVersion ?? 0, complete: page.coverage?.complete ?? false };
539
567
  }
540
568
  denyView(thread, version) {
569
+ this.windowEdges.delete(thread);
541
570
  this.revoked.add(thread);
542
571
  const watch = this.watches.get(thread);
543
572
  const snapshot = { messages: [], hasEarlier: false, complete: false, resetVersion: Math.max(watch?.snapshot.resetVersion ?? 0, version ?? (watch?.snapshot.resetVersion ?? 0) + 1) };
@@ -619,6 +648,7 @@ export class MessageClient {
619
648
  this.abort.abort();
620
649
  this.channel?.close();
621
650
  this.watches.clear();
651
+ this.windowEdges.clear();
622
652
  this.allListeners.clear();
623
653
  this.accessListeners.clear();
624
654
  this.storage.close();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pmate/chat-sdk",
3
- "version": "0.12.0-next.33",
3
+ "version": "0.12.0-next.34",
4
4
  "description": "Cross-platform PMate chat input components, voice input primitives, and ASR helpers",
5
5
  "type": "module",
6
6
  "main": "./lib/index.js",