@antzsoft/chat-core 1.3.3 → 1.3.5
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 +35 -1
- package/dist/index.cjs +14 -7
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +14 -7
- package/dist/index.js.map +1 -1
- package/dist/internal.d.cts +1 -1
- package/dist/internal.d.ts +1 -1
- package/dist/{storage-DdHsneZR.d.cts → storage-DJh54pps.d.cts} +7 -0
- package/dist/{storage-DdHsneZR.d.ts → storage-DJh54pps.d.ts} +7 -0
- package/docs/integration-guide.html +63 -3
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1746,6 +1746,7 @@ interface CrossConversationSyncResponse {
|
|
|
1746
1746
|
deliveredReceipts: SyncDeliveredReceipt[]; // delivery receipts since `since`
|
|
1747
1747
|
reactions: SyncReactions; // v1.3.1+ — full current state for messages with reaction activity
|
|
1748
1748
|
stars: SyncStarEntry[]; // v1.3.1+ — star/unstar records since `since`
|
|
1749
|
+
deletedConversationIds: string[]; // v1.3.4+ — conversations the user deleted from their list since `since`
|
|
1749
1750
|
}
|
|
1750
1751
|
|
|
1751
1752
|
interface SyncDeletedForMe {
|
|
@@ -1861,6 +1862,7 @@ The built-in `SyncService.syncConversation()` in the RN app uses the backward di
|
|
|
1861
1862
|
| `participantChanges` | ✅ | ✅ | Role changes, mute/unmute, removals (`isActive: false`) |
|
|
1862
1863
|
| `readReceipts` | ✅ | ✅ | Read receipts — merge into `msg.readBy[]`, recompute status |
|
|
1863
1864
|
| `deliveredReceipts` | ✅ | ✅ | Delivery receipts — merge into `msg.deliveredTo[]`, recompute status |
|
|
1865
|
+
| `deletedConversationIds` | ✅ v1.3.4 | — | Conversations this user deleted from their list — remove from local DB. Cursor-safe: won't reappear on next `pull()` |
|
|
1864
1866
|
|
|
1865
1867
|
#### Stale handling
|
|
1866
1868
|
|
|
@@ -2139,7 +2141,7 @@ import type { SocketStatus } from '@antzsoft/chat-core';
|
|
|
2139
2141
|
|---|---|---|
|
|
2140
2142
|
| `connectSocket` | `(config: ResolvedConfig, getToken: () => string \| null \| undefined) => Promise<Socket>` | Initialize and connect the Socket.IO client. No-ops if already connected. |
|
|
2141
2143
|
| `disconnectSocket` | `() => void` | Disconnect and clear the socket singleton. |
|
|
2142
|
-
| `reconnectSocket` | `(token: string) => void` | Update the auth token on the existing socket and reconnect. |
|
|
2144
|
+
| `reconnectSocket` | `(token: string) => void` | Update the auth token on the existing socket and reconnect. When transit encryption is enabled it re-runs the full `connectSocket()` handshake (re-establishing the transit session) rather than a bare auth swap, and dedupes concurrent calls. |
|
|
2143
2145
|
| `getSocketStatus` | `() => SocketStatus` | Synchronously read the current connection status. |
|
|
2144
2146
|
| `onSocketStatus` | `(listener: (status: SocketStatus) => void) => () => void` | Subscribe to status changes. Returns an unsubscribe function. |
|
|
2145
2147
|
|
|
@@ -3054,6 +3056,38 @@ document.querySelectorAll('[data-conv-id]').forEach((el) => {
|
|
|
3054
3056
|
|
|
3055
3057
|
## Changelog
|
|
3056
3058
|
|
|
3059
|
+
### v1.3.5
|
|
3060
|
+
|
|
3061
|
+
- **Fix: `reconnectSocket()` no longer drops the transit-encryption handshake** — when transit encryption is enabled, `reconnectSocket()` now delegates to the full `connectSocket()` flow instead of doing a bare `_socket.auth` swap. `reconnectSocket()` predates transit encryption and was never migrated: it overwrote `_socket.auth` with only `{ token, userId, tenantId }`, dropping the `transitSessionId` / `transitEphemeralPub` fields that `connectSocket()` sets during the handshake. Combined with the `'disconnect'` handler clearing the cached transit session, a reconnect after the socket had disconnected (e.g. app returning to foreground on iOS/Android, where backgrounding fully disconnects) went out with no transit auth and no cached session → the server rejected the handshake with **"Transit encryption required: missing transitEphemeralPub/transitAlgo in handshake auth"**. It was intermittent — fast devices whose cached transit session survived the reconnect were unaffected.
|
|
3062
|
+
|
|
3063
|
+
Now, when transit encryption is on, `reconnectSocket()` re-runs `connectSocket()`, which re-establishes/reuses the transit session and rebuilds the handshake auth. It also inherits `connectSocket()`'s in-flight dedupe (`_connectingPromise`), so multiple rapid reconnect calls (a token refresh can trigger several) collapse into a single connect. Non-transit deployments keep the original fast bare auth-swap path unchanged.
|
|
3064
|
+
|
|
3065
|
+
The transit path is gated on the resolved config flag (`transitEncryption`), not the runtime `isTransitEnabled()` — the latter is `false` immediately after a disconnect clears the session, which is exactly when the transit-aware reconnect is needed.
|
|
3066
|
+
|
|
3067
|
+
**No integration changes required** — `reconnectSocket(token, userId, tenantId)` keeps the same signature; the SDK now handles the transit handshake internally on reconnect.
|
|
3068
|
+
|
|
3069
|
+
### v1.3.4
|
|
3070
|
+
|
|
3071
|
+
- **New: `deletedConversationIds` in `CrossConversationSyncResponse`** — `syncApi.pull(since)` now returns `deletedConversationIds: string[]`. Contains the IDs of conversations this user explicitly deleted from their list (via the delete-conversation action) since the `since` cursor. The client should remove these from local SQLite and the UI conversation list.
|
|
3072
|
+
|
|
3073
|
+
```typescript
|
|
3074
|
+
const result = await syncApi.pull(lastSyncedAt);
|
|
3075
|
+
|
|
3076
|
+
// Remove conversations the user deleted from their list
|
|
3077
|
+
for (const convId of result.deletedConversationIds) {
|
|
3078
|
+
await db.conversations.delete(convId);
|
|
3079
|
+
}
|
|
3080
|
+
```
|
|
3081
|
+
|
|
3082
|
+
**Scoped to the requesting user only** — if another user deletes their copy of a shared DM, it does not appear in your `deletedConversationIds`. **Cursor-safe** — once the client saves the returned `syncedAt` as the new cursor, the same IDs will not reappear on the next `pull()` call. On the server side, this is detected via `participant.isHidden = true AND updatedAt > since` — the same flag set by `DELETE /conversations/:id`.
|
|
3083
|
+
|
|
3084
|
+
- **Fix: Sync access guard parity with message listing API** — All three sync paths now enforce the same access rules as `GET /messages`:
|
|
3085
|
+
- **`membershipPeriods` windows** — users who deleted and were re-added only see messages from their active membership periods; a deleted conversation with no periods returns no messages.
|
|
3086
|
+
- **`status` filter** — active messages and deleted-for-everyone tombstones (so clients can render "This message was deleted") are included; `failed`-status messages are excluded.
|
|
3087
|
+
- **`isHidden` group check** — hidden group participants (exit+delete) receive `403 Forbidden` on per-conversation sync, matching message listing behaviour. Hidden DM participants are still allowed.
|
|
3088
|
+
- **Removed-member read access** — removed members (`isActive: false`) can still call per-conversation sync to retrieve history, matching the message listing API's `validateConversationAccess` which does not require `isActive: true` for reads.
|
|
3089
|
+
- **No integration changes required.** These are server-side enforcement fixes — the response shape is unchanged, only the set of messages returned is now correctly filtered.
|
|
3090
|
+
|
|
3057
3091
|
### v1.3.3
|
|
3058
3092
|
|
|
3059
3093
|
- **New: `metadata` and `sender` fields in all sync message responses** — Messages returned by all three sync paths (`crossConversationSync`, `conversationSync`, `conversationSyncBySeq`) now include `metadata` (system message metadata — `actorUserId`, `targetUserId`, `action`) and `sender` (displayName, avatarUrl snapshot at send time). Both fields were already optional on the core SDK `Message` type so no SDK type changes were required. Previously absent from sync responses, meaning system message text could not be rendered and sender avatars were blank after an offline sync. The server batch-fetches sender profiles in a single `findByIds` call per sync request — one extra DB round trip per sync, not one per message. **No integration changes required.**
|
package/dist/index.cjs
CHANGED
|
@@ -1516,6 +1516,7 @@ var _statusListeners = /* @__PURE__ */ new Set();
|
|
|
1516
1516
|
var _getToken = null;
|
|
1517
1517
|
var _userId;
|
|
1518
1518
|
var _tenantId;
|
|
1519
|
+
var _config2 = null;
|
|
1519
1520
|
function setStatus(s) {
|
|
1520
1521
|
_status = s;
|
|
1521
1522
|
_statusListeners.forEach((l) => l(s));
|
|
@@ -1594,6 +1595,7 @@ async function _doConnect(config, getToken) {
|
|
|
1594
1595
|
_getToken = getToken;
|
|
1595
1596
|
_userId = config.userId;
|
|
1596
1597
|
_tenantId = config.tenantId;
|
|
1598
|
+
_config2 = config;
|
|
1597
1599
|
const token = getToken();
|
|
1598
1600
|
const socketHandshakeAuth = {
|
|
1599
1601
|
token: token ? `Bearer ${token}` : "",
|
|
@@ -1756,16 +1758,21 @@ function disconnectSocket() {
|
|
|
1756
1758
|
_getToken = null;
|
|
1757
1759
|
_userId = void 0;
|
|
1758
1760
|
_tenantId = void 0;
|
|
1761
|
+
_config2 = null;
|
|
1759
1762
|
}
|
|
1760
1763
|
function reconnectSocket(token, userId, tenantId) {
|
|
1761
|
-
if (_socket)
|
|
1762
|
-
|
|
1763
|
-
|
|
1764
|
-
|
|
1765
|
-
|
|
1766
|
-
};
|
|
1767
|
-
_socket.connect();
|
|
1764
|
+
if (!_socket) return;
|
|
1765
|
+
if (_config2?.transitEncryption && _getToken) {
|
|
1766
|
+
if (!_socket.disconnected) _socket.disconnect();
|
|
1767
|
+
void connectSocket(_config2, _getToken);
|
|
1768
|
+
return;
|
|
1768
1769
|
}
|
|
1770
|
+
_socket.auth = {
|
|
1771
|
+
token: `Bearer ${token}`,
|
|
1772
|
+
...userId && { userId },
|
|
1773
|
+
...tenantId && { tenantId }
|
|
1774
|
+
};
|
|
1775
|
+
_socket.connect();
|
|
1769
1776
|
}
|
|
1770
1777
|
function refreshSocketAuth() {
|
|
1771
1778
|
if (!_socket || !_getToken) return false;
|