@natoe/colab 0.1.14 → 0.1.16

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/dist/index.d.mts CHANGED
@@ -380,6 +380,20 @@ type PresenceCallback = (presences: Record<string, {
380
380
  userId: string;
381
381
  isOnline: boolean;
382
382
  }>) => void;
383
+ /**
384
+ * Server-pushed unread counts. The backend broadcasts BOTH keyings in
385
+ * one payload so consumers can render badges at either granularity (FAB
386
+ * + inbox row use `conversation`; table-row chat icons use `order`) off
387
+ * a single socket event. Legacy backends that send a flat
388
+ * `Record<string, number>` are normalised at the socket boundary into
389
+ * `{ conversation: <flat>, order: {} }` for forward compatibility.
390
+ */
391
+ interface UnreadCounts {
392
+ /** keyed by conversation id */
393
+ conversation: Record<string, number>;
394
+ /** keyed by order id — used for table-row chat-icon badges */
395
+ order: Record<string, number>;
396
+ }
383
397
  interface ConversationCallbacks {
384
398
  onMessage?: MessageCallback;
385
399
  onTyping?: TypingCallback;
@@ -433,8 +447,10 @@ declare class CollabSocket {
433
447
  connect(config: CollabConfig): void;
434
448
  /** Subscribe to user-level events (unread counts, notifications) */
435
449
  private joinUserChannel;
436
- /** Register callback for unread count changes */
437
- onUnreadCountUpdate(callback: (counts: Record<string, number>) => void): void;
450
+ /** Register callback for unread count changes. The callback receives
451
+ * the normalised {@link UnreadCounts} shape regardless of which
452
+ * payload format the backend pushed. */
453
+ onUnreadCountUpdate(callback: (counts: UnreadCounts) => void): void;
438
454
  /**
439
455
  * Join a conversation channel and subscribe to events.
440
456
  *
@@ -512,6 +528,13 @@ interface CollabContextValue {
512
528
  * mounting their own useConversation.
513
529
  */
514
530
  unreadCounts: Record<string, number>;
531
+ /**
532
+ * Same unread counts, but keyed by **order ID** instead of
533
+ * conversation ID. Useful for table-row chat-icon badges where the
534
+ * row only knows its order_id, not the conversation_id. Same socket
535
+ * push updates both maps in lock-step.
536
+ */
537
+ unreadCountsByOrder: Record<string, number>;
515
538
  /** Batched preview lookup — coalesces calls within a microtask */
516
539
  requestPreview: (orderId: string) => Promise<ConversationPreview | null>;
517
540
  /** Invalidate a cached preview (e.g. when a new message arrives) */
package/dist/index.d.ts CHANGED
@@ -380,6 +380,20 @@ type PresenceCallback = (presences: Record<string, {
380
380
  userId: string;
381
381
  isOnline: boolean;
382
382
  }>) => void;
383
+ /**
384
+ * Server-pushed unread counts. The backend broadcasts BOTH keyings in
385
+ * one payload so consumers can render badges at either granularity (FAB
386
+ * + inbox row use `conversation`; table-row chat icons use `order`) off
387
+ * a single socket event. Legacy backends that send a flat
388
+ * `Record<string, number>` are normalised at the socket boundary into
389
+ * `{ conversation: <flat>, order: {} }` for forward compatibility.
390
+ */
391
+ interface UnreadCounts {
392
+ /** keyed by conversation id */
393
+ conversation: Record<string, number>;
394
+ /** keyed by order id — used for table-row chat-icon badges */
395
+ order: Record<string, number>;
396
+ }
383
397
  interface ConversationCallbacks {
384
398
  onMessage?: MessageCallback;
385
399
  onTyping?: TypingCallback;
@@ -433,8 +447,10 @@ declare class CollabSocket {
433
447
  connect(config: CollabConfig): void;
434
448
  /** Subscribe to user-level events (unread counts, notifications) */
435
449
  private joinUserChannel;
436
- /** Register callback for unread count changes */
437
- onUnreadCountUpdate(callback: (counts: Record<string, number>) => void): void;
450
+ /** Register callback for unread count changes. The callback receives
451
+ * the normalised {@link UnreadCounts} shape regardless of which
452
+ * payload format the backend pushed. */
453
+ onUnreadCountUpdate(callback: (counts: UnreadCounts) => void): void;
438
454
  /**
439
455
  * Join a conversation channel and subscribe to events.
440
456
  *
@@ -512,6 +528,13 @@ interface CollabContextValue {
512
528
  * mounting their own useConversation.
513
529
  */
514
530
  unreadCounts: Record<string, number>;
531
+ /**
532
+ * Same unread counts, but keyed by **order ID** instead of
533
+ * conversation ID. Useful for table-row chat-icon badges where the
534
+ * row only knows its order_id, not the conversation_id. Same socket
535
+ * push updates both maps in lock-step.
536
+ */
537
+ unreadCountsByOrder: Record<string, number>;
515
538
  /** Batched preview lookup — coalesces calls within a microtask */
516
539
  requestPreview: (orderId: string) => Promise<ConversationPreview | null>;
517
540
  /** Invalidate a cached preview (e.g. when a new message arrives) */
package/dist/index.js CHANGED
@@ -63,6 +63,19 @@ function toCamelKey(key) {
63
63
  }
64
64
 
65
65
  // src/core/socket.ts
66
+ function normalizeUnreadPayload(payload) {
67
+ if (payload && typeof payload === "object") {
68
+ const obj = payload;
69
+ if (obj.conversation && typeof obj.conversation === "object") {
70
+ return {
71
+ conversation: obj.conversation,
72
+ order: obj.order && typeof obj.order === "object" ? obj.order : {}
73
+ };
74
+ }
75
+ return { conversation: payload, order: {} };
76
+ }
77
+ return { conversation: {}, order: {} };
78
+ }
66
79
  var CollabSocket = class {
67
80
  constructor() {
68
81
  this.socket = null;
@@ -128,7 +141,7 @@ var CollabSocket = class {
128
141
  if (!this.socket || !this.config) return;
129
142
  this.userChannel = this.socket.channel("user_notifications", {});
130
143
  this.userChannel.on("unread_update", (payload) => {
131
- this.onUnreadUpdate?.(payload);
144
+ this.onUnreadUpdate?.(normalizeUnreadPayload(payload));
132
145
  });
133
146
  this.userChannel.join().receive("ok", () => {
134
147
  }).receive("error", (reason) => {
@@ -139,7 +152,9 @@ var CollabSocket = class {
139
152
  });
140
153
  });
141
154
  }
142
- /** Register callback for unread count changes */
155
+ /** Register callback for unread count changes. The callback receives
156
+ * the normalised {@link UnreadCounts} shape regardless of which
157
+ * payload format the backend pushed. */
143
158
  onUnreadCountUpdate(callback) {
144
159
  this.onUnreadUpdate = callback;
145
160
  }
@@ -583,6 +598,7 @@ function CollabProvider({ config, apiBaseUrl, children }) {
583
598
  return new CollabSocket();
584
599
  });
585
600
  const [unreadCounts, setUnreadCounts] = React4.useState({});
601
+ const [unreadCountsByOrder, setUnreadCountsByOrder] = React4.useState({});
586
602
  const pendingOrderIds = React4.useRef(/* @__PURE__ */ new Set());
587
603
  const pendingResolvers = React4.useRef(/* @__PURE__ */ new Map());
588
604
  const previewCache = React4.useRef(/* @__PURE__ */ new Map());
@@ -598,7 +614,8 @@ function CollabProvider({ config, apiBaseUrl, children }) {
598
614
  setSocket(s);
599
615
  }
600
616
  s.onUnreadCountUpdate((counts) => {
601
- setUnreadCounts(counts);
617
+ setUnreadCounts(counts.conversation);
618
+ setUnreadCountsByOrder(counts.order);
602
619
  previewCache.current.clear();
603
620
  });
604
621
  if (!s.isConnected()) {
@@ -806,6 +823,7 @@ function CollabProvider({ config, apiBaseUrl, children }) {
806
823
  apiBaseUrl,
807
824
  totalUnread,
808
825
  unreadCounts,
826
+ unreadCountsByOrder,
809
827
  requestPreview,
810
828
  invalidatePreview,
811
829
  fetchMessages,
@@ -6327,7 +6345,7 @@ function useUnreadCount() {
6327
6345
  const [counts, setCounts] = React4.useState({});
6328
6346
  React4.useEffect(() => {
6329
6347
  socket.onUnreadCountUpdate((serverCounts) => {
6330
- setCounts(serverCounts);
6348
+ setCounts(serverCounts.conversation);
6331
6349
  });
6332
6350
  }, [socket]);
6333
6351
  const getCountForConversation = React4.useCallback(