@droponair/sdk-js 0.22.0 → 0.22.1

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 CHANGED
@@ -6,12 +6,20 @@ This project follows [Semantic Versioning](https://semver.org/).
6
6
 
7
7
  ---
8
8
 
9
+ ## [0.22.1], 2026-05-31
10
+
11
+ ### Fixed
12
+
13
+ - **Message send/receive broken when attachments support is compiled in.** The protobuf reflection tree shared a single `AttachmentRef` type instance across `Envelope`, `GroupEnvelope`, and `GroupMessageNotification`. Because a protobufjs reflection object can have only one parent, adding it to a later message re-parented it and removed it from `Envelope`, so encoding any 1:1 message threw `no such Type or Enum 'AttachmentRef' in Type Envelope` before a frame was ever produced. Each message now builds its own `AttachmentRef` (and nested `DeviceWrappedKey` / `EncryptionType`) instance. Wire format is unchanged, this is purely a client-side construction fix. Also resolves the same latent failure on `GroupMessageNotification` decode.
14
+
15
+ ---
16
+
9
17
  ## [0.22.0], 2026-05-25
10
18
 
11
19
  ### Added
12
20
 
13
21
  - **MessagingClient transport selection.** `initialize({ transport: 'ws' | 'sse' | 'wt' | 'auto' })` lets your app choose the signaling lane at init time. Default stays `'ws'`, so existing integrations are byte-identical. `'auto'` queries `GET /api/info.transports` and picks the best available lane from what the runtime supports. WebSocket close-code semantics (1008 JWT-expiry surfacing, 4001 JWT-refresh-on-event) are preserved on the WebSocket path; SSE/WT synthesize close events.
14
- - **MQTT (IoT) broadcast lane (4.5b).** Broadcasts now mirror to MQTT topic `droponair/v1/broadcast/{appId}/{channelId}` on `mqtts://mqtt.droponair.com:8883`. For IoT subscribers that consume your broadcasts without our full SDK. Subscribe-only, per-app credentials, TLS only. Visible via `GET /api/info` (`transports` includes `"mqtt"`, `features` includes `"transport_mqtt"`). No SDK API change, the lane is consumed directly by MQTT clients.
22
+ - **MQTT (IoT) broadcast lane.** Broadcasts now mirror to MQTT topic `droponair/v1/broadcast/{appId}/{channelId}` on `mqtts://mqtt.droponair.com:8883`. For IoT subscribers that consume your broadcasts without our full SDK. Subscribe-only, per-app credentials, TLS only. Visible via `GET /api/info` (`transports` includes `"mqtt"`, `features` includes `"transport_mqtt"`). No SDK API change, the lane is consumed directly by MQTT clients.
15
23
 
16
24
  ### Changed
17
25
 
@@ -23,11 +31,11 @@ This project follows [Semantic Versioning](https://semver.org/).
23
31
 
24
32
  ### Added
25
33
 
26
- - **Transport auto-select helper (Phase 4.6).** New `selectTransport({ httpUrl })` reads `/api/info.transports`, intersects with the runtime's `WebTransport`/`WebSocket`/`EventSource` availability, and returns the best lane (preference: WebTransport -> WebSocket -> SSE; overridable via `preference`). Caller then constructs the corresponding primitive. Pluggable `fetchFn` for Node + tests.
34
+ - **Transport auto-select helper.** New `selectTransport({ httpUrl })` reads `/api/info.transports`, intersects with the runtime's `WebTransport`/`WebSocket`/`EventSource` availability, and returns the best lane (preference: WebTransport -> WebSocket -> SSE; overridable via `preference`). Caller then constructs the corresponding primitive. Pluggable `fetchFn` for Node + tests.
27
35
 
28
36
  ### Notes
29
37
 
30
- - Foundation for an `init({ transport: 'auto' })` shortcut once full `MessagingClient` integration lands (4.2.1b). Today it's a small standalone helper so existing customers can adopt the pattern without waiting.
38
+ - Foundation for an `init({ transport: 'auto' })` shortcut once full `MessagingClient` integration lands in a follow-up release. Today it's a small standalone helper so existing customers can adopt the pattern without waiting.
31
39
 
32
40
  ---
33
41
 
@@ -35,12 +43,12 @@ This project follows [Semantic Versioning](https://semver.org/).
35
43
 
36
44
  ### Added
37
45
 
38
- - **WebTransport (HTTP/3) transport primitive (Phase 4.3).** New `WebTransportTransport` class uses the browser-native `WebTransport` API to ride the platform's `/v1/transport/wt` HTTP/3 endpoint, terminated by the `droponair-webtransport` sidecar. Same shape as `SseTransport`: `onFrame`, `sendEnvelope`, `connect`, `close`. Caller brings own protobuf decoder. Browser-only for v1 (Chromium 97+, Firefox 125+, Safari TP-only); Node 22+ has experimental support behind flags.
46
+ - **WebTransport (HTTP/3) transport primitive.** New `WebTransportTransport` class uses the browser-native `WebTransport` API to ride the platform's `/v1/transport/wt` HTTP/3 endpoint,. Same shape as `SseTransport`: `onFrame`, `sendEnvelope`, `connect`, `close`. Caller brings own protobuf decoder. Browser-only for v1 (Chromium 97+, Firefox 125+, Safari TP-only); Node 22+ has experimental support behind flags.
39
47
 
40
48
  ### Notes
41
49
 
42
50
  - WebTransport gives multi-stream perf wins over WebSocket on flaky cellular and similar networks. WebSocket on `/ws` remains the default; this primitive is opt-in for environments that have native WebTransport.
43
- - The droponair.com endpoint only advertises `transports: ["webtransport"]` once the `droponair-webtransport` sidecar is up and `app.transport.webtransport-enabled` is flipped on sdk-be. Check `GET /api/info.transports` for the live list.
51
+ - The droponair.com endpoint only advertises `transports: ["webtransport"]` once the HTTP/3 lane is enabled and `app.transport.webtransport-enabled` is flipped on the platform. Check `GET /api/info.transports` for the live list.
44
52
 
45
53
  ---
46
54
 
@@ -48,11 +56,11 @@ This project follows [Semantic Versioning](https://semver.org/).
48
56
 
49
57
  ### Added
50
58
 
51
- - **SSE transport primitive (Phase 4.2.1).** New `SseTransport` class exposes the platform's HTTP-fallback lane (`/v1/transport/stream` + `/v1/transport/send`) as a small standalone client, for environments where WebSocket upgrades are blocked by corporate firewalls but HTTPS GET/POST work. EventSource-based receive (auto-reconnects), `fetch` POST for send. Bring your own protobuf decoder (use the codec already exported from the SDK).
59
+ - **SSE transport primitive.** New `SseTransport` class exposes the platform's HTTP-fallback lane (`/v1/transport/stream` + `/v1/transport/send`) as a small standalone client, for environments where WebSocket upgrades are blocked by corporate firewalls but HTTPS GET/POST work. EventSource-based receive (auto-reconnects), `fetch` POST for send. Bring your own protobuf decoder (use the codec already exported from the SDK).
52
60
 
53
61
  ### Notes
54
62
 
55
- - v1 is a primitive; full `init({ transport: 'sse' })` integration into `MessagingClient` lands in 4.2.1b. Customers who need the SSE lane today can use `SseTransport` directly alongside the existing WS client.
63
+ - v1 is a primitive; full `init({ transport: 'sse' })` integration into `MessagingClient` lands in a follow-up release. Customers who need the SSE lane today can use `SseTransport` directly alongside the existing WS client.
56
64
  - WebSocket on `/ws` remains the default for all SDK calls; this addition is purely opt-in. Older code paths and existing apps are unaffected.
57
65
 
58
66
  ---
@@ -61,7 +69,7 @@ This project follows [Semantic Versioning](https://semver.org/).
61
69
 
62
70
  ### Added
63
71
 
64
- - **SFU recording (Phase 3.7.5).** Server-side recording for SFU-mode rooms with `mediaEncryption: 'SFU'`. The platform's media server records the composite of every track in the room and uploads the finalized file directly to the customer's storage bucket - the platform never holds the recorded bytes. Storage destinations (S3 / GCS / Azure) are registered once in the panel; the SDK references each by an opaque `destinationId`.
72
+ - **SFU recording.** Server-side recording for SFU-mode rooms with `mediaEncryption: 'SFU'`. The platform's media server records the composite of every track in the room and uploads the finalized file directly to the customer's storage bucket - the platform never holds the recorded bytes. Storage destinations (S3 / GCS / Azure) are registered once in the panel; the SDK references each by an opaque `destinationId`.
65
73
  - Three new client methods:
66
74
  - `startSfuRecording(roomId, destinationId)` -> `SfuRecording`
67
75
  - `stopSfuRecording(roomId, recordingId)` -> `SfuRecording`
@@ -326,7 +334,6 @@ This project follows [Semantic Versioning](https://semver.org/).
326
334
  - Wire-level additive: legacy 0.4.x clients ignore the new `Envelope.attachments` field (proto3 forwards-compat). Existing apps continue to work unchanged.
327
335
  - v1 storage adapters supported by the server: S3-compatible (S3, R2, MinIO, B2, Wasabi), Google Cloud Storage, Azure Blob.
328
336
  - Plan limits: `maxAttachmentSizeMb` per file + `maxAttachmentsPerMonth`. FREE = attachments disabled. PRO = 25 MB / 1000 per month. GROWTH = 100 MB / 10000. PAYG = 250 MB / metered. ENTERPRISE = custom.
329
- - Requires sdk-be `0.5.0` server.
330
337
 
331
338
  ---
332
339
 
@@ -342,7 +349,6 @@ This project follows [Semantic Versioning](https://semver.org/).
342
349
  ### Notes
343
350
  - Each edit and each `FOR_EVERYONE` delete counts as **one** MESSAGE usage record (subject to plan quotas + rate limits).
344
351
  - Wire-level additive: legacy 0.3.x clients ignore unknown frame types (proto3 forwards-compat), so existing TwinFlame and CrowdSyncer apps continue to work unchanged.
345
- - Requires sdk-be `0.4.0` server.
346
352
 
347
353
  ---
348
354
 
package/README.md CHANGED
@@ -183,7 +183,7 @@ E2EE invariant: the push body is sender-supplied cleartext metadata only (e.g. "
183
183
 
184
184
  ### Message Edit & Delete
185
185
 
186
- Available since SDK `0.4.0` and requires sdk-be `0.4.0`.
186
+ Available since SDK `0.4.0`.
187
187
 
188
188
  ```typescript
189
189
  // Edit an encrypted message
@@ -213,7 +213,7 @@ client.onMessageDelete((del) => {
213
213
 
214
214
  ### Attachments (Customer-Managed Storage)
215
215
 
216
- Available since SDK `0.5.0` and requires sdk-be `0.5.0`. Configure your bucket once in the DropOnAir panel (S3-compatible, GCS, or Azure Blob). DropOnAir never holds file bytes - the SDK uploads/downloads directly against your bucket via short-lived presigned URLs.
216
+ Available since SDK `0.5.0`. Configure your bucket once in the DropOnAir panel (S3-compatible, GCS, or Azure Blob). DropOnAir never holds file bytes - the SDK uploads/downloads directly against your bucket via short-lived presigned URLs.
217
217
 
218
218
  ```typescript
219
219
  // Convenience: encrypt + upload + finalize in one call, then send with the message.
@@ -42,29 +42,38 @@ 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'))
63
- .add(new protobuf.Field('thumbnailAttachmentId', 8, 'string'));
45
+ // Reference to an out-of-band attachment in customer-managed storage, plus its
46
+ // nested per-device wrapped file key (PROTOCOL_VERSION 4+).
47
+ //
48
+ // A protobufjs reflection object can have only ONE parent: calling `.add(obj)`
49
+ // on a second message re-parents `obj` and silently removes it from the first.
50
+ // Envelope, GroupEnvelope and GroupMessageNotification each nest AttachmentRef,
51
+ // so each needs its OWN instance, built fresh here. Sharing a single instance
52
+ // across them re-parented it onto the last adder and orphaned it from Envelope,
53
+ // breaking every 1:1 send with "no such Type or Enum 'AttachmentRef' in Type
54
+ // Envelope". The EncryptionType enum and DeviceWrappedKey type are nested inside
55
+ // each AttachmentRef and so are rebuilt per call for the same reason.
56
+ function buildAttachmentRefType() {
57
+ return new protobuf.Type('AttachmentRef')
58
+ .add(new protobuf.Enum('EncryptionType', { E2EE: 0, CLEARTEXT: 1 }))
59
+ .add(new protobuf.Type('DeviceWrappedKey')
60
+ .add(new protobuf.Field('deviceId', 1, 'string'))
61
+ .add(new protobuf.Field('wrappedKey', 2, 'bytes'))
62
+ .add(new protobuf.Field('senderPublicKey', 3, 'bytes'))
63
+ .add(new protobuf.Field('nonce', 4, 'bytes')))
64
+ .add(new protobuf.Field('attachmentId', 1, 'string'))
65
+ .add(new protobuf.Field('storageHint', 2, 'string'))
66
+ .add(new protobuf.Field('mimeType', 3, 'string'))
67
+ .add(new protobuf.Field('sizeBytes', 4, 'int64'))
68
+ .add(new protobuf.Field('sha256', 5, 'string'))
69
+ .add(new protobuf.Field('encryptionType', 6, 'EncryptionType'))
70
+ .add(new protobuf.Field('wrappedKeys', 7, 'DeviceWrappedKey', 'repeated'))
71
+ .add(new protobuf.Field('thumbnailAttachmentId', 8, 'string'));
72
+ }
64
73
  const EnvelopeType = new protobuf.Type('Envelope')
65
74
  .add(EncryptionTypeEnum)
66
75
  .add(DeviceEncryptedPayloadType) // nested type must be added first
67
- .add(AttachmentRefType)
76
+ .add(buildAttachmentRefType())
68
77
  .add(new protobuf.Field('messageId', 1, 'string'))
69
78
  .add(new protobuf.Field('appId', 2, 'string'))
70
79
  .add(new protobuf.Field('fromUserId', 3, 'string'))
@@ -128,7 +137,7 @@ const GroupEnvelopeEncryptionTypeEnum = new protobuf.Enum('EncryptionType', { E2
128
137
  const GroupEnvelopeType = new protobuf.Type('GroupEnvelope')
129
138
  .add(GroupEnvelopeEncryptionTypeEnum)
130
139
  .add(GroupMemberPayloadType)
131
- .add(AttachmentRefType)
140
+ .add(buildAttachmentRefType())
132
141
  .add(new protobuf.Field('messageId', 1, 'string'))
133
142
  .add(new protobuf.Field('appId', 2, 'string'))
134
143
  .add(new protobuf.Field('groupId', 3, 'string'))
@@ -149,6 +158,7 @@ const GroupNotifDeviceType = new protobuf.Type('DeviceEncryptedPayload')
149
158
  const GroupMessageNotificationType = new protobuf.Type('GroupMessageNotification')
150
159
  .add(GroupNotifEncryptionTypeEnum)
151
160
  .add(GroupNotifDeviceType)
161
+ .add(buildAttachmentRefType())
152
162
  .add(new protobuf.Field('messageId', 1, 'string'))
153
163
  .add(new protobuf.Field('groupId', 2, 'string'))
154
164
  .add(new protobuf.Field('fromUserId', 3, 'string'))
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.22.0";
10
+ export declare const SDK_VERSION = "0.22.1";
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.22.0';
13
+ exports.SDK_VERSION = '0.22.1';
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@droponair/sdk-js",
3
- "version": "0.22.0",
3
+ "version": "0.22.1",
4
4
  "description": "DropOnAir SDK for end-to-end encrypted messaging",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",