@antzsoft/chat-core 1.1.0 → 1.1.2
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/README.md +55 -20
- package/dist/index.cjs +381 -29
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +37 -31
- package/dist/index.d.ts +37 -31
- package/dist/index.js +380 -29
- package/dist/index.js.map +1 -1
- package/docs/integration-guide.html +222 -17
- package/package.json +1 -1
|
@@ -155,7 +155,7 @@ section.sec>h2:hover{color:#fff}
|
|
|
155
155
|
|
|
156
156
|
<div class="section-label">What's New</div>
|
|
157
157
|
<ul>
|
|
158
|
-
<li><a href="#whats-new">v1.1.
|
|
158
|
+
<li><a href="#whats-new">v1.1.2 Release Notes</a></li>
|
|
159
159
|
</ul>
|
|
160
160
|
|
|
161
161
|
<div class="section-label">Getting Started</div>
|
|
@@ -242,12 +242,174 @@ section.sec>h2:hover{color:#fff}
|
|
|
242
242
|
<h2>What's New</h2>
|
|
243
243
|
<p style="color:var(--muted);font-size:13px;margin-bottom:20px">Version history and release notes. Click a version to expand.</p>
|
|
244
244
|
|
|
245
|
-
<!-- ── v1.1.
|
|
246
|
-
<div class="wn-version open" id="wn-
|
|
245
|
+
<!-- ── v1.1.2 (current) ── -->
|
|
246
|
+
<div class="wn-version open" id="wn-112">
|
|
247
|
+
<div class="wn-header" onclick="toggleVersion('wn-112')">
|
|
248
|
+
<div class="wn-title">
|
|
249
|
+
<span class="wn-ver">v1.1.2</span>
|
|
250
|
+
<span class="wn-badge current">Current</span>
|
|
251
|
+
<span class="wn-date">May 2026</span>
|
|
252
|
+
</div>
|
|
253
|
+
<span class="wn-chevron">▲</span>
|
|
254
|
+
</div>
|
|
255
|
+
<div class="wn-body">
|
|
256
|
+
|
|
257
|
+
<div class="wn-item" id="wn-112-1">
|
|
258
|
+
<div class="wn-item-header" onclick="toggleItem('wn-112-1')">
|
|
259
|
+
<span class="wn-tag new">New</span>
|
|
260
|
+
<span class="wn-item-title">Participants stored in a dedicated collection</span>
|
|
261
|
+
<span class="wn-chevron-sm">▾</span>
|
|
262
|
+
</div>
|
|
263
|
+
<div class="wn-item-body">
|
|
264
|
+
<p>Participants are no longer embedded inside conversation documents. Each participant is now its own document in a separate <code>chat_conversation_participants</code> collection.</p>
|
|
265
|
+
<p>This removes the MongoDB 16 MB document size ceiling for large groups, eliminates write contention when many members join or leave simultaneously, and allows per-user data (mute, pin, notification settings) to be updated without touching the conversation document.</p>
|
|
266
|
+
<p><strong>No client API changes.</strong> All existing SDK calls, types, and socket events are unaffected.</p>
|
|
267
|
+
</div>
|
|
268
|
+
</div>
|
|
269
|
+
|
|
270
|
+
<div class="wn-item" id="wn-112-2">
|
|
271
|
+
<div class="wn-item-header" onclick="toggleItem('wn-112-2')">
|
|
272
|
+
<span class="wn-tag new">New</span>
|
|
273
|
+
<span class="wn-item-title">Transit encryption</span>
|
|
274
|
+
<span class="wn-chevron-sm">▾</span>
|
|
275
|
+
</div>
|
|
276
|
+
<div class="wn-item-body">
|
|
277
|
+
<p>All socket payloads are now encrypted end-to-end using a per-session symmetric key negotiated on connect via a server-side handshake. Encryption and decryption are handled transparently inside the SDK — no changes to how you call <code>sendMessage</code>, <code>socketEmit</code>, or any event listeners.</p>
|
|
278
|
+
<p><strong>No action required.</strong> Existing callers work without modification.</p>
|
|
279
|
+
</div>
|
|
280
|
+
</div>
|
|
281
|
+
|
|
282
|
+
<div class="wn-item" id="wn-112-3">
|
|
283
|
+
<div class="wn-item-header" onclick="toggleItem('wn-112-3')">
|
|
284
|
+
<span class="wn-tag fix">Fix</span>
|
|
285
|
+
<span class="wn-item-title">Disbanded groups now visible in read-only mode for removed members</span>
|
|
286
|
+
<span class="wn-chevron-sm">▾</span>
|
|
287
|
+
</div>
|
|
288
|
+
<div class="wn-item-body">
|
|
289
|
+
<p>When a group was disbanded (all members left or removed), removed participants had an inconsistent view — the conversation sometimes disappeared entirely before they could dismiss it. Removed participants now always see the conversation in read-only mode until they explicitly call <code>leave()</code> to hide it from their list.</p>
|
|
290
|
+
</div>
|
|
291
|
+
</div>
|
|
292
|
+
|
|
293
|
+
<div class="wn-item" id="wn-112-4">
|
|
294
|
+
<div class="wn-item-header" onclick="toggleItem('wn-112-4')">
|
|
295
|
+
<span class="wn-tag fix">Fix</span>
|
|
296
|
+
<span class="wn-item-title">Removed participant access hardened</span>
|
|
297
|
+
<span class="wn-chevron-sm">▾</span>
|
|
298
|
+
</div>
|
|
299
|
+
<div class="wn-item-body">
|
|
300
|
+
<p>Three access control gaps closed for removed users:</p>
|
|
301
|
+
<ul>
|
|
302
|
+
<li><strong>Message history capped at removal time</strong> — The REST message list API now applies a <code>createdAt ≤ removedAt</code> filter for removed participants. Messages sent after removal are no longer visible.</li>
|
|
303
|
+
<li><strong>Search, starred messages, and unread counts blocked</strong> — Removed users could previously search messages, view their starred messages, and fetch unread counts from conversations they were removed from. All three endpoints now check active membership before returning results.</li>
|
|
304
|
+
<li><strong>Socket and push already enforced</strong> — Real-time events and push notifications were already blocked at the socket room level (room kick on removal). No change here.</li>
|
|
305
|
+
</ul>
|
|
306
|
+
<p><strong>No client action required.</strong> These are server-side enforcement fixes.</p>
|
|
307
|
+
</div>
|
|
308
|
+
</div>
|
|
309
|
+
|
|
310
|
+
<div class="wn-item" id="wn-112-5">
|
|
311
|
+
<div class="wn-item-header" onclick="toggleItem('wn-112-5')">
|
|
312
|
+
<span class="wn-tag fix">Fix</span>
|
|
313
|
+
<span class="wn-item-title">Unread badge drops to zero immediately when admin removes a user</span>
|
|
314
|
+
<span class="wn-chevron-sm">▾</span>
|
|
315
|
+
</div>
|
|
316
|
+
<div class="wn-item-body">
|
|
317
|
+
<p>When an admin removed a user from a group, the removed user's unread badge stayed non-zero until they manually opened the conversation. The server now bulk-inserts read records for all unread messages in that conversation at the moment of removal, so the badge correctly drops to zero immediately.</p>
|
|
318
|
+
<p><strong>No client action required.</strong></p>
|
|
319
|
+
</div>
|
|
320
|
+
</div>
|
|
321
|
+
|
|
322
|
+
<div class="wn-item" id="wn-112-6">
|
|
323
|
+
<div class="wn-item-header" onclick="toggleItem('wn-112-6')">
|
|
324
|
+
<span class="wn-tag fix">Fix</span>
|
|
325
|
+
<span class="wn-item-title">Compression metadata now stored on the server</span>
|
|
326
|
+
<span class="wn-chevron-sm">▾</span>
|
|
327
|
+
</div>
|
|
328
|
+
<div class="wn-item-body">
|
|
329
|
+
<p>When a compressed image was uploaded via <code>uploadBatch</code>, the file record on the server silently dropped <code>compressed</code>, <code>originalSize</code>, and <code>compressionAlgorithm</code> due to DTO validation stripping unknown fields. These are now correctly persisted.</p>
|
|
330
|
+
<p><strong>No client action required.</strong> <code>uploadBatch</code> already sends this metadata — it will now be saved automatically.</p>
|
|
331
|
+
</div>
|
|
332
|
+
</div>
|
|
333
|
+
|
|
334
|
+
<div class="wn-item" id="wn-112-7">
|
|
335
|
+
<div class="wn-item-header" onclick="toggleItem('wn-112-7')">
|
|
336
|
+
<span class="wn-tag fix">Fix</span>
|
|
337
|
+
<span class="wn-item-title">Delete for me also removes the message from your starred list</span>
|
|
338
|
+
<span class="wn-chevron-sm">▾</span>
|
|
339
|
+
</div>
|
|
340
|
+
<div class="wn-item-body">
|
|
341
|
+
<p>Calling <code>deleteForMe</code> on a starred message hid it from the message list but left it in the starred messages list. The server now removes the star record at the same time as the delete-for-me record. The message no longer appears in <code>getStarredMessages</code> after being deleted for the requesting user.</p>
|
|
342
|
+
<p><strong>No client action required.</strong></p>
|
|
343
|
+
</div>
|
|
344
|
+
</div>
|
|
345
|
+
|
|
346
|
+
</div>
|
|
347
|
+
</div><!-- /.wn-version -->
|
|
348
|
+
|
|
349
|
+
<!-- ── v1.1.1 ── -->
|
|
350
|
+
<div class="wn-version" id="wn-111">
|
|
351
|
+
<div class="wn-header" onclick="toggleVersion('wn-111')">
|
|
352
|
+
<div class="wn-title">
|
|
353
|
+
<span class="wn-ver">v1.1.1</span>
|
|
354
|
+
<span class="wn-date">May 2026</span>
|
|
355
|
+
</div>
|
|
356
|
+
<span class="wn-chevron">▲</span>
|
|
357
|
+
</div>
|
|
358
|
+
<div class="wn-body">
|
|
359
|
+
|
|
360
|
+
<div class="wn-item" id="wn-111-1">
|
|
361
|
+
<div class="wn-item-header" onclick="toggleItem('wn-111-1')">
|
|
362
|
+
<span class="wn-tag new">New</span>
|
|
363
|
+
<span class="wn-item-title">Attachment snapshot on reply messages</span>
|
|
364
|
+
<span class="wn-chevron-sm">▾</span>
|
|
365
|
+
</div>
|
|
366
|
+
<div class="wn-item-body">
|
|
367
|
+
<p><code>replyTo</code> now includes an <code>attachmentSnapshot</code> field containing a snapshot of the first attachment from the quoted message: <code>type</code>, <code>filename</code>, <code>mimeType</code>, <code>size</code>, <code>duration</code>, <code>dimensions</code>, and a signed <code>url</code>.</p>
|
|
368
|
+
<p>The snapshot is stored at write time so reply bubbles can render the quoted attachment preview without fetching the original message. A new <code>ReplyAttachmentSnapshot</code> type is exported from the SDK.</p>
|
|
369
|
+
</div>
|
|
370
|
+
</div>
|
|
371
|
+
|
|
372
|
+
<div class="wn-item" id="wn-111-2">
|
|
373
|
+
<div class="wn-item-header" onclick="toggleItem('wn-111-2')">
|
|
374
|
+
<span class="wn-tag fix">Fix</span>
|
|
375
|
+
<span class="wn-item-title"><code>contentPreview</code> for multi-attachment replies</span>
|
|
376
|
+
<span class="wn-chevron-sm">▾</span>
|
|
377
|
+
</div>
|
|
378
|
+
<div class="wn-item-body">
|
|
379
|
+
<p>When replying to a message with multiple attachments, <code>replyTo.contentPreview</code> now reflects the full count: <code>"photo.jpg +2 more"</code>, <code>"3 Photos"</code>, <code>"3 Attachments"</code> (mixed types). Previously it always showed only the first filename regardless of how many attachments the quoted message had.</p>
|
|
380
|
+
</div>
|
|
381
|
+
</div>
|
|
382
|
+
|
|
383
|
+
<div class="wn-item" id="wn-111-3">
|
|
384
|
+
<div class="wn-item-header" onclick="toggleItem('wn-111-3')">
|
|
385
|
+
<span class="wn-tag fix">Fix</span>
|
|
386
|
+
<span class="wn-item-title">Pin, unpin, and unmute operations</span>
|
|
387
|
+
<span class="wn-chevron-sm">▾</span>
|
|
388
|
+
</div>
|
|
389
|
+
<div class="wn-item-body">
|
|
390
|
+
<p>Server-side issues causing pin, unpin, and unmute to fail in certain states are resolved. All three operations now complete reliably. <strong>No client action required.</strong></p>
|
|
391
|
+
</div>
|
|
392
|
+
</div>
|
|
393
|
+
|
|
394
|
+
<div class="wn-item" id="wn-111-4">
|
|
395
|
+
<div class="wn-item-header" onclick="toggleItem('wn-111-4')">
|
|
396
|
+
<span class="wn-tag fix">Fix</span>
|
|
397
|
+
<span class="wn-item-title">Various backend fixes</span>
|
|
398
|
+
<span class="wn-chevron-sm">▾</span>
|
|
399
|
+
</div>
|
|
400
|
+
<div class="wn-item-body">
|
|
401
|
+
<p>Stability and correctness improvements across multiple server-side paths. <strong>No client action required.</strong></p>
|
|
402
|
+
</div>
|
|
403
|
+
</div>
|
|
404
|
+
|
|
405
|
+
</div>
|
|
406
|
+
</div><!-- /.wn-version -->
|
|
407
|
+
|
|
408
|
+
<!-- ── v1.1.0 ── -->
|
|
409
|
+
<div class="wn-version" id="wn-110">
|
|
247
410
|
<div class="wn-header" onclick="toggleVersion('wn-110')">
|
|
248
411
|
<div class="wn-title">
|
|
249
412
|
<span class="wn-ver">v1.1.0</span>
|
|
250
|
-
<span class="wn-badge current">Current</span>
|
|
251
413
|
<span class="wn-date">May 2026</span>
|
|
252
414
|
</div>
|
|
253
415
|
<span class="wn-chevron">▲</span>
|
|
@@ -430,7 +592,7 @@ section.sec>h2:hover{color:#fff}
|
|
|
430
592
|
<span class="wn-chevron-sm">▾</span>
|
|
431
593
|
</div>
|
|
432
594
|
<div class="wn-item-body">
|
|
433
|
-
<p>The <code>participant_left</code> socket event was only broadcast to the <code>conversation:<id></code> room. Users only join that room when they actively open that specific conversation — so users on the conversation-list screen never received the event and saw a stale participant count. The server now also emits directly to each remaining participant's personal <code>user:<tenantId>:<userId></code> room, skipping users already in the conversation room to avoid double-delivery.</p>
|
|
595
|
+
<p>The <code>participant_left</code> socket event was only broadcast to the <code>conversation:<tenantId>:<id></code> room. Users only join that room when they actively open that specific conversation — so users on the conversation-list screen never received the event and saw a stale participant count. The server now also emits directly to each remaining participant's personal <code>user:<tenantId>:<userId></code> room, skipping users already in the conversation room to avoid double-delivery.</p>
|
|
434
596
|
<p><strong>Action required:</strong> None. Server-side fix only.</p>
|
|
435
597
|
</div>
|
|
436
598
|
</div>
|
|
@@ -457,6 +619,48 @@ section.sec>h2:hover{color:#fff}
|
|
|
457
619
|
</div>
|
|
458
620
|
</div>
|
|
459
621
|
|
|
622
|
+
<div class="wn-item" id="wn-109-7">
|
|
623
|
+
<div class="wn-item-header" onclick="toggleItem('wn-109-7')">
|
|
624
|
+
<span class="wn-tag fix">Fix</span>
|
|
625
|
+
<span class="wn-item-title">Removed user could re-enter conversation room via <code>join_room</code></span>
|
|
626
|
+
<span class="wn-chevron-sm">▾</span>
|
|
627
|
+
</div>
|
|
628
|
+
<div class="wn-item-body">
|
|
629
|
+
<p>The socket access check for <code>join_room</code> was missing the <code>isActive</code> participant check. A removed user whose client re-emitted <code>joinRoom</code> (e.g. on reconnect or by navigating back to the chat screen) would be silently re-admitted to the conversation room and continue receiving <code>new_message</code> events. The check now requires <code>isActive: true</code>, consistent with the write-access check.</p>
|
|
630
|
+
<p><strong>Action required:</strong> None. Server-side fix only.</p>
|
|
631
|
+
</div>
|
|
632
|
+
</div>
|
|
633
|
+
|
|
634
|
+
<div class="wn-item" id="wn-109-8">
|
|
635
|
+
<div class="wn-item-header" onclick="toggleItem('wn-109-8')">
|
|
636
|
+
<span class="wn-tag fix">Fix</span>
|
|
637
|
+
<span class="wn-item-title">Re-added user's conversation missing from list when they had previously deleted it</span>
|
|
638
|
+
<span class="wn-chevron-sm">▾</span>
|
|
639
|
+
</div>
|
|
640
|
+
<div class="wn-item-body">
|
|
641
|
+
<p>When a user deleted a conversation (<code>isHidden: true</code>), was then removed from the group, and later re-added by an admin, the conversation never reappeared in their list. The reactivation path now resets <code>isHidden</code> to <code>false</code> alongside <code>isActive</code>.</p>
|
|
642
|
+
<p>Additionally, the server now server-side joins the re-added user's active sockets into the conversation room and emits <code>conversation_created</code> to their personal room so the conversation appears immediately — no reconnect or <code>joinRoom</code> call needed.</p>
|
|
643
|
+
<p><strong>Action required:</strong> None. Server-side fix only. Existing <code>conversation_created → joinRoom</code> listeners remain safe (idempotent).</p>
|
|
644
|
+
</div>
|
|
645
|
+
</div>
|
|
646
|
+
|
|
647
|
+
<div class="wn-item" id="wn-109-9">
|
|
648
|
+
<div class="wn-item-header" onclick="toggleItem('wn-109-9')">
|
|
649
|
+
<span class="wn-tag new">New</span>
|
|
650
|
+
<span class="wn-item-title">Optional <code>role</code> parameter on <code>addParticipants</code></span>
|
|
651
|
+
<span class="wn-chevron-sm">▾</span>
|
|
652
|
+
</div>
|
|
653
|
+
<div class="wn-item-body">
|
|
654
|
+
<p><code>addParticipants</code> now accepts an optional <code>role</code> parameter (<code>'admin' | 'member'</code>, default <code>'member'</code>). This applies to both newly added users and previously removed users being re-added. A former admin who is re-added without specifying <code>role: 'admin'</code> will come back as a member — their previous role is never silently restored.</p>
|
|
655
|
+
<pre><code><span class="cm">// Default — added as member (backward compatible)</span>
|
|
656
|
+
<span class="kw">await</span> conversationsApi.<span class="fn">addParticipants</span>(conversationId, [<span class="str">'user-3'</span>]);
|
|
657
|
+
|
|
658
|
+
<span class="cm">// Explicitly add as admin</span>
|
|
659
|
+
<span class="kw">await</span> conversationsApi.<span class="fn">addParticipants</span>(conversationId, [<span class="str">'user-3'</span>], <span class="str">'admin'</span>);</code></pre>
|
|
660
|
+
<p><strong>Action required:</strong> None for existing code — the parameter is optional and defaults to <code>'member'</code>. No call sites need updating unless you want to add members as admins directly.</p>
|
|
661
|
+
</div>
|
|
662
|
+
</div>
|
|
663
|
+
|
|
460
664
|
</div>
|
|
461
665
|
</div>
|
|
462
666
|
|
|
@@ -1175,7 +1379,7 @@ npx pod-install</code></pre>
|
|
|
1175
1379
|
<tr><td><code>userId</code></td><td><code>string</code></td><td>External auth</td><td>Your system's user ID</td></tr>
|
|
1176
1380
|
<tr><td><code>avatar.url</code></td><td><code>string</code></td><td>No</td><td>Avatar URL — pass <code>url</code> OR <code>base64</code>, not both</td></tr>
|
|
1177
1381
|
<tr><td><code>avatar.base64</code></td><td><code>string</code></td><td>No</td><td>Raw base64 avatar string</td></tr>
|
|
1178
|
-
<tr><td><code>
|
|
1382
|
+
<tr><td><code>transitEncryption</code></td><td><code>boolean</code></td><td>No</td><td>Payload-level wire encryption: encrypts every HTTP request/response and socket event using ECDH key exchange + AES-256-GCM. Default: <code>true</code>. Server must have <code>TRANSIT_ENCRYPTION_ENABLED=true</code> (default). Safe to toggle anytime — wire-only, nothing stored. Set <code>false</code> for local development only.</td></tr>
|
|
1179
1383
|
<tr><td><code>upload</code></td><td><code>UploadConfig</code></td><td>No</td><td>File size limits, allowed types, progress callback</td></tr>
|
|
1180
1384
|
</tbody>
|
|
1181
1385
|
</table>
|
|
@@ -1536,7 +1740,8 @@ chatClient.<span class="fn">disconnect</span>();
|
|
|
1536
1740
|
|
|
1537
1741
|
<span class="cm">// Participants</span>
|
|
1538
1742
|
<span class="kw">const</span> members = <span class="kw">await</span> conversationsApi.<span class="fn">getMembers</span>(conversationId);
|
|
1539
|
-
<span class="kw">await</span> conversationsApi.<span class="fn">addParticipants</span>(conversationId, [<span class="str">'user-3'</span>]);
|
|
1743
|
+
<span class="kw">await</span> conversationsApi.<span class="fn">addParticipants</span>(conversationId, [<span class="str">'user-3'</span>]); <span class="cm">// added as member (default)</span>
|
|
1744
|
+
<span class="kw">await</span> conversationsApi.<span class="fn">addParticipants</span>(conversationId, [<span class="str">'user-3'</span>], <span class="str">'admin'</span>); <span class="cm">// added as admin</span>
|
|
1540
1745
|
<span class="kw">await</span> conversationsApi.<span class="fn">removeParticipant</span>(conversationId, <span class="str">'user-2'</span>);
|
|
1541
1746
|
<span class="kw">await</span> conversationsApi.<span class="fn">updateParticipantRole</span>(conversationId, <span class="str">'user-1'</span>, <span class="str">'admin'</span>);
|
|
1542
1747
|
|
|
@@ -1582,16 +1787,15 @@ chatClient.<span class="fn">disconnect</span>();
|
|
|
1582
1787
|
|
|
1583
1788
|
<h4>When to call <code>joinRoom</code></h4>
|
|
1584
1789
|
<p>
|
|
1585
|
-
|
|
1586
|
-
|
|
1587
|
-
|
|
1588
|
-
|
|
1589
|
-
<code>new_message</code>, <code>typing_indicator</code>, or other room events for that conversation.
|
|
1790
|
+
When the <strong>user is added to a conversation while their socket is already connected</strong>, the server now automatically joins their active sockets into the new room and emits <code>conversation_created</code> to their personal room. No <code>joinRoom</code> call is required — <code>new_message</code>, <code>typing_indicator</code>, and all other room events will arrive immediately.
|
|
1791
|
+
</p>
|
|
1792
|
+
<p>
|
|
1793
|
+
Calling <code>joinRoom</code> on <code>conversation_created</code> is still safe (idempotent) and can be kept for defensive compatibility, but is no longer necessary:
|
|
1590
1794
|
</p>
|
|
1591
1795
|
|
|
1592
|
-
<pre><code><span class="cm">//
|
|
1796
|
+
<pre><code><span class="cm">// Optional — server already handles this automatically</span>
|
|
1593
1797
|
client.socket.<span class="fn">on</span>(<span class="str">'conversation_created'</span>, (conv) => {
|
|
1594
|
-
client.socket.emit.<span class="fn">joinRoom</span>(conv.id);
|
|
1798
|
+
client.socket.emit.<span class="fn">joinRoom</span>(conv.id); <span class="cm">// safe no-op if already in room</span>
|
|
1595
1799
|
});</code></pre>
|
|
1596
1800
|
|
|
1597
1801
|
<p><code>leaveRoom</code> is only needed if you want to intentionally stop receiving events for a room the user is still a member of (e.g. archiving client-side). It is not needed when navigating away from a screen.</p>
|
|
@@ -1622,9 +1826,9 @@ client.socket.<span class="fn">on</span>(<span class="str">'new_message'</span>,
|
|
|
1622
1826
|
});
|
|
1623
1827
|
});
|
|
1624
1828
|
|
|
1625
|
-
<span class="cm">//
|
|
1829
|
+
<span class="cm">// Optional — server auto-joins the room, but this is safe to keep</span>
|
|
1626
1830
|
client.socket.<span class="fn">on</span>(<span class="str">'conversation_created'</span>, (conv) => {
|
|
1627
|
-
client.socket.emit.<span class="fn">joinRoom</span>(conv.id);
|
|
1831
|
+
client.socket.emit.<span class="fn">joinRoom</span>(conv.id); <span class="cm">// idempotent no-op if already joined</span>
|
|
1628
1832
|
});</code></pre>
|
|
1629
1833
|
</div>
|
|
1630
1834
|
<div data-p="node">
|
|
@@ -1635,6 +1839,7 @@ client.socket.<span class="fn">on</span>(<span class="str">'new_message'</span>,
|
|
|
1635
1839
|
client.socket.emit.<span class="fn">markRead</span>(message.conversationId, message.id);
|
|
1636
1840
|
});
|
|
1637
1841
|
|
|
1842
|
+
<span class="cm">// Optional — server auto-joins the room, but safe to keep</span>
|
|
1638
1843
|
client.socket.<span class="fn">on</span>(<span class="str">'conversation_created'</span>, (conv) => {
|
|
1639
1844
|
client.socket.emit.<span class="fn">joinRoom</span>(conv.id);
|
|
1640
1845
|
});</code></pre>
|
|
@@ -1644,7 +1849,7 @@ client.socket.<span class="fn">on</span>(<span class="str">'conversation_created
|
|
|
1644
1849
|
<strong>Summary of rules:</strong>
|
|
1645
1850
|
<ul>
|
|
1646
1851
|
<li>All existing rooms are auto-joined on socket connect — no <code>joinRoom</code> needed on screen open.</li>
|
|
1647
|
-
<li>
|
|
1852
|
+
<li>When added to a conversation at runtime, the server now auto-joins the socket room and emits <code>conversation_created</code>. No <code>joinRoom</code> call needed, but safe to keep for compatibility.</li>
|
|
1648
1853
|
<li>Add the <code>new_message</code> listener once at app root, never per screen.</li>
|
|
1649
1854
|
<li>Use <code>message.conversationId</code> to route to the right view or badge update.</li>
|
|
1650
1855
|
<li>Track <code>activeConversationId</code> to decide whether to increment the unread count.</li>
|
package/package.json
CHANGED