@antzsoft/chat-core 1.1.1 → 1.1.3
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 +91 -19
- package/dist/index.cjs +445 -30
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +58 -31
- package/dist/index.d.ts +58 -31
- package/dist/index.js +444 -30
- package/dist/index.js.map +1 -1
- package/docs/integration-guide.html +354 -14
- 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.3 Release Notes</a></li>
|
|
159
159
|
</ul>
|
|
160
160
|
|
|
161
161
|
<div class="section-label">Getting Started</div>
|
|
@@ -242,12 +242,307 @@ 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.3 (current) ── -->
|
|
246
|
+
<div class="wn-version open" id="wn-113">
|
|
247
|
+
<div class="wn-header" onclick="toggleVersion('wn-113')">
|
|
248
|
+
<div class="wn-title">
|
|
249
|
+
<span class="wn-ver">v1.1.3</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-113-1">
|
|
258
|
+
<div class="wn-item-header" onclick="toggleItem('wn-113-1')">
|
|
259
|
+
<span class="wn-tag new">New</span>
|
|
260
|
+
<span class="wn-item-title">usersApi.updateProfile() — self-user profile update</span>
|
|
261
|
+
<span class="wn-chevron-sm">▾</span>
|
|
262
|
+
</div>
|
|
263
|
+
<div class="wn-item-body">
|
|
264
|
+
<p>The self user can now update their own profile (name, email, phone) instantly without waiting for the 2-hour background sync cycle.</p>
|
|
265
|
+
<pre><code><span class="kw">await</span> usersApi.<span class="fn">updateProfile</span>({ firstName: <span class="str">'Jane'</span>, lastName: <span class="str">'Smith'</span>, email: <span class="str">'jane@example.com'</span> });</code></pre>
|
|
266
|
+
<p><strong>Admin-updated fields (firstName, lastName) via external identity provider:</strong> the chat module will reflect those changes either on the next 2-hour sync or the next time the app initialises the chat client. Webhook-based instant sync will be introduced in a future release.</p>
|
|
267
|
+
<p class="wn-ref">→ <a href="#users-api">Users API</a> for the full reference</p>
|
|
268
|
+
</div>
|
|
269
|
+
</div>
|
|
270
|
+
|
|
271
|
+
<div class="wn-item" id="wn-113-2">
|
|
272
|
+
<div class="wn-item-header" onclick="toggleItem('wn-113-2')">
|
|
273
|
+
<span class="wn-tag new">New</span>
|
|
274
|
+
<span class="wn-item-title">Group icon — remove support</span>
|
|
275
|
+
<span class="wn-chevron-sm">▾</span>
|
|
276
|
+
</div>
|
|
277
|
+
<div class="wn-item-body">
|
|
278
|
+
<p>Admins can now remove a group icon in addition to setting or replacing one. Tapping the new <strong>✕</strong> button (top-right of the group avatar in Group Info) clears the icon immediately — the asset is deleted from storage and the conversation reverts to its initials avatar.</p>
|
|
279
|
+
<pre><code><span class="cm">// Remove icon — admin only</span>
|
|
280
|
+
<span class="kw">const</span> updated = <span class="kw">await</span> conversationsApi.<span class="fn">removeIcon</span>(groupId);
|
|
281
|
+
<span class="cm">// updated.iconUrl === undefined</span></code></pre>
|
|
282
|
+
<p>Like upload, remove is admin-only; non-admins receive <code>403 Forbidden</code>. No icon is ever left orphaned in storage.</p>
|
|
283
|
+
<p class="wn-ref">→ <a href="#step-convs">Step 6 — Conversations</a> (group icon section) for the full pipeline</p>
|
|
284
|
+
</div>
|
|
285
|
+
</div>
|
|
286
|
+
|
|
287
|
+
<div class="wn-item" id="wn-113-3">
|
|
288
|
+
<div class="wn-item-header" onclick="toggleItem('wn-113-3')">
|
|
289
|
+
<span class="wn-tag new">New</span>
|
|
290
|
+
<span class="wn-item-title">Leave / Delete / Exit — WhatsApp-style behavior</span>
|
|
291
|
+
<span class="wn-chevron-sm">▾</span>
|
|
292
|
+
</div>
|
|
293
|
+
<div class="wn-item-body">
|
|
294
|
+
<p><code>leave(id)</code> exits a group but keeps it in the list (read-only). <code>leave(id, true)</code> exits and removes it atomically. <code>delete(id)</code> hides any conversation from the caller's list — no longer admin-only, works for DMs ("Delete Chat") and already-exited groups ("Delete Group"). When the last admin exits, the server auto-promotes the longest-standing member instead of returning <code>400</code>.</p>
|
|
295
|
+
<p class="wn-ref">→ <a href="#step-convs">Step 6 — Conversations</a> for code examples</p>
|
|
296
|
+
</div>
|
|
297
|
+
</div>
|
|
298
|
+
|
|
299
|
+
<div class="wn-item" id="wn-113-4">
|
|
300
|
+
<div class="wn-item-header" onclick="toggleItem('wn-113-4')">
|
|
301
|
+
<span class="wn-tag new">New</span>
|
|
302
|
+
<span class="wn-item-title">Message visibility windows — gap messages hidden after re-add</span>
|
|
303
|
+
<span class="wn-chevron-sm">▾</span>
|
|
304
|
+
</div>
|
|
305
|
+
<div class="wn-item-body">
|
|
306
|
+
<p>Messages sent while a user was not a member (gap periods) are now always hidden. Re-adding after a plain exit preserves prior history; re-adding after "Exit and Delete" shows only messages from the re-add point. DM "Delete Chat" also resets the window — when the other party messages again, only new messages are visible. No client changes required.</p>
|
|
307
|
+
</div>
|
|
308
|
+
</div>
|
|
309
|
+
|
|
310
|
+
<div class="wn-item" id="wn-113-5">
|
|
311
|
+
<div class="wn-item-header" onclick="toggleItem('wn-113-5')">
|
|
312
|
+
<span class="wn-tag new">New</span>
|
|
313
|
+
<span class="wn-item-title">useConversations() — leaveGroup, leaveAndDeleteGroup, deleteConversation</span>
|
|
314
|
+
<span class="wn-chevron-sm">▾</span>
|
|
315
|
+
</div>
|
|
316
|
+
<div class="wn-item-body">
|
|
317
|
+
<p>Three new mutations added to <code>useConversations()</code> in both web and RN SDKs: <code>leaveGroup</code>, <code>leaveAndDeleteGroup</code>, and <code>deleteConversation</code> (RN) / <code>deleteGroup</code> (web). Cache is updated optimistically — no manual invalidation needed.</p>
|
|
318
|
+
</div>
|
|
319
|
+
</div>
|
|
320
|
+
|
|
321
|
+
</div>
|
|
322
|
+
</div><!-- /.wn-version -->
|
|
323
|
+
|
|
324
|
+
<!-- ── v1.1.2 ── -->
|
|
325
|
+
<div class="wn-version" id="wn-112">
|
|
326
|
+
<div class="wn-header" onclick="toggleVersion('wn-112')">
|
|
327
|
+
<div class="wn-title">
|
|
328
|
+
<span class="wn-ver">v1.1.2</span>
|
|
329
|
+
<span class="wn-date">May 2026</span>
|
|
330
|
+
</div>
|
|
331
|
+
<span class="wn-chevron">▾</span>
|
|
332
|
+
</div>
|
|
333
|
+
<div class="wn-body">
|
|
334
|
+
|
|
335
|
+
<div class="wn-item" id="wn-112-0a">
|
|
336
|
+
<div class="wn-item-header" onclick="toggleItem('wn-112-0a')">
|
|
337
|
+
<span class="wn-tag new">New</span>
|
|
338
|
+
<span class="wn-item-title">usersApi.updateProfile() — immediate profile update</span>
|
|
339
|
+
<span class="wn-chevron-sm">▾</span>
|
|
340
|
+
</div>
|
|
341
|
+
<div class="wn-item-body">
|
|
342
|
+
<p>A new <code>usersApi.updateProfile(payload)</code> method lets the host app push profile field changes to the chat server immediately — without waiting for the next background sync cycle.</p>
|
|
343
|
+
<p>This is especially useful in <strong>non-builtin (external/SSO) modes</strong>: when the user updates their name or email in the main identity provider, the host app can call <code>updateProfile()</code> so the chat UI reflects the change right away rather than waiting up to 2 hours for the next cron sync.</p>
|
|
344
|
+
<pre><code><span class="kw">import</span> { usersApi } <span class="kw">from</span> <span class="str">'@antzsoft/chat-core'</span>;
|
|
345
|
+
|
|
346
|
+
<span class="kw">await</span> usersApi.<span class="fn">updateProfile</span>({
|
|
347
|
+
firstName: <span class="str">'Jane'</span>,
|
|
348
|
+
lastName: <span class="str">'Smith'</span>,
|
|
349
|
+
email: <span class="str">'jane@example.com'</span>,
|
|
350
|
+
displayName: <span class="str">'Jane S.'</span>, <span class="cm">// optional</span>
|
|
351
|
+
phone: <span class="str">'+919900000000'</span>,
|
|
352
|
+
});</code></pre>
|
|
353
|
+
<table>
|
|
354
|
+
<tr><th>Field</th><th>Builtin</th><th>Non-builtin</th></tr>
|
|
355
|
+
<tr><td><code>firstName</code>, <code>lastName</code>, <code>email</code></td><td>Written directly</td><td>Written immediately; may be overwritten on next sync if user-service returns different values</td></tr>
|
|
356
|
+
<tr><td><code>displayName</code>, <code>phone</code></td><td>Written directly</td><td>Written immediately</td></tr>
|
|
357
|
+
<tr><td><code>username</code>, <code>status</code></td><td colspan="2">Not allowed</td></tr>
|
|
358
|
+
</table>
|
|
359
|
+
<p><strong>Uniqueness:</strong> <code>email</code> and <code>phone</code> must each be unique within the tenant. A <code>409 Conflict</code> is returned if another user already holds the same value.</p>
|
|
360
|
+
<p class="wn-ref">→ <a href="#users-api">Users API</a> for the full reference</p>
|
|
361
|
+
</div>
|
|
362
|
+
</div>
|
|
363
|
+
|
|
364
|
+
<div class="wn-item" id="wn-112-0b">
|
|
365
|
+
<div class="wn-item-header" onclick="toggleItem('wn-112-0b')">
|
|
366
|
+
<span class="wn-tag new">New</span>
|
|
367
|
+
<span class="wn-item-title">On-connect per-user profile sync</span>
|
|
368
|
+
<span class="wn-chevron-sm">▾</span>
|
|
369
|
+
</div>
|
|
370
|
+
<div class="wn-item-body">
|
|
371
|
+
<p>In non-builtin modes, <code>AntzChatClient.connect()</code> now triggers a fire-and-forget background sync of the current user's profile from the upstream user-service if the shadow record hasn't been synced in the last 6 hours.</p>
|
|
372
|
+
<p>Previously only the 2-hour bulk cron kept shadow records up to date. Now profile fields (<code>firstName</code>, <code>lastName</code>, <code>displayName</code>, <code>email</code>, <code>username</code>, <code>phone</code>, <code>status</code>) are refreshed on every fresh SDK initialisation, providing near-immediate consistency for users who reconnect after a period of inactivity.</p>
|
|
373
|
+
<p><strong>No client action required.</strong> This is handled automatically inside <code>connect()</code>.</p>
|
|
374
|
+
</div>
|
|
375
|
+
</div>
|
|
376
|
+
|
|
377
|
+
<div class="wn-item" id="wn-112-0c">
|
|
378
|
+
<div class="wn-item-header" onclick="toggleItem('wn-112-0c')">
|
|
379
|
+
<span class="wn-tag new">New</span>
|
|
380
|
+
<span class="wn-item-title">Phone number uniqueness enforced per tenant</span>
|
|
381
|
+
<span class="wn-chevron-sm">▾</span>
|
|
382
|
+
</div>
|
|
383
|
+
<div class="wn-item-body">
|
|
384
|
+
<p><code>phone</code> is now unique within a tenant — the same phone number cannot be registered to two different users under the same tenant. A <code>409 Conflict</code> is returned on registration or profile update if the number is already in use.</p>
|
|
385
|
+
<p>Same-phone across different tenants is still allowed (a user can have the same phone in tenant A and tenant B).</p>
|
|
386
|
+
<p><strong>No client action required</strong> for existing data. New uniqueness is enforced at write time only.</p>
|
|
387
|
+
</div>
|
|
388
|
+
</div>
|
|
389
|
+
|
|
390
|
+
<div class="wn-item" id="wn-112-1">
|
|
391
|
+
<div class="wn-item-header" onclick="toggleItem('wn-112-1')">
|
|
392
|
+
<span class="wn-tag new">New</span>
|
|
393
|
+
<span class="wn-item-title">Participants stored in a dedicated collection</span>
|
|
394
|
+
<span class="wn-chevron-sm">▾</span>
|
|
395
|
+
</div>
|
|
396
|
+
<div class="wn-item-body">
|
|
397
|
+
<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>
|
|
398
|
+
<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>
|
|
399
|
+
<p><strong>No client API changes.</strong> All existing SDK calls, types, and socket events are unaffected.</p>
|
|
400
|
+
</div>
|
|
401
|
+
</div>
|
|
402
|
+
|
|
403
|
+
<div class="wn-item" id="wn-112-2">
|
|
404
|
+
<div class="wn-item-header" onclick="toggleItem('wn-112-2')">
|
|
405
|
+
<span class="wn-tag new">New</span>
|
|
406
|
+
<span class="wn-item-title">Transit encryption</span>
|
|
407
|
+
<span class="wn-chevron-sm">▾</span>
|
|
408
|
+
</div>
|
|
409
|
+
<div class="wn-item-body">
|
|
410
|
+
<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>
|
|
411
|
+
<p><strong>No action required.</strong> Existing callers work without modification.</p>
|
|
412
|
+
</div>
|
|
413
|
+
</div>
|
|
414
|
+
|
|
415
|
+
<div class="wn-item" id="wn-112-3">
|
|
416
|
+
<div class="wn-item-header" onclick="toggleItem('wn-112-3')">
|
|
417
|
+
<span class="wn-tag fix">Fix</span>
|
|
418
|
+
<span class="wn-item-title">Disbanded groups now visible in read-only mode for removed members</span>
|
|
419
|
+
<span class="wn-chevron-sm">▾</span>
|
|
420
|
+
</div>
|
|
421
|
+
<div class="wn-item-body">
|
|
422
|
+
<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>
|
|
423
|
+
</div>
|
|
424
|
+
</div>
|
|
425
|
+
|
|
426
|
+
<div class="wn-item" id="wn-112-4">
|
|
427
|
+
<div class="wn-item-header" onclick="toggleItem('wn-112-4')">
|
|
428
|
+
<span class="wn-tag fix">Fix</span>
|
|
429
|
+
<span class="wn-item-title">Removed participant access hardened</span>
|
|
430
|
+
<span class="wn-chevron-sm">▾</span>
|
|
431
|
+
</div>
|
|
432
|
+
<div class="wn-item-body">
|
|
433
|
+
<p>Three access control gaps closed for removed users:</p>
|
|
434
|
+
<ul>
|
|
435
|
+
<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>
|
|
436
|
+
<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>
|
|
437
|
+
<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>
|
|
438
|
+
</ul>
|
|
439
|
+
<p><strong>No client action required.</strong> These are server-side enforcement fixes.</p>
|
|
440
|
+
</div>
|
|
441
|
+
</div>
|
|
442
|
+
|
|
443
|
+
<div class="wn-item" id="wn-112-5">
|
|
444
|
+
<div class="wn-item-header" onclick="toggleItem('wn-112-5')">
|
|
445
|
+
<span class="wn-tag fix">Fix</span>
|
|
446
|
+
<span class="wn-item-title">Unread badge drops to zero immediately when admin removes a user</span>
|
|
447
|
+
<span class="wn-chevron-sm">▾</span>
|
|
448
|
+
</div>
|
|
449
|
+
<div class="wn-item-body">
|
|
450
|
+
<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>
|
|
451
|
+
<p><strong>No client action required.</strong></p>
|
|
452
|
+
</div>
|
|
453
|
+
</div>
|
|
454
|
+
|
|
455
|
+
<div class="wn-item" id="wn-112-6">
|
|
456
|
+
<div class="wn-item-header" onclick="toggleItem('wn-112-6')">
|
|
457
|
+
<span class="wn-tag fix">Fix</span>
|
|
458
|
+
<span class="wn-item-title">Compression metadata now stored on the server</span>
|
|
459
|
+
<span class="wn-chevron-sm">▾</span>
|
|
460
|
+
</div>
|
|
461
|
+
<div class="wn-item-body">
|
|
462
|
+
<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>
|
|
463
|
+
<p><strong>No client action required.</strong> <code>uploadBatch</code> already sends this metadata — it will now be saved automatically.</p>
|
|
464
|
+
</div>
|
|
465
|
+
</div>
|
|
466
|
+
|
|
467
|
+
<div class="wn-item" id="wn-112-7">
|
|
468
|
+
<div class="wn-item-header" onclick="toggleItem('wn-112-7')">
|
|
469
|
+
<span class="wn-tag fix">Fix</span>
|
|
470
|
+
<span class="wn-item-title">Delete for me also removes the message from your starred list</span>
|
|
471
|
+
<span class="wn-chevron-sm">▾</span>
|
|
472
|
+
</div>
|
|
473
|
+
<div class="wn-item-body">
|
|
474
|
+
<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>
|
|
475
|
+
<p><strong>No client action required.</strong></p>
|
|
476
|
+
</div>
|
|
477
|
+
</div>
|
|
478
|
+
|
|
479
|
+
</div>
|
|
480
|
+
</div><!-- /.wn-version -->
|
|
481
|
+
|
|
482
|
+
<!-- ── v1.1.1 ── -->
|
|
483
|
+
<div class="wn-version" id="wn-111">
|
|
484
|
+
<div class="wn-header" onclick="toggleVersion('wn-111')">
|
|
485
|
+
<div class="wn-title">
|
|
486
|
+
<span class="wn-ver">v1.1.1</span>
|
|
487
|
+
<span class="wn-date">May 2026</span>
|
|
488
|
+
</div>
|
|
489
|
+
<span class="wn-chevron">▲</span>
|
|
490
|
+
</div>
|
|
491
|
+
<div class="wn-body">
|
|
492
|
+
|
|
493
|
+
<div class="wn-item" id="wn-111-1">
|
|
494
|
+
<div class="wn-item-header" onclick="toggleItem('wn-111-1')">
|
|
495
|
+
<span class="wn-tag new">New</span>
|
|
496
|
+
<span class="wn-item-title">Attachment snapshot on reply messages</span>
|
|
497
|
+
<span class="wn-chevron-sm">▾</span>
|
|
498
|
+
</div>
|
|
499
|
+
<div class="wn-item-body">
|
|
500
|
+
<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>
|
|
501
|
+
<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>
|
|
502
|
+
</div>
|
|
503
|
+
</div>
|
|
504
|
+
|
|
505
|
+
<div class="wn-item" id="wn-111-2">
|
|
506
|
+
<div class="wn-item-header" onclick="toggleItem('wn-111-2')">
|
|
507
|
+
<span class="wn-tag fix">Fix</span>
|
|
508
|
+
<span class="wn-item-title"><code>contentPreview</code> for multi-attachment replies</span>
|
|
509
|
+
<span class="wn-chevron-sm">▾</span>
|
|
510
|
+
</div>
|
|
511
|
+
<div class="wn-item-body">
|
|
512
|
+
<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>
|
|
513
|
+
</div>
|
|
514
|
+
</div>
|
|
515
|
+
|
|
516
|
+
<div class="wn-item" id="wn-111-3">
|
|
517
|
+
<div class="wn-item-header" onclick="toggleItem('wn-111-3')">
|
|
518
|
+
<span class="wn-tag fix">Fix</span>
|
|
519
|
+
<span class="wn-item-title">Pin, unpin, and unmute operations</span>
|
|
520
|
+
<span class="wn-chevron-sm">▾</span>
|
|
521
|
+
</div>
|
|
522
|
+
<div class="wn-item-body">
|
|
523
|
+
<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>
|
|
524
|
+
</div>
|
|
525
|
+
</div>
|
|
526
|
+
|
|
527
|
+
<div class="wn-item" id="wn-111-4">
|
|
528
|
+
<div class="wn-item-header" onclick="toggleItem('wn-111-4')">
|
|
529
|
+
<span class="wn-tag fix">Fix</span>
|
|
530
|
+
<span class="wn-item-title">Various backend fixes</span>
|
|
531
|
+
<span class="wn-chevron-sm">▾</span>
|
|
532
|
+
</div>
|
|
533
|
+
<div class="wn-item-body">
|
|
534
|
+
<p>Stability and correctness improvements across multiple server-side paths. <strong>No client action required.</strong></p>
|
|
535
|
+
</div>
|
|
536
|
+
</div>
|
|
537
|
+
|
|
538
|
+
</div>
|
|
539
|
+
</div><!-- /.wn-version -->
|
|
540
|
+
|
|
541
|
+
<!-- ── v1.1.0 ── -->
|
|
542
|
+
<div class="wn-version" id="wn-110">
|
|
247
543
|
<div class="wn-header" onclick="toggleVersion('wn-110')">
|
|
248
544
|
<div class="wn-title">
|
|
249
545
|
<span class="wn-ver">v1.1.0</span>
|
|
250
|
-
<span class="wn-badge current">Current</span>
|
|
251
546
|
<span class="wn-date">May 2026</span>
|
|
252
547
|
</div>
|
|
253
548
|
<span class="wn-chevron">▲</span>
|
|
@@ -430,7 +725,7 @@ section.sec>h2:hover{color:#fff}
|
|
|
430
725
|
<span class="wn-chevron-sm">▾</span>
|
|
431
726
|
</div>
|
|
432
727
|
<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>
|
|
728
|
+
<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
729
|
<p><strong>Action required:</strong> None. Server-side fix only.</p>
|
|
435
730
|
</div>
|
|
436
731
|
</div>
|
|
@@ -780,17 +1075,21 @@ section.sec>h2:hover{color:#fff}
|
|
|
780
1075
|
<div class="wn-item" id="wn-106-7">
|
|
781
1076
|
<div class="wn-item-header" onclick="toggleItem('wn-106-7')">
|
|
782
1077
|
<span class="wn-tag new">New</span>
|
|
783
|
-
<span class="wn-item-title">Group icon — create &
|
|
1078
|
+
<span class="wn-item-title">Group icon — create, update & remove</span>
|
|
784
1079
|
<span class="wn-chevron-sm">▾</span>
|
|
785
1080
|
</div>
|
|
786
1081
|
<div class="wn-item-body">
|
|
787
|
-
<p>Group conversations now support a custom icon. Admins can set or
|
|
1082
|
+
<p>Group conversations now support a custom icon. Admins can set, replace, or remove it at any time. The icon is stored server-side and a fresh signed URL is returned on every conversation response.</p>
|
|
788
1083
|
<pre><code><span class="cm">// Upload icon — admin only</span>
|
|
789
1084
|
<span class="kw">const</span> updated = <span class="kw">await</span> client.<span class="fn">uploadIcon</span>(groupId, {
|
|
790
1085
|
<span class="at">uri</span>: file.uri, <span class="at">name</span>: <span class="str">'icon.jpg'</span>, <span class="at">type</span>: <span class="str">'image/jpeg'</span>, <span class="at">size</span>: file.size,
|
|
791
1086
|
});
|
|
792
|
-
<span class="cm">// updated.iconUrl → fresh signed URL</span
|
|
793
|
-
|
|
1087
|
+
<span class="cm">// updated.iconUrl → fresh signed URL</span>
|
|
1088
|
+
|
|
1089
|
+
<span class="cm">// Remove icon — admin only</span>
|
|
1090
|
+
<span class="kw">const</span> noIcon = <span class="kw">await</span> conversationsApi.<span class="fn">removeIcon</span>(groupId);
|
|
1091
|
+
<span class="cm">// noIcon.iconUrl === undefined</span></code></pre>
|
|
1092
|
+
<p>Non-admins receive <code>403 Forbidden</code> on both operations. The URL is never stored in the DB — regenerated from <code>iconMeta.storageKey</code> on every response. Replacing or removing an icon automatically deletes the previous asset from storage.</p>
|
|
794
1093
|
<p class="wn-ref">→ <a href="#step-convs">Step 6 — Conversations</a> (group icon section) for the full upload pipeline</p>
|
|
795
1094
|
</div>
|
|
796
1095
|
</div>
|
|
@@ -1217,7 +1516,7 @@ npx pod-install</code></pre>
|
|
|
1217
1516
|
<tr><td><code>userId</code></td><td><code>string</code></td><td>External auth</td><td>Your system's user ID</td></tr>
|
|
1218
1517
|
<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>
|
|
1219
1518
|
<tr><td><code>avatar.base64</code></td><td><code>string</code></td><td>No</td><td>Raw base64 avatar string</td></tr>
|
|
1220
|
-
<tr><td><code>
|
|
1519
|
+
<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>
|
|
1221
1520
|
<tr><td><code>upload</code></td><td><code>UploadConfig</code></td><td>No</td><td>File size limits, allowed types, progress callback</td></tr>
|
|
1222
1521
|
</tbody>
|
|
1223
1522
|
</table>
|
|
@@ -1535,6 +1834,17 @@ chatClient.<span class="fn">disconnect</span>();
|
|
|
1535
1834
|
<span class="cm">// Search users by name / username / email</span>
|
|
1536
1835
|
<span class="kw">const</span> { data: results } = <span class="kw">await</span> usersApi.<span class="fn">list</span>({ <span class="at">query</span>: <span class="str">'john'</span> });
|
|
1537
1836
|
|
|
1837
|
+
<span class="cm">// Update current user's profile — works in both builtin and non-builtin modes.</span>
|
|
1838
|
+
<span class="cm">// In non-builtin modes use this to push a change immediately without waiting</span>
|
|
1839
|
+
<span class="cm">// for the next 2-hour background sync from the upstream user-service.</span>
|
|
1840
|
+
<span class="kw">await</span> usersApi.<span class="fn">updateProfile</span>({
|
|
1841
|
+
firstName: <span class="str">'Jane'</span>,
|
|
1842
|
+
lastName: <span class="str">'Smith'</span>,
|
|
1843
|
+
email: <span class="str">'jane@example.com'</span>, <span class="cm">// 409 if taken by another user in this tenant</span>
|
|
1844
|
+
displayName: <span class="str">'Jane S.'</span>,
|
|
1845
|
+
phone: <span class="str">'+919900000000'</span>, <span class="cm">// 409 if taken by another user in this tenant</span>
|
|
1846
|
+
});
|
|
1847
|
+
|
|
1538
1848
|
<span class="cm">// Create DM — returns existing if already exists</span>
|
|
1539
1849
|
<span class="kw">const</span> dm = <span class="kw">await</span> conversationsApi.<span class="fn">createDirect</span>({ <span class="at">userId</span>: <span class="str">'target-user-id'</span> });
|
|
1540
1850
|
|
|
@@ -1573,8 +1883,15 @@ chatClient.<span class="fn">disconnect</span>();
|
|
|
1573
1883
|
<span class="cm">// - iconMeta = { storageKey, provider, bucket, mimeType, size } embedded in conversation doc</span>
|
|
1574
1884
|
<span class="cm">// - Non-admins get 403 Forbidden at server level</span>
|
|
1575
1885
|
|
|
1886
|
+
<span class="cm">// Remove the group icon (admin only)</span>
|
|
1887
|
+
<span class="cm">// Deletes asset from storage + clears iconMeta. Returns conversation with iconUrl: undefined.</span>
|
|
1888
|
+
<span class="kw">const</span> noIcon = <span class="kw">await</span> conversationsApi.<span class="fn">removeIcon</span>(group.id);
|
|
1889
|
+
<span class="cm">// → DELETE /conversations/:id/icon</span>
|
|
1890
|
+
<span class="cm">// Server: validateAdmin() → deleteByKey(iconMeta.storageKey) → $unset iconMeta</span>
|
|
1891
|
+
<span class="cm">// noIcon.iconUrl === undefined</span>
|
|
1892
|
+
|
|
1576
1893
|
<span class="cm">// Web/RN SDK components (GroupInfoPanel, NewChatModal, ChatHeader) handle this automatically.</span>
|
|
1577
|
-
<span class="cm">// Camera button shown only to admins. No code needed in your app.</span>
|
|
1894
|
+
<span class="cm">// Camera button + remove (✕) button shown only to admins. No code needed in your app.</span>
|
|
1578
1895
|
|
|
1579
1896
|
<span class="cm">// Participants</span>
|
|
1580
1897
|
<span class="kw">const</span> members = <span class="kw">await</span> conversationsApi.<span class="fn">getMembers</span>(conversationId);
|
|
@@ -1583,11 +1900,34 @@ chatClient.<span class="fn">disconnect</span>();
|
|
|
1583
1900
|
<span class="kw">await</span> conversationsApi.<span class="fn">removeParticipant</span>(conversationId, <span class="str">'user-2'</span>);
|
|
1584
1901
|
<span class="kw">await</span> conversationsApi.<span class="fn">updateParticipantRole</span>(conversationId, <span class="str">'user-1'</span>, <span class="str">'admin'</span>);
|
|
1585
1902
|
|
|
1586
|
-
<span class="cm">// Pin · Mute
|
|
1903
|
+
<span class="cm">// Pin · Mute</span>
|
|
1587
1904
|
<span class="kw">await</span> conversationsApi.<span class="fn">pin</span>(conversationId); <span class="cm">// 400 if already at 5 pinned</span>
|
|
1588
1905
|
<span class="kw">await</span> conversationsApi.<span class="fn">mute</span>(conversationId, <span class="str">'2025-12-31T23:59:59Z'</span>); <span class="cm">// omit date = indefinite</span>
|
|
1589
|
-
|
|
1590
|
-
<span class="
|
|
1906
|
+
|
|
1907
|
+
<span class="cm">// ── 1:1 Chat ──────────────────────────────────────────────────────────────────</span>
|
|
1908
|
+
<span class="cm">// "Delete Chat" — hides from caller's list only. Other participant unaffected.</span>
|
|
1909
|
+
<span class="cm">// If the other person messages again the chat reappears, showing only new messages.</span>
|
|
1910
|
+
<span class="kw">await</span> conversationsApi.<span class="fn">delete</span>(dmConversationId);
|
|
1911
|
+
|
|
1912
|
+
<span class="cm">// ── Group Chat ─────────────────────────────────────────────────────────────────</span>
|
|
1913
|
+
<span class="cm">// "Exit Group" — leave but keep in list (read-only). Auto-promotes if last admin.</span>
|
|
1914
|
+
<span class="kw">await</span> conversationsApi.<span class="fn">leave</span>(groupId);
|
|
1915
|
+
|
|
1916
|
+
<span class="cm">// "Exit and Delete" — leave + remove from list atomically.</span>
|
|
1917
|
+
<span class="kw">await</span> conversationsApi.<span class="fn">leave</span>(groupId, <span class="kw">true</span>);
|
|
1918
|
+
|
|
1919
|
+
<span class="cm">// "Delete Group" — hide an already-exited group from the list. Any participant.</span>
|
|
1920
|
+
<span class="kw">await</span> conversationsApi.<span class="fn">delete</span>(groupId);</code></pre>
|
|
1921
|
+
|
|
1922
|
+
<div class="callout info">
|
|
1923
|
+
<strong>Leave / Delete semantics</strong>
|
|
1924
|
+
<ul style="margin:8px 0 0;padding-left:20px;line-height:1.7">
|
|
1925
|
+
<li><strong>Exit Group</strong> — <code>leave(id)</code>. Caller becomes inactive, stays in list read-only. If the caller is the only admin, the server auto-promotes the longest-standing active member before completing the exit.</li>
|
|
1926
|
+
<li><strong>Exit and Delete</strong> — <code>leave(id, true)</code>. Atomic: exit + hide from list in one server write. No race window.</li>
|
|
1927
|
+
<li><strong>Delete Group</strong> (after exit) — <code>delete(id)</code>. Caller must already be inactive. Hides from their list only. Any participant, no admin role required.</li>
|
|
1928
|
+
<li><strong>Delete Chat</strong> (1:1) — <code>delete(id)</code>. Hides from caller's list. DMs have no admin concept. When the other participant messages again, the chat reappears for the caller with only new messages visible.</li>
|
|
1929
|
+
</ul>
|
|
1930
|
+
</div>
|
|
1591
1931
|
|
|
1592
1932
|
<div class="callout info">
|
|
1593
1933
|
<strong>Pin limit — max 5</strong> — The server enforces a maximum of 5 pinned conversations per user. Attempting to pin a 6th returns <code>400 Bad Request</code>. Gate your UI before calling the API:
|
package/package.json
CHANGED