@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.
- package/CHANGELOG.md +25 -0
- package/README.md +5 -1
- package/dist/browser/index.js +7 -7
- package/dist/browser/index.js.map +4 -4
- package/dist/browser/index.js.sha384 +1 -1
- package/dist/browser/manifest.json +1 -1
- package/dist/connection-diagnostics.d.ts +24 -0
- package/dist/connection-diagnostics.d.ts.map +1 -0
- package/dist/connection-diagnostics.js +155 -0
- package/dist/connection-diagnostics.js.map +1 -0
- package/dist/diagnostics.d.ts +19 -2
- package/dist/diagnostics.d.ts.map +1 -1
- package/dist/diagnostics.js +49 -8
- package/dist/diagnostics.js.map +1 -1
- package/dist/index.d.ts +12 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +149 -25
- package/dist/index.js.map +2 -2
- package/dist/presentations.d.ts +20 -0
- package/dist/presentations.d.ts.map +1 -0
- package/dist/presentations.js +91 -0
- package/dist/presentations.js.map +1 -0
- package/dist/rpc-transport-diagnostics.d.ts +6 -0
- package/dist/rpc-transport-diagnostics.d.ts.map +1 -0
- package/dist/rpc-transport-diagnostics.js +84 -0
- package/dist/rpc-transport-diagnostics.js.map +1 -0
- package/dist/vendor/livekit-client.esm.mjs +32 -0
- package/package.json +3 -3
|
@@ -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.
|
|
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.
|
|
52
|
+
"esbuild": "0.28.2",
|
|
53
53
|
"typescript": "7.0.2"
|
|
54
54
|
}
|
|
55
55
|
}
|