@vex-chat/libvex 7.2.0 → 7.3.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.
@@ -27,7 +27,7 @@
27
27
  * - `LIBVEX_DEBUG_DM=1` — logs DM/X3dh paths in `Client` to stderr (remove / gate off when done).
28
28
  */
29
29
 
30
- import type { ClientOptions, Message } from "../../index.js";
30
+ import type { CallEvent, ClientOptions, Message } from "../../index.js";
31
31
  import type { Storage } from "../../Storage.js";
32
32
 
33
33
  import { getCryptoProfile, setCryptoProfile } from "@vex-chat/crypto";
@@ -117,6 +117,64 @@ export function platformSuite(
117
117
  expect(msg.extra).toBe(extra);
118
118
  });
119
119
 
120
+ test("encrypted call invite arrives as call event", async () => {
121
+ class NativeIceCandidate {
122
+ toJSON() {
123
+ return {
124
+ candidate: "candidate-test",
125
+ sdpMid: "0",
126
+ sdpMLineIndex: 0,
127
+ };
128
+ }
129
+ }
130
+ class NativeSessionDescription {
131
+ toJSON() {
132
+ return { sdp: "test-offer", type: "offer" };
133
+ }
134
+ }
135
+
136
+ const me = client.me.user();
137
+ let unexpectedMessages = 0;
138
+ const onMessage = (_msg: Message) => {
139
+ unexpectedMessages += 1;
140
+ };
141
+ client.on("message", onMessage);
142
+ try {
143
+ const callPromise = waitForCall(
144
+ client,
145
+ (event) =>
146
+ event.action === "invite" &&
147
+ event.fromDeviceID === client.me.device().deviceID,
148
+ `[${platformName}] encrypted self-call invite`,
149
+ );
150
+ const returned = await client.calls.startDM(me.userID, {
151
+ candidate: new NativeIceCandidate(),
152
+ description: new NativeSessionDescription(),
153
+ kind: "offer",
154
+ });
155
+ const incoming = await callPromise;
156
+ expect(returned.call.callID).toBe(incoming.call.callID);
157
+ expect(incoming.signal?.kind).toBe("offer");
158
+ expect(incoming.signal?.candidate).toEqual({
159
+ candidate: "candidate-test",
160
+ sdpMid: "0",
161
+ sdpMLineIndex: 0,
162
+ });
163
+ expect(incoming.signal?.description).toEqual({
164
+ sdp: "test-offer",
165
+ type: "offer",
166
+ });
167
+ expect(unexpectedMessages).toBe(0);
168
+
169
+ const active = await client.calls.active();
170
+ expect(
171
+ active.some((call) => call.callID === incoming.call.callID),
172
+ ).toBe(true);
173
+ } finally {
174
+ client.off("message", onMessage);
175
+ }
176
+ });
177
+
120
178
  test("message history retrieve + delete", async () => {
121
179
  const me = client.me.user();
122
180
  const body = "history-test";
@@ -721,6 +779,27 @@ async function e2eWaitForPeerDeviceCount(
721
779
  }
722
780
  */
723
781
 
782
+ async function waitForCall(
783
+ c: Client,
784
+ predicate: (event: CallEvent) => boolean,
785
+ label: string,
786
+ timeout = 10_000,
787
+ ): Promise<CallEvent> {
788
+ return new Promise((resolve, reject) => {
789
+ const timer = setTimeout(() => {
790
+ reject(new Error(`${label} call timed out`));
791
+ }, timeout);
792
+ const onCall = (event: CallEvent) => {
793
+ if (predicate(event)) {
794
+ clearTimeout(timer);
795
+ c.off("call", onCall);
796
+ resolve(event);
797
+ }
798
+ };
799
+ c.on("call", onCall);
800
+ });
801
+ }
802
+
724
803
  async function waitForMessage(
725
804
  c: Client,
726
805
  predicate: (m: Message) => boolean,