@droponair/sdk-js 0.3.1 → 0.5.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 +42 -0
- package/README.md +72 -0
- package/dist/attachment/attachment-client.d.ts +74 -0
- package/dist/attachment/attachment-client.js +323 -0
- package/dist/attachment/attachment-types.d.ts +77 -0
- package/dist/attachment/attachment-types.js +11 -0
- package/dist/core/messaging-client.d.ts +25 -2
- package/dist/core/messaging-client.js +314 -3
- package/dist/core/types.d.ts +77 -1
- package/dist/index.d.ts +2 -1
- package/dist/transport/protobuf-codec.d.ts +61 -0
- package/dist/transport/protobuf-codec.js +139 -1
- package/dist/version.d.ts +2 -2
- package/dist/version.js +2 -2
- package/package.json +1 -1
|
@@ -42,9 +42,28 @@ const DeviceEncryptedPayloadType = new protobuf.Type('DeviceEncryptedPayload')
|
|
|
42
42
|
.add(new protobuf.Field('deviceId', 1, 'string'))
|
|
43
43
|
.add(new protobuf.Field('encryptedPayload', 2, 'bytes'))
|
|
44
44
|
.add(new protobuf.Field('senderPublicKey', 3, 'bytes'));
|
|
45
|
+
// Per-device wrapped file key for E2EE attachments (PROTOCOL_VERSION 4+)
|
|
46
|
+
const DeviceWrappedKeyType = new protobuf.Type('DeviceWrappedKey')
|
|
47
|
+
.add(new protobuf.Field('deviceId', 1, 'string'))
|
|
48
|
+
.add(new protobuf.Field('wrappedKey', 2, 'bytes'))
|
|
49
|
+
.add(new protobuf.Field('senderPublicKey', 3, 'bytes'))
|
|
50
|
+
.add(new protobuf.Field('nonce', 4, 'bytes'));
|
|
51
|
+
// Reference to an out-of-band attachment in customer-managed storage.
|
|
52
|
+
const AttachmentRefEncTypeEnum = new protobuf.Enum('EncryptionType', { E2EE: 0, CLEARTEXT: 1 });
|
|
53
|
+
const AttachmentRefType = new protobuf.Type('AttachmentRef')
|
|
54
|
+
.add(AttachmentRefEncTypeEnum)
|
|
55
|
+
.add(DeviceWrappedKeyType)
|
|
56
|
+
.add(new protobuf.Field('attachmentId', 1, 'string'))
|
|
57
|
+
.add(new protobuf.Field('storageHint', 2, 'string'))
|
|
58
|
+
.add(new protobuf.Field('mimeType', 3, 'string'))
|
|
59
|
+
.add(new protobuf.Field('sizeBytes', 4, 'int64'))
|
|
60
|
+
.add(new protobuf.Field('sha256', 5, 'string'))
|
|
61
|
+
.add(new protobuf.Field('encryptionType', 6, 'EncryptionType'))
|
|
62
|
+
.add(new protobuf.Field('wrappedKeys', 7, 'DeviceWrappedKey', 'repeated'));
|
|
45
63
|
const EnvelopeType = new protobuf.Type('Envelope')
|
|
46
64
|
.add(EncryptionTypeEnum)
|
|
47
65
|
.add(DeviceEncryptedPayloadType) // nested type must be added first
|
|
66
|
+
.add(AttachmentRefType)
|
|
48
67
|
.add(new protobuf.Field('messageId', 1, 'string'))
|
|
49
68
|
.add(new protobuf.Field('appId', 2, 'string'))
|
|
50
69
|
.add(new protobuf.Field('fromUserId', 3, 'string'))
|
|
@@ -55,7 +74,8 @@ const EnvelopeType = new protobuf.Type('Envelope')
|
|
|
55
74
|
.add(new protobuf.Field('devicePayloads', 8, 'DeviceEncryptedPayload', 'repeated'))
|
|
56
75
|
.add(new protobuf.Field('senderDeviceId', 9, 'string'))
|
|
57
76
|
.add(new protobuf.Field('encryptionType', 10, 'EncryptionType'))
|
|
58
|
-
.add(new protobuf.Field('plaintextPayload', 11, 'string'))
|
|
77
|
+
.add(new protobuf.Field('plaintextPayload', 11, 'string'))
|
|
78
|
+
.add(new protobuf.Field('attachments', 12, 'AttachmentRef', 'repeated'));
|
|
59
79
|
const AckType = new protobuf.Type('Ack')
|
|
60
80
|
.add(new protobuf.Field('messageId', 1, 'string'))
|
|
61
81
|
.add(new protobuf.Field('type', 2, 'string'));
|
|
@@ -104,6 +124,9 @@ const GroupMemberPayloadType = new protobuf.Type('GroupMemberPayload')
|
|
|
104
124
|
.add(new protobuf.Field('userId', 1, 'string'))
|
|
105
125
|
.add(new protobuf.Field('devicePayloads', 2, 'DeviceEncryptedPayload', 'repeated'));
|
|
106
126
|
const GroupEnvelopeEncryptionTypeEnum = new protobuf.Enum('EncryptionType', { E2EE: 0, CLEARTEXT: 1 });
|
|
127
|
+
// NOTE: GroupEnvelope JS field numbers diverge from the proto contract (tracked
|
|
128
|
+
// under phase 2.3 "JS encrypted group send parity"). Attachments support for
|
|
129
|
+
// groups in JS will land with phase 2.3 / 2.4 once field numbers are aligned.
|
|
107
130
|
const GroupEnvelopeType = new protobuf.Type('GroupEnvelope')
|
|
108
131
|
.add(GroupEnvelopeEncryptionTypeEnum)
|
|
109
132
|
.add(GroupMemberPayloadType)
|
|
@@ -141,6 +164,47 @@ const GroupCallFrameType = new protobuf.Type('GroupCallFrame')
|
|
|
141
164
|
.add(new protobuf.Field('groupId', 3, 'string'))
|
|
142
165
|
.add(new protobuf.Field('targetUserId', 4, 'string'))
|
|
143
166
|
.add(new protobuf.Field('payload', 5, 'string'));
|
|
167
|
+
// ---------------------------------------------------------------------------
|
|
168
|
+
// Message Edit and Delete (PROTOCOL_VERSION 3+)
|
|
169
|
+
// ---------------------------------------------------------------------------
|
|
170
|
+
//
|
|
171
|
+
// E2EE invariant, server never sees plaintext for E2EE edits. The same frame
|
|
172
|
+
// type is sent on the wire in both directions, client to server (request) and
|
|
173
|
+
// server to recipient devices (notification).
|
|
174
|
+
//
|
|
175
|
+
// Type discriminator at field 1 mirrors the CallFrame pattern. Probed BEFORE
|
|
176
|
+
// Envelope to avoid mis-routing.
|
|
177
|
+
const MessageEditDeviceType = new protobuf.Type('DeviceEncryptedPayload')
|
|
178
|
+
.add(new protobuf.Field('deviceId', 1, 'string'))
|
|
179
|
+
.add(new protobuf.Field('encryptedPayload', 2, 'bytes'))
|
|
180
|
+
.add(new protobuf.Field('senderPublicKey', 3, 'bytes'));
|
|
181
|
+
const MessageEditEncryptionTypeEnum = new protobuf.Enum('EncryptionType', { E2EE: 0, CLEARTEXT: 1 });
|
|
182
|
+
const MessageEditFrameType = new protobuf.Type('MessageEditFrame')
|
|
183
|
+
.add(MessageEditEncryptionTypeEnum)
|
|
184
|
+
.add(MessageEditDeviceType)
|
|
185
|
+
.add(new protobuf.Field('type', 1, 'string'))
|
|
186
|
+
.add(new protobuf.Field('editId', 2, 'string'))
|
|
187
|
+
.add(new protobuf.Field('originalMessageId', 3, 'string'))
|
|
188
|
+
.add(new protobuf.Field('appId', 4, 'string'))
|
|
189
|
+
.add(new protobuf.Field('fromUserId', 5, 'string'))
|
|
190
|
+
.add(new protobuf.Field('toUserId', 6, 'string'))
|
|
191
|
+
.add(new protobuf.Field('timestamp', 7, 'int64'))
|
|
192
|
+
.add(new protobuf.Field('encryptionType', 8, 'EncryptionType'))
|
|
193
|
+
.add(new protobuf.Field('encryptedPayload', 9, 'bytes'))
|
|
194
|
+
.add(new protobuf.Field('devicePayloads', 10, 'DeviceEncryptedPayload', 'repeated'))
|
|
195
|
+
.add(new protobuf.Field('senderDeviceId', 11, 'string'))
|
|
196
|
+
.add(new protobuf.Field('plaintextPayload', 12, 'string'))
|
|
197
|
+
.add(new protobuf.Field('clientEditId', 13, 'string'));
|
|
198
|
+
const MessageDeleteFrameType = new protobuf.Type('MessageDeleteFrame')
|
|
199
|
+
.add(new protobuf.Field('type', 1, 'string'))
|
|
200
|
+
.add(new protobuf.Field('deleteId', 2, 'string'))
|
|
201
|
+
.add(new protobuf.Field('originalMessageId', 3, 'string'))
|
|
202
|
+
.add(new protobuf.Field('appId', 4, 'string'))
|
|
203
|
+
.add(new protobuf.Field('fromUserId', 5, 'string'))
|
|
204
|
+
.add(new protobuf.Field('toUserId', 6, 'string'))
|
|
205
|
+
.add(new protobuf.Field('timestamp', 7, 'int64'))
|
|
206
|
+
.add(new protobuf.Field('scope', 8, 'string'))
|
|
207
|
+
.add(new protobuf.Field('clientDeleteId', 9, 'string'));
|
|
144
208
|
class ProtobufCodec {
|
|
145
209
|
encodeEnvelope(value) {
|
|
146
210
|
return EnvelopeType.encode(value).finish();
|
|
@@ -163,7 +227,24 @@ class ProtobufCodec {
|
|
|
163
227
|
encodeGroupAck(value) {
|
|
164
228
|
return GroupAckType.encode(value).finish();
|
|
165
229
|
}
|
|
230
|
+
encodeMessageEditFrame(value) {
|
|
231
|
+
return MessageEditFrameType.encode(value).finish();
|
|
232
|
+
}
|
|
233
|
+
encodeMessageDeleteFrame(value) {
|
|
234
|
+
return MessageDeleteFrameType.encode(value).finish();
|
|
235
|
+
}
|
|
166
236
|
decodeFrame(payload) {
|
|
237
|
+
// Edit and delete frames must be probed BEFORE Envelope, the type
|
|
238
|
+
// discriminator at field 1 ("MESSAGE_EDIT" / "MESSAGE_DELETE") would
|
|
239
|
+
// otherwise parse as Envelope.messageId and could be mis-routed.
|
|
240
|
+
const asEdit = this.tryDecodeMessageEditFrame(payload);
|
|
241
|
+
if (asEdit) {
|
|
242
|
+
return { kind: 'messageEdit', data: asEdit };
|
|
243
|
+
}
|
|
244
|
+
const asDelete = this.tryDecodeMessageDeleteFrame(payload);
|
|
245
|
+
if (asDelete) {
|
|
246
|
+
return { kind: 'messageDelete', data: asDelete };
|
|
247
|
+
}
|
|
167
248
|
const asEnvelope = this.tryDecodeEnvelope(payload);
|
|
168
249
|
if (asEnvelope) {
|
|
169
250
|
return { kind: 'envelope', data: asEnvelope };
|
|
@@ -231,6 +312,23 @@ class ProtobufCodec {
|
|
|
231
312
|
senderPublicKey: new Uint8Array(dp.senderPublicKey),
|
|
232
313
|
}));
|
|
233
314
|
}
|
|
315
|
+
// Normalize attachments (PROTOCOL_VERSION 4+)
|
|
316
|
+
if (decoded.attachments && decoded.attachments.length > 0) {
|
|
317
|
+
result.attachments = decoded.attachments.map(att => ({
|
|
318
|
+
attachmentId: att.attachmentId,
|
|
319
|
+
storageHint: att.storageHint,
|
|
320
|
+
mimeType: att.mimeType,
|
|
321
|
+
sizeBytes: Number(att.sizeBytes),
|
|
322
|
+
sha256: att.sha256,
|
|
323
|
+
encryptionType: att.encryptionType ?? 0,
|
|
324
|
+
wrappedKeys: att.wrappedKeys?.map(wk => ({
|
|
325
|
+
deviceId: wk.deviceId,
|
|
326
|
+
wrappedKey: new Uint8Array(wk.wrappedKey),
|
|
327
|
+
senderPublicKey: new Uint8Array(wk.senderPublicKey),
|
|
328
|
+
nonce: new Uint8Array(wk.nonce),
|
|
329
|
+
})) ?? [],
|
|
330
|
+
}));
|
|
331
|
+
}
|
|
234
332
|
return result;
|
|
235
333
|
}
|
|
236
334
|
catch {
|
|
@@ -333,5 +431,45 @@ class ProtobufCodec {
|
|
|
333
431
|
return null;
|
|
334
432
|
}
|
|
335
433
|
}
|
|
434
|
+
tryDecodeMessageEditFrame(payload) {
|
|
435
|
+
try {
|
|
436
|
+
const decoded = MessageEditFrameType.decode(payload);
|
|
437
|
+
if (decoded.type !== 'MESSAGE_EDIT') {
|
|
438
|
+
return null;
|
|
439
|
+
}
|
|
440
|
+
const result = {
|
|
441
|
+
...decoded,
|
|
442
|
+
timestamp: Number(decoded.timestamp),
|
|
443
|
+
encryptedPayload: decoded.encryptedPayload && decoded.encryptedPayload.length > 0
|
|
444
|
+
? new Uint8Array(decoded.encryptedPayload) : undefined,
|
|
445
|
+
};
|
|
446
|
+
if (decoded.devicePayloads && decoded.devicePayloads.length > 0) {
|
|
447
|
+
result.devicePayloads = decoded.devicePayloads.map(dp => ({
|
|
448
|
+
deviceId: dp.deviceId,
|
|
449
|
+
encryptedPayload: new Uint8Array(dp.encryptedPayload),
|
|
450
|
+
senderPublicKey: new Uint8Array(dp.senderPublicKey),
|
|
451
|
+
}));
|
|
452
|
+
}
|
|
453
|
+
return result;
|
|
454
|
+
}
|
|
455
|
+
catch {
|
|
456
|
+
return null;
|
|
457
|
+
}
|
|
458
|
+
}
|
|
459
|
+
tryDecodeMessageDeleteFrame(payload) {
|
|
460
|
+
try {
|
|
461
|
+
const decoded = MessageDeleteFrameType.decode(payload);
|
|
462
|
+
if (decoded.type !== 'MESSAGE_DELETE') {
|
|
463
|
+
return null;
|
|
464
|
+
}
|
|
465
|
+
return {
|
|
466
|
+
...decoded,
|
|
467
|
+
timestamp: Number(decoded.timestamp),
|
|
468
|
+
};
|
|
469
|
+
}
|
|
470
|
+
catch {
|
|
471
|
+
return null;
|
|
472
|
+
}
|
|
473
|
+
}
|
|
336
474
|
}
|
|
337
475
|
exports.ProtobufCodec = ProtobufCodec;
|
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.5.0";
|
|
11
11
|
/**
|
|
12
12
|
* Binary encrypted-payload format version.
|
|
13
13
|
* Included as the first byte of every encrypted payload so receivers can
|
|
@@ -19,4 +19,4 @@ export declare const PAYLOAD_FORMAT_VERSION = 1;
|
|
|
19
19
|
* Increment when adding required proto fields or changing frame semantics.
|
|
20
20
|
* The server advertises its supported range via GET /api/info.
|
|
21
21
|
*/
|
|
22
|
-
export declare const PROTOCOL_VERSION =
|
|
22
|
+
export declare const PROTOCOL_VERSION = 4;
|
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.5.0';
|
|
14
14
|
/**
|
|
15
15
|
* Binary encrypted-payload format version.
|
|
16
16
|
* Included as the first byte of every encrypted payload so receivers can
|
|
@@ -22,4 +22,4 @@ exports.PAYLOAD_FORMAT_VERSION = 1;
|
|
|
22
22
|
* Increment when adding required proto fields or changing frame semantics.
|
|
23
23
|
* The server advertises its supported range via GET /api/info.
|
|
24
24
|
*/
|
|
25
|
-
exports.PROTOCOL_VERSION =
|
|
25
|
+
exports.PROTOCOL_VERSION = 4;
|