@voxevolv/client 0.3.15 → 0.3.17

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.
@@ -0,0 +1,20 @@
1
+ type SendRpc = (request: {
2
+ destinationIdentity: string;
3
+ method: string;
4
+ payload: string;
5
+ responseTimeout: number;
6
+ }) => Promise<string>;
7
+ /** Keeps concurrent and later deliveries of one presentation on the same promise. */
8
+ export declare class Presentations {
9
+ private readonly send;
10
+ private readonly isClosed;
11
+ private readonly receiptFailed;
12
+ private readonly results;
13
+ constructor(send: SendRpc, isClosed: () => boolean, receiptFailed: () => void);
14
+ invoke(id: string, worker: string, execute: () => Promise<string>): Promise<string>;
15
+ private execute;
16
+ private complete;
17
+ private request;
18
+ }
19
+ export {};
20
+ //# sourceMappingURL=presentations.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"presentations.d.ts","sourceRoot":"","sources":["../src/presentations.ts"],"names":[],"mappings":"AAMA,KAAK,OAAO,GAAG,CAAC,OAAO,EAAE;IACvB,mBAAmB,EAAE,MAAM,CAAC;IAC5B,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,eAAe,EAAE,MAAM,CAAC;CACzB,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;AAItB,qFAAqF;AACrF,qBAAa,aAAa;IAItB,OAAO,CAAC,QAAQ,CAAC,IAAI;IACrB,OAAO,CAAC,QAAQ,CAAC,QAAQ;IACzB,OAAO,CAAC,QAAQ,CAAC,aAAa;IALhC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAyC;IAEjE,YACmB,IAAI,EAAE,OAAO,EACb,QAAQ,EAAE,MAAM,OAAO,EACvB,aAAa,EAAE,MAAM,IAAI,EACxC;IAEJ,MAAM,CAAC,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,OAAO,CAAC,MAAM,CAAC,GAAG,OAAO,CAAC,MAAM,CAAC,CAoBlF;YAEa,OAAO;IAuCrB,OAAO,CAAC,QAAQ;IAQhB,OAAO,CAAC,OAAO;CAMhB"}
@@ -0,0 +1,91 @@
1
+ import { RpcError } from "livekit-client";
2
+ const PRESENTATION_METHOD = "voxevolv.presentation";
3
+ const MAX_CACHED_PRESENTATIONS = 64;
4
+ const MAX_RESULT_BYTES = 65_536;
5
+ /** Keeps concurrent and later deliveries of one presentation on the same promise. */
6
+ export class Presentations {
7
+ send;
8
+ isClosed;
9
+ receiptFailed;
10
+ results = new Map();
11
+ constructor(send, isClosed, receiptFailed) {
12
+ this.send = send;
13
+ this.isClosed = isClosed;
14
+ this.receiptFailed = receiptFailed;
15
+ }
16
+ invoke(id, worker, execute) {
17
+ const key = JSON.stringify([worker, id]);
18
+ const existing = this.results.get(key);
19
+ if (existing)
20
+ return existing.response;
21
+ if (this.results.size >= MAX_CACHED_PRESENTATIONS) {
22
+ const settled = [...this.results].find(([, item]) => item.settled);
23
+ if (!settled)
24
+ return Promise.reject(new RpcError(1500, "Too many pending presentations"));
25
+ this.results.delete(settled[0]);
26
+ }
27
+ // Defer execution until after insertion so reentrant calls also share ownership.
28
+ const cached = {
29
+ response: Promise.resolve().then(() => this.execute(id, worker, execute)),
30
+ settled: false,
31
+ };
32
+ this.results.set(key, cached);
33
+ void cached.response.then(() => { cached.settled = true; }, () => { cached.settled = true; });
34
+ return cached.response;
35
+ }
36
+ async execute(id, worker, execute) {
37
+ if (this.isClosed())
38
+ throw new RpcError(1500, "Session has ended");
39
+ const startedAt = performance.now();
40
+ let grant;
41
+ try {
42
+ grant = JSON.parse(await this.request(id, worker, { action: "claim" }));
43
+ }
44
+ catch (error) {
45
+ // No handler ran. A later delivery may retry authorization; the worker
46
+ // still rejects a second claim if the first response was merely lost.
47
+ // This pending entry cannot have been evicted or replaced in the cache.
48
+ this.results.delete(JSON.stringify([worker, id]));
49
+ throw error;
50
+ }
51
+ if (typeof grant.response === "string")
52
+ return grant.response;
53
+ if (typeof grant.error === "string")
54
+ throw new RpcError(1500, grant.error);
55
+ // Deduct the entire round trip, conservatively, without comparing wall clocks.
56
+ // A frozen tab must not execute a grant that sat waiting in its event queue.
57
+ if (this.isClosed() || typeof grant.remaining_ms !== "number"
58
+ || !Number.isFinite(grant.remaining_ms)
59
+ || performance.now() - startedAt >= grant.remaining_ms) {
60
+ throw new RpcError(1500, "Presentation authorization expired");
61
+ }
62
+ let response;
63
+ try {
64
+ response = await execute();
65
+ if (new TextEncoder().encode(response).byteLength > MAX_RESULT_BYTES) {
66
+ throw new RpcError(1500, "Presentation result is too large");
67
+ }
68
+ }
69
+ catch (error) {
70
+ const message = error instanceof Error ? error.message : "Presentation failed";
71
+ this.complete(id, worker, { error: message.slice(0, 1000) });
72
+ throw error;
73
+ }
74
+ this.complete(id, worker, { response });
75
+ return response;
76
+ }
77
+ complete(id, worker, result) {
78
+ // Do not delay the original RPC response. This independent receipt can reconcile
79
+ // an outcome after its original caller has already stopped waiting.
80
+ void this.request(id, worker, { action: "complete", ...result }).catch(() => {
81
+ this.receiptFailed();
82
+ });
83
+ }
84
+ request(id, worker, payload) {
85
+ return this.send({
86
+ destinationIdentity: worker, method: PRESENTATION_METHOD,
87
+ payload: JSON.stringify({ operation_id: id, ...payload }), responseTimeout: 2_000,
88
+ });
89
+ }
90
+ }
91
+ //# sourceMappingURL=presentations.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"presentations.js","sourceRoot":"","sources":["../src/presentations.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ import type { ClientDiagnosticInput } from "./diagnostics.js";
2
+ /** Observe the pinned LiveKit build; never inspect or retain RPC arguments/results.
3
+ * A channel_send means RTCDataChannel.send returned, not remote receipt.
4
+ */
5
+ export declare function observeRpcTransport(engineValue: unknown, record: (entry: ClientDiagnosticInput) => void): () => void;
6
+ //# sourceMappingURL=rpc-transport-diagnostics.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rpc-transport-diagnostics.d.ts","sourceRoot":"","sources":["../src/rpc-transport-diagnostics.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,kBAAkB,CAAC;AAwB9D;;GAEG;AACH,wBAAgB,mBAAmB,CACjC,WAAW,EAAE,OAAO,EACpB,MAAM,EAAE,CAAC,KAAK,EAAE,qBAAqB,KAAK,IAAI,GAC7C,MAAM,IAAI,CAuEZ"}
@@ -0,0 +1,84 @@
1
+ /** Observe the pinned LiveKit build; never inspect or retain RPC arguments/results.
2
+ * A channel_send means RTCDataChannel.send returned, not remote receipt.
3
+ */
4
+ export function observeRpcTransport(engineValue, record) {
5
+ const engine = engineValue;
6
+ const streams = new Map();
7
+ function metadata(packet, incoming) {
8
+ const value = packet.value?.value;
9
+ if (!value)
10
+ return;
11
+ const kind = packet.value?.case;
12
+ if (kind === "rpcRequest" || kind === "rpcAck" || kind === "rpcResponse") {
13
+ // Inline requests call their identifier `id`; ACKs/responses use requestId.
14
+ const requestId = kind === "rpcRequest" ? value.id : value.requestId;
15
+ if (!requestId)
16
+ return;
17
+ const packetKinds = { rpcRequest: "request", rpcAck: "ack", rpcResponse: "response" };
18
+ return { rpc_request_id: requestId, rpc_packet: packetKinds[kind] };
19
+ }
20
+ const key = `${incoming ? "in" : "out"}:${value.streamId}`;
21
+ if (kind === "streamHeader" && value.streamId
22
+ && (value.topic === "lk.rpc_request" || value.topic === "lk.rpc_response")) {
23
+ const requestId = value.attributes?.["lk.rpc_request_id"];
24
+ if (!requestId)
25
+ return;
26
+ const now = performance.now();
27
+ for (const [id, stream] of streams) {
28
+ if (now - stream.at >= 300_000)
29
+ streams.delete(id);
30
+ }
31
+ if (streams.size >= 128)
32
+ streams.delete(streams.keys().next().value);
33
+ const rpcKind = value.topic === "lk.rpc_request" ? "request" : "response";
34
+ streams.set(key, { requestId, kind: rpcKind, at: now });
35
+ return { rpc_request_id: requestId, rpc_packet: `${rpcKind}_header` };
36
+ }
37
+ if (kind === "streamTrailer") {
38
+ const stream = streams.get(key);
39
+ streams.delete(key);
40
+ if (stream)
41
+ return { rpc_request_id: stream.requestId, rpc_packet: `${stream.kind}_end` };
42
+ }
43
+ }
44
+ function observer(packet, incoming) {
45
+ const info = metadata(packet, incoming);
46
+ if (!info)
47
+ return;
48
+ const started = performance.now();
49
+ return (stage) => {
50
+ try {
51
+ const channel = engine.dataChannelForKind(0, incoming);
52
+ record({
53
+ operation: "rpc_transport", ...info, stage,
54
+ status: stage === "publish_failed" || stage === "channel_unavailable" ? "failed" : "started",
55
+ duration_ms: performance.now() - started,
56
+ channel_state: channel?.readyState,
57
+ buffered_bytes: channel?.bufferedAmount,
58
+ });
59
+ }
60
+ catch {
61
+ // Observers must never alter a packet's delivery or exception.
62
+ }
63
+ };
64
+ }
65
+ const outgoing = (packet) => observer(packet, false);
66
+ const incoming = (packet) => {
67
+ try {
68
+ observer(packet, true)?.("transport_received");
69
+ }
70
+ catch {
71
+ // A malformed diagnostic observation must not interrupt Room's listener.
72
+ }
73
+ };
74
+ engine.voxevolvObserveRpcPacket = outgoing;
75
+ // Observe decoded receipt before Room starts ACK publication or the handler.
76
+ engine.prependListener("dataPacketReceived", incoming);
77
+ return () => {
78
+ if (engine.voxevolvObserveRpcPacket === outgoing)
79
+ delete engine.voxevolvObserveRpcPacket;
80
+ engine.off("dataPacketReceived", incoming);
81
+ streams.clear();
82
+ };
83
+ }
84
+ //# sourceMappingURL=rpc-transport-diagnostics.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rpc-transport-diagnostics.js","sourceRoot":"","sources":["../src/rpc-transport-diagnostics.ts"],"names":[],"mappings":"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"}
@@ -16249,6 +16249,7 @@ class WebSocketStream {
16249
16249
  reason = _ref3.reason;
16250
16250
  resolve({
16251
16251
  closeCode: code,
16252
+ wasClean: _ref3.wasClean,
16252
16253
  reason
16253
16254
  });
16254
16255
  ws.removeEventListener('error', rejectHandler);
@@ -16428,6 +16429,13 @@ class SignalClient {
16428
16429
  try {
16429
16430
  this.ws.closed.then(closeInfo => {
16430
16431
  var _a;
16432
+ if (this.state === SignalConnectionState.CONNECTED) {
16433
+ try { this.voxevolvObserveConnection?.({
16434
+ reason: "websocket_closed",
16435
+ ws_close_code: closeInfo.closeCode ?? closeInfo.code,
16436
+ ws_close_clean: closeInfo.wasClean
16437
+ }); } catch {}
16438
+ }
16431
16439
  if (this.isEstablishingConnection) {
16432
16440
  reject(ConnectionError.internal("Websocket got closed during a (re)connection attempt: ".concat(closeInfo.reason)));
16433
16441
  }
@@ -16444,6 +16452,7 @@ class SignalClient {
16444
16452
  }
16445
16453
  return;
16446
16454
  }).catch(reason => {
16455
+ try { this.voxevolvObserveConnection?.({ reason: "websocket_error" }); } catch {}
16447
16456
  if (this.isEstablishingConnection) {
16448
16457
  reject(ConnectionError.internal("Websocket error during a (re)connection attempt: ".concat(reason)));
16449
16458
  }
@@ -16918,6 +16927,11 @@ class SignalClient {
16918
16927
  handleOnClose(reason) {
16919
16928
  return __awaiter(this, void 0, void 0, function* () {
16920
16929
  if (this.state === SignalConnectionState.DISCONNECTED) return;
16930
+ try { this.voxevolvObserveConnection?.({
16931
+ reason: reason === "ping timeout" ? "signal_ping_timeout" : "signal_closed",
16932
+ signal_timeout_ms: this.pingTimeoutDuration * 1000,
16933
+ signal_idle_ms: this.voxevolvLastSignalAt === undefined ? undefined : performance.now() - this.voxevolvLastSignalAt
16934
+ }); } catch {}
16921
16935
  const onCloseCallback = this.onClose;
16922
16936
  yield this.close(undefined, reason);
16923
16937
  this.log.info("websocket connection closed: ".concat(reason), {
@@ -16938,6 +16952,7 @@ class SignalClient {
16938
16952
  * Call this after receiving a pong message
16939
16953
  */
16940
16954
  resetPingTimeout() {
16955
+ this.voxevolvLastSignalAt = performance.now();
16941
16956
  this.clearPingTimeout();
16942
16957
  if (!this.pingTimeoutDuration) {
16943
16958
  this.log.warn('ping timeout duration not set');
@@ -21262,6 +21277,9 @@ class RTCEngine extends eventsExports.EventEmitter {
21262
21277
  if (this._isClosed) {
21263
21278
  return;
21264
21279
  }
21280
+ try { this.voxevolvObserveConnection?.({
21281
+ reason: "livekit_reconnect_requested", reconnect_reason: disconnectReason ?? 0
21282
+ }); } catch {}
21265
21283
  this.log.warn("".concat(connection, " disconnected"));
21266
21284
  if (this.reconnectAttempts === 0) {
21267
21285
  // only reset start time on the first try
@@ -22342,6 +22360,11 @@ class RTCEngine extends eventsExports.EventEmitter {
22342
22360
  sendDataPacket(packet, kind, signal) {
22343
22361
  return __awaiter(this, void 0, void 0, function* () {
22344
22362
  var _a, _b;
22363
+ let rpcObserver;
22364
+ try { rpcObserver = this.voxevolvObserveRpcPacket?.(packet); } catch {}
22365
+ const observeRpc = (stage) => { try { rpcObserver?.(stage); } catch {} };
22366
+ observeRpc("publish_started");
22367
+ try {
22345
22368
  signal?.throwIfAborted();
22346
22369
  // make sure we do have a data connection
22347
22370
  yield this.ensurePublisherConnected(kind);
@@ -22391,13 +22414,21 @@ class RTCEngine extends eventsExports.EventEmitter {
22391
22414
  sequence: packet.sequence
22392
22415
  });
22393
22416
  if (this.attemptingReconnect) {
22417
+ observeRpc("reconnect_buffered");
22394
22418
  return;
22395
22419
  }
22396
22420
  dc.send(msg);
22421
+ observeRpc("channel_send");
22422
+ } else {
22423
+ observeRpc("channel_unavailable");
22397
22424
  }
22398
22425
  this.updateAndEmitDCBufferStatus(kind);
22399
22426
  break;
22400
22427
  }
22428
+ } catch (error) {
22429
+ observeRpc("publish_failed");
22430
+ throw error;
22431
+ }
22401
22432
  });
22402
22433
  }
22403
22434
  /* @internal */
@@ -30804,6 +30835,7 @@ class Room extends eventsExports.EventEmitter {
30804
30835
  }
30805
30836
  this.engine = new RTCEngine(this.options);
30806
30837
  this.engine.e2eeManager = this.e2eeManager;
30838
+ try { this.voxevolvObserveEngine?.(); } catch {}
30807
30839
  this.engine.on(EngineEvent.ParticipantUpdate, this.handleParticipantUpdates).on(EngineEvent.RoomUpdate, this.handleRoomUpdate).on(EngineEvent.SpeakersChanged, this.handleSpeakersChanged).on(EngineEvent.StreamStateChanged, this.handleStreamStateUpdate).on(EngineEvent.ConnectionQualityUpdate, this.handleConnectionQualityUpdate).on(EngineEvent.SubscriptionError, this.handleSubscriptionError).on(EngineEvent.SubscriptionPermissionUpdate, this.handleSubscriptionPermissionUpdate).on(EngineEvent.MediaTrackAdded, (mediaTrack, stream, receiver) => {
30808
30840
  this.onTrackAdded(mediaTrack, stream, receiver);
30809
30841
  }).on(EngineEvent.Disconnected, reason => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@voxevolv/client",
3
- "version": "0.3.15",
3
+ "version": "0.3.17",
4
4
  "description": "Browser SDK for VoxEvolv multimodal realtime sessions",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -42,14 +42,14 @@
42
42
  "scripts": {
43
43
  "build": "tsc -p tsconfig.json && node scripts/build-browser.mjs",
44
44
  "typecheck": "tsc -p tsconfig.json --noEmit",
45
- "test": "npm run build && node scripts/protocol-smoke.mjs && node --test scripts/context-delivery.test.mjs scripts/context-cancellation.test.mjs scripts/diagnostic-delivery.test.mjs scripts/startup-recovery.test.mjs scripts/connection-lifecycle.test.mjs scripts/audio-recovery.test.mjs scripts/recovery-progress.test.mjs scripts/reliable-sequence.test.mjs && node scripts/transcript-smoke.mjs",
45
+ "test": "npm run build && node scripts/protocol-smoke.mjs && node --test scripts/context-delivery.test.mjs scripts/context-cancellation.test.mjs scripts/diagnostic-delivery.test.mjs scripts/connection-diagnostics.test.mjs scripts/presentations.test.mjs scripts/startup-recovery.test.mjs scripts/connection-lifecycle.test.mjs scripts/audio-recovery.test.mjs scripts/recovery-progress.test.mjs scripts/reliable-sequence.test.mjs && node scripts/transcript-smoke.mjs",
46
46
  "pack:check": "npm run build && npm pack --dry-run"
47
47
  },
48
48
  "dependencies": {
49
49
  "livekit-client": "2.20.0"
50
50
  },
51
51
  "devDependencies": {
52
- "esbuild": "0.27.0",
52
+ "esbuild": "0.28.2",
53
53
  "typescript": "7.0.2"
54
54
  }
55
55
  }