@droponair/sdk-js 0.28.0 → 0.29.0
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/CHANGELOG.md +19 -0
- package/README.md +6 -0
- package/dist/core/messaging-client.d.ts +9 -0
- package/dist/core/messaging-client.js +38 -0
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,24 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.29.0
|
|
4
|
+
|
|
5
|
+
### Fixed
|
|
6
|
+
|
|
7
|
+
- **Delivered and seen no longer depend on the sender being online.** A receipt
|
|
8
|
+
existed only as a frame on a live socket, so a sender who was away when someone
|
|
9
|
+
fetched or read the message never learned it and the mark stayed where it was
|
|
10
|
+
for good. An app that disconnects in the background, which is what an app has to
|
|
11
|
+
do to be pushed at all, missed nearly all of them. The SDK now catches up on
|
|
12
|
+
connect and reports the state as the ordinary delivered and read callbacks, so
|
|
13
|
+
there is no new API to adopt: existing receipt handling starts working.
|
|
14
|
+
|
|
15
|
+
### Notes
|
|
16
|
+
|
|
17
|
+
- Catch-up covers the messages you sent most recently and replays their current
|
|
18
|
+
state, so handling must be idempotent. Marks should only ever move forward.
|
|
19
|
+
- Additive and backward compatible. A relay that predates this answers 404 and
|
|
20
|
+
the SDK treats that as nothing to catch up on.
|
|
21
|
+
|
|
3
22
|
## 0.28.0
|
|
4
23
|
|
|
5
24
|
### Fixed
|
package/README.md
CHANGED
|
@@ -363,6 +363,12 @@ client.onMessage(async (msg) => {
|
|
|
363
363
|
| `sendCleartextGroupMessage(groupId, plaintext)` | `Promise<{ messageId }>` | Send a plaintext (non-encrypted) group message; server fans out to every other member. |
|
|
364
364
|
| `onGroupMessage(callback)` | `() => void` | Listen for group messages |
|
|
365
365
|
|
|
366
|
+
Delivered and seen are caught up on every connect, so a sender that was away
|
|
367
|
+
while someone fetched or read still learns about it. The state arrives through
|
|
368
|
+
the same delivered and read callbacks a live receipt uses, so there is nothing
|
|
369
|
+
extra to handle; make sure your handling is idempotent and only ever moves a
|
|
370
|
+
mark forward, since catch-up replays the current state rather than the changes.
|
|
371
|
+
|
|
366
372
|
**Group delivery is per member.** A group message has many recipients, so the platform
|
|
367
373
|
reports delivery as a set rather than a single flag and leaves the presentation to you.
|
|
368
374
|
`DELIVERED` and `SEEN` arrive as events whose `metadata` carries `messageId`, `groupId`
|
|
@@ -388,6 +388,15 @@ export declare class MessagingClient implements DropOnAirClient {
|
|
|
388
388
|
* live at that instant and is unreachable afterwards, so anyone closed loses it.
|
|
389
389
|
* Fetching is also what tells the sender the message reached this member.
|
|
390
390
|
*/
|
|
391
|
+
/**
|
|
392
|
+
* Catches up on who has the messages this client sent.
|
|
393
|
+
*
|
|
394
|
+
* A receipt used to be a frame on a live socket and nothing else, so a sender
|
|
395
|
+
* that was away when someone fetched or read never found out and the tick
|
|
396
|
+
* stayed where it was. The state is kept per member, and this replays it as the
|
|
397
|
+
* events that would have arrived live, so an app needs no separate path for it.
|
|
398
|
+
*/
|
|
399
|
+
private fetchGroupReceipts;
|
|
391
400
|
private fetchAndProcessOfflineGroupMessages;
|
|
392
401
|
private fetchAndProcessOfflineMessages;
|
|
393
402
|
private getValidDropOnAirJwt;
|
|
@@ -1806,6 +1806,9 @@ class MessagingClient {
|
|
|
1806
1806
|
this.sendPushRegistration().catch((err) => {
|
|
1807
1807
|
this.logError('push_registration_failed', { error: String(err) });
|
|
1808
1808
|
});
|
|
1809
|
+
this.fetchGroupReceipts().catch((err) => {
|
|
1810
|
+
this.logError('group_receipts_fetch_failed', { error: String(err) });
|
|
1811
|
+
});
|
|
1809
1812
|
this.fetchAndProcessOfflineGroupMessages().catch((err) => {
|
|
1810
1813
|
this.logError('group_offline_fetch_failed', { error: String(err) });
|
|
1811
1814
|
});
|
|
@@ -2277,6 +2280,41 @@ class MessagingClient {
|
|
|
2277
2280
|
* live at that instant and is unreachable afterwards, so anyone closed loses it.
|
|
2278
2281
|
* Fetching is also what tells the sender the message reached this member.
|
|
2279
2282
|
*/
|
|
2283
|
+
/**
|
|
2284
|
+
* Catches up on who has the messages this client sent.
|
|
2285
|
+
*
|
|
2286
|
+
* A receipt used to be a frame on a live socket and nothing else, so a sender
|
|
2287
|
+
* that was away when someone fetched or read never found out and the tick
|
|
2288
|
+
* stayed where it was. The state is kept per member, and this replays it as the
|
|
2289
|
+
* events that would have arrived live, so an app needs no separate path for it.
|
|
2290
|
+
*/
|
|
2291
|
+
async fetchGroupReceipts() {
|
|
2292
|
+
const jwt = await this.getValidDropOnAirJwt(false);
|
|
2293
|
+
const response = await this.fetchFn(`${this.httpUrl}/v1/groups/messages/receipts?limit=100`, {
|
|
2294
|
+
method: 'GET',
|
|
2295
|
+
headers: { Authorization: `Bearer ${jwt}`, 'Content-Type': 'application/json' },
|
|
2296
|
+
});
|
|
2297
|
+
// A relay that predates this endpoint answers 404: nothing to catch up on.
|
|
2298
|
+
if (!response.ok) {
|
|
2299
|
+
return;
|
|
2300
|
+
}
|
|
2301
|
+
const body = await response.json();
|
|
2302
|
+
for (const entry of body.messages ?? []) {
|
|
2303
|
+
for (const memberUserId of entry.deliveredTo ?? []) {
|
|
2304
|
+
this.emitEvent({
|
|
2305
|
+
type: 'DELIVERED',
|
|
2306
|
+
metadata: JSON.stringify({ messageId: entry.messageId, groupId: entry.groupId, memberUserId }),
|
|
2307
|
+
});
|
|
2308
|
+
}
|
|
2309
|
+
for (const memberUserId of entry.seenBy ?? []) {
|
|
2310
|
+
this.emitEvent({
|
|
2311
|
+
type: 'SEEN',
|
|
2312
|
+
metadata: JSON.stringify({ messageId: entry.messageId, groupId: entry.groupId, memberUserId }),
|
|
2313
|
+
});
|
|
2314
|
+
}
|
|
2315
|
+
}
|
|
2316
|
+
this.log('group_receipts_fetched', { messages: (body.messages ?? []).length });
|
|
2317
|
+
}
|
|
2280
2318
|
async fetchAndProcessOfflineGroupMessages() {
|
|
2281
2319
|
const jwt = await this.getValidDropOnAirJwt(false);
|
|
2282
2320
|
let page = 0;
|
package/dist/version.d.ts
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
* MINOR, additive feature (e.g. multi-device payloads, new call event type)
|
|
8
8
|
* PATCH, bug-fix / perf improvement with no wire or API change
|
|
9
9
|
*/
|
|
10
|
-
export declare const SDK_VERSION = "0.
|
|
10
|
+
export declare const SDK_VERSION = "0.29.0";
|
|
11
11
|
/**
|
|
12
12
|
* Binary encrypted-payload format version.
|
|
13
13
|
* Included as the first byte of every encrypted payload so receivers can
|
package/dist/version.js
CHANGED
|
@@ -10,7 +10,7 @@ exports.PROTOCOL_VERSION = exports.PAYLOAD_FORMAT_VERSION = exports.SDK_VERSION
|
|
|
10
10
|
* MINOR, additive feature (e.g. multi-device payloads, new call event type)
|
|
11
11
|
* PATCH, bug-fix / perf improvement with no wire or API change
|
|
12
12
|
*/
|
|
13
|
-
exports.SDK_VERSION = '0.
|
|
13
|
+
exports.SDK_VERSION = '0.29.0';
|
|
14
14
|
/**
|
|
15
15
|
* Binary encrypted-payload format version.
|
|
16
16
|
* Included as the first byte of every encrypted payload so receivers can
|
package/package.json
CHANGED