@furious.luke/argus-js 0.5.3 → 0.5.5
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/README.md +22 -7
- package/dist/index.cjs +165 -51
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +35 -4
- package/dist/index.d.ts +35 -4
- package/dist/index.js +165 -51
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.cts
CHANGED
|
@@ -102,6 +102,12 @@ type SignalMessage = {
|
|
|
102
102
|
turn_username?: string;
|
|
103
103
|
turn_credential?: string;
|
|
104
104
|
read_token?: string;
|
|
105
|
+
} | {
|
|
106
|
+
type: "placement_redirect";
|
|
107
|
+
gateway_url: string;
|
|
108
|
+
} | {
|
|
109
|
+
type: "unavailable";
|
|
110
|
+
retry_after_ms?: number;
|
|
105
111
|
};
|
|
106
112
|
/**
|
|
107
113
|
* Callbacks emitted by the Publisher during its lifecycle.
|
|
@@ -119,6 +125,8 @@ interface PublisherCallbacks {
|
|
|
119
125
|
onRecoveryRequired?: (event: PublisherRecoveryEvent) => void;
|
|
120
126
|
/** Called when paced assistant text arrives alongside synthesized speech. */
|
|
121
127
|
onAssistantText?: (event: AssistantTextEvent) => void;
|
|
128
|
+
/** Called on the same ordered data channel after an utterance's last caption. */
|
|
129
|
+
onAssistantTextFinished?: (event: AssistantTextFinishedEvent) => void;
|
|
122
130
|
/** Called when the server accepts or rejects typed user input. */
|
|
123
131
|
onUserTextResult?: (event: UserTextResultEvent) => void;
|
|
124
132
|
/** Called once the explicitly requested outbound speech track arrives. */
|
|
@@ -128,6 +136,9 @@ interface AssistantTextEvent {
|
|
|
128
136
|
utteranceId: string;
|
|
129
137
|
text: string;
|
|
130
138
|
}
|
|
139
|
+
interface AssistantTextFinishedEvent {
|
|
140
|
+
utteranceId: string;
|
|
141
|
+
}
|
|
131
142
|
interface UserTextResultEvent {
|
|
132
143
|
messageId: string;
|
|
133
144
|
accepted: boolean;
|
|
@@ -160,7 +171,12 @@ interface GatewayReadyInfo {
|
|
|
160
171
|
* Options for publishing a media stream.
|
|
161
172
|
*/
|
|
162
173
|
interface PublisherOptions {
|
|
163
|
-
/**
|
|
174
|
+
/**
|
|
175
|
+
* Gateway WebSocket URLs returned by POST /api/streams `gateway_urls`. All are
|
|
176
|
+
* opened at once; the region whose `accepted` returns first is selected on
|
|
177
|
+
* network path, and only that region places the stream. The rest are held as
|
|
178
|
+
* standbys the publisher fails over to.
|
|
179
|
+
*/
|
|
164
180
|
gatewayURLs: string[];
|
|
165
181
|
/** The short-lived join token from POST /api/streams. */
|
|
166
182
|
token: string;
|
|
@@ -182,11 +198,26 @@ interface PublisherOptions {
|
|
|
182
198
|
*/
|
|
183
199
|
turnTransportPolicy?: TurnTransportPolicy;
|
|
184
200
|
/**
|
|
185
|
-
* Overall deadline for the initial accepted/proceed/ready gateway race
|
|
186
|
-
*
|
|
187
|
-
*
|
|
201
|
+
* Overall deadline for the initial accepted/proceed/ready gateway race,
|
|
202
|
+
* spanning selection, placement, and any failovers. Sockets that have not sent
|
|
203
|
+
* `accepted` are replaced after three seconds within this deadline. Defaults to
|
|
204
|
+
* 20 seconds.
|
|
188
205
|
*/
|
|
189
206
|
gatewayHandshakeTimeoutMs?: number;
|
|
207
|
+
/**
|
|
208
|
+
* How long the selected region has to return `ready` before the publisher
|
|
209
|
+
* abandons it and fails over to the next-fastest acknowledgement. This is a
|
|
210
|
+
* backstop for a region whose socket stays open but silent (a hung placement);
|
|
211
|
+
* a socket that closes or errors fails over immediately regardless. It is
|
|
212
|
+
* deliberately generous — placement includes the selected region's own
|
|
213
|
+
* control-plane round-trips, and a short deadline would abandon exactly the
|
|
214
|
+
* user-close-but-control-plane-distant regions this race is meant to prefer.
|
|
215
|
+
* Defaults to 8 seconds and is capped at 20 seconds: the gateway reaps a
|
|
216
|
+
* standby socket that has been accepted but not yet told to proceed, so the
|
|
217
|
+
* failover window must stay below that deadline or standbys would disappear
|
|
218
|
+
* before the browser fails over to them.
|
|
219
|
+
*/
|
|
220
|
+
gatewayFailoverTimeoutMs?: number;
|
|
190
221
|
/** Deadline after the initial offer for WebRTC to reach connected. Defaults to 30 seconds. */
|
|
191
222
|
peerConnectionTimeoutMs?: number;
|
|
192
223
|
/**
|
package/dist/index.d.ts
CHANGED
|
@@ -102,6 +102,12 @@ type SignalMessage = {
|
|
|
102
102
|
turn_username?: string;
|
|
103
103
|
turn_credential?: string;
|
|
104
104
|
read_token?: string;
|
|
105
|
+
} | {
|
|
106
|
+
type: "placement_redirect";
|
|
107
|
+
gateway_url: string;
|
|
108
|
+
} | {
|
|
109
|
+
type: "unavailable";
|
|
110
|
+
retry_after_ms?: number;
|
|
105
111
|
};
|
|
106
112
|
/**
|
|
107
113
|
* Callbacks emitted by the Publisher during its lifecycle.
|
|
@@ -119,6 +125,8 @@ interface PublisherCallbacks {
|
|
|
119
125
|
onRecoveryRequired?: (event: PublisherRecoveryEvent) => void;
|
|
120
126
|
/** Called when paced assistant text arrives alongside synthesized speech. */
|
|
121
127
|
onAssistantText?: (event: AssistantTextEvent) => void;
|
|
128
|
+
/** Called on the same ordered data channel after an utterance's last caption. */
|
|
129
|
+
onAssistantTextFinished?: (event: AssistantTextFinishedEvent) => void;
|
|
122
130
|
/** Called when the server accepts or rejects typed user input. */
|
|
123
131
|
onUserTextResult?: (event: UserTextResultEvent) => void;
|
|
124
132
|
/** Called once the explicitly requested outbound speech track arrives. */
|
|
@@ -128,6 +136,9 @@ interface AssistantTextEvent {
|
|
|
128
136
|
utteranceId: string;
|
|
129
137
|
text: string;
|
|
130
138
|
}
|
|
139
|
+
interface AssistantTextFinishedEvent {
|
|
140
|
+
utteranceId: string;
|
|
141
|
+
}
|
|
131
142
|
interface UserTextResultEvent {
|
|
132
143
|
messageId: string;
|
|
133
144
|
accepted: boolean;
|
|
@@ -160,7 +171,12 @@ interface GatewayReadyInfo {
|
|
|
160
171
|
* Options for publishing a media stream.
|
|
161
172
|
*/
|
|
162
173
|
interface PublisherOptions {
|
|
163
|
-
/**
|
|
174
|
+
/**
|
|
175
|
+
* Gateway WebSocket URLs returned by POST /api/streams `gateway_urls`. All are
|
|
176
|
+
* opened at once; the region whose `accepted` returns first is selected on
|
|
177
|
+
* network path, and only that region places the stream. The rest are held as
|
|
178
|
+
* standbys the publisher fails over to.
|
|
179
|
+
*/
|
|
164
180
|
gatewayURLs: string[];
|
|
165
181
|
/** The short-lived join token from POST /api/streams. */
|
|
166
182
|
token: string;
|
|
@@ -182,11 +198,26 @@ interface PublisherOptions {
|
|
|
182
198
|
*/
|
|
183
199
|
turnTransportPolicy?: TurnTransportPolicy;
|
|
184
200
|
/**
|
|
185
|
-
* Overall deadline for the initial accepted/proceed/ready gateway race
|
|
186
|
-
*
|
|
187
|
-
*
|
|
201
|
+
* Overall deadline for the initial accepted/proceed/ready gateway race,
|
|
202
|
+
* spanning selection, placement, and any failovers. Sockets that have not sent
|
|
203
|
+
* `accepted` are replaced after three seconds within this deadline. Defaults to
|
|
204
|
+
* 20 seconds.
|
|
188
205
|
*/
|
|
189
206
|
gatewayHandshakeTimeoutMs?: number;
|
|
207
|
+
/**
|
|
208
|
+
* How long the selected region has to return `ready` before the publisher
|
|
209
|
+
* abandons it and fails over to the next-fastest acknowledgement. This is a
|
|
210
|
+
* backstop for a region whose socket stays open but silent (a hung placement);
|
|
211
|
+
* a socket that closes or errors fails over immediately regardless. It is
|
|
212
|
+
* deliberately generous — placement includes the selected region's own
|
|
213
|
+
* control-plane round-trips, and a short deadline would abandon exactly the
|
|
214
|
+
* user-close-but-control-plane-distant regions this race is meant to prefer.
|
|
215
|
+
* Defaults to 8 seconds and is capped at 20 seconds: the gateway reaps a
|
|
216
|
+
* standby socket that has been accepted but not yet told to proceed, so the
|
|
217
|
+
* failover window must stay below that deadline or standbys would disappear
|
|
218
|
+
* before the browser fails over to them.
|
|
219
|
+
*/
|
|
220
|
+
gatewayFailoverTimeoutMs?: number;
|
|
190
221
|
/** Deadline after the initial offer for WebRTC to reach connected. Defaults to 30 seconds. */
|
|
191
222
|
peerConnectionTimeoutMs?: number;
|
|
192
223
|
/**
|
package/dist/index.js
CHANGED
|
@@ -69,6 +69,12 @@ var defaultSignalingReconnectTimeoutMs = 2e4;
|
|
|
69
69
|
var defaultGatewayHandshakeTimeoutMs = 2e4;
|
|
70
70
|
var defaultPeerConnectionTimeoutMs = 3e4;
|
|
71
71
|
var initialGatewayAttemptTimeoutMs = 3e3;
|
|
72
|
+
var defaultGatewayFailoverTimeoutMs = 8e3;
|
|
73
|
+
var maxGatewayFailoverTimeoutMs = 2e4;
|
|
74
|
+
var defaultGatewayRetryBackoffMs = 3e3;
|
|
75
|
+
var minGatewayRetryBackoffMs = 250;
|
|
76
|
+
var maxGatewayRetryBackoffMs = 5e3;
|
|
77
|
+
var maxPlacementRedirects = 2;
|
|
72
78
|
var signalingResumeAttemptTimeoutMs = 3e3;
|
|
73
79
|
var signalingResumeMaxBackoffMs = 3e3;
|
|
74
80
|
var senderRestartPauseMs = 100;
|
|
@@ -522,6 +528,16 @@ var Publisher = class {
|
|
|
522
528
|
// -------------------------------------------------------------------------
|
|
523
529
|
// Private helpers
|
|
524
530
|
// -------------------------------------------------------------------------
|
|
531
|
+
// raceGateways opens every candidate gateway at once, then decides in two
|
|
532
|
+
// separate moments. SELECTION: the first socket to deliver `accepted` (a cheap,
|
|
533
|
+
// control-plane-free acknowledgement) is chosen on network path; the browser
|
|
534
|
+
// sends `proceed` on that one only and keeps the rest as standbys. PLACEMENT:
|
|
535
|
+
// the selected region does its control-plane work and returns `ready`. If the
|
|
536
|
+
// selection dies (socket close/error → immediately) or stalls past the failover
|
|
537
|
+
// deadline (a hung-but-open socket), the browser abandons it — closing the
|
|
538
|
+
// socket cancels that region's placement server-side — and selects the
|
|
539
|
+
// next-fastest standby. A `placement_redirect` points the browser at the region
|
|
540
|
+
// that already holds the stream so a mistimed failover self-heals.
|
|
525
541
|
raceGateways(signal) {
|
|
526
542
|
return new Promise((resolve, reject) => {
|
|
527
543
|
const { gatewayURLs, token } = this.opts;
|
|
@@ -531,43 +547,149 @@ var Publisher = class {
|
|
|
531
547
|
}
|
|
532
548
|
const sockets = [];
|
|
533
549
|
const attemptTimers = /* @__PURE__ */ new Map();
|
|
550
|
+
const reopenTimers = /* @__PURE__ */ new Set();
|
|
551
|
+
const standbys = [];
|
|
552
|
+
let selected = null;
|
|
553
|
+
let failoverTimer = null;
|
|
554
|
+
let redirects = 0;
|
|
534
555
|
let settled = false;
|
|
535
556
|
let timeoutTimer = null;
|
|
557
|
+
const failoverMs = Math.min(
|
|
558
|
+
maxGatewayFailoverTimeoutMs,
|
|
559
|
+
Math.max(0, this.opts.gatewayFailoverTimeoutMs ?? defaultGatewayFailoverTimeoutMs)
|
|
560
|
+
);
|
|
536
561
|
const clearTimeoutTimer = () => {
|
|
537
562
|
if (timeoutTimer !== null) clearTimeout(timeoutTimer);
|
|
538
563
|
timeoutTimer = null;
|
|
539
564
|
};
|
|
565
|
+
const clearFailoverTimer = () => {
|
|
566
|
+
if (failoverTimer !== null) clearTimeout(failoverTimer);
|
|
567
|
+
failoverTimer = null;
|
|
568
|
+
};
|
|
569
|
+
const clearReopenTimers = () => {
|
|
570
|
+
for (const timer of reopenTimers) clearTimeout(timer);
|
|
571
|
+
reopenTimers.clear();
|
|
572
|
+
};
|
|
540
573
|
const clearAttemptTimer = (socket) => {
|
|
541
574
|
const timer = attemptTimers.get(socket);
|
|
542
575
|
if (timer !== void 0) clearTimeout(timer);
|
|
543
576
|
attemptTimers.delete(socket);
|
|
544
577
|
};
|
|
578
|
+
const detach = (socket) => {
|
|
579
|
+
clearAttemptTimer(socket);
|
|
580
|
+
socket.onmessage = null;
|
|
581
|
+
socket.onerror = null;
|
|
582
|
+
socket.onclose = null;
|
|
583
|
+
};
|
|
584
|
+
const dropStandby = (socket) => {
|
|
585
|
+
const i = standbys.indexOf(socket);
|
|
586
|
+
if (i !== -1) standbys.splice(i, 1);
|
|
587
|
+
};
|
|
545
588
|
const closeAll = (except) => {
|
|
546
589
|
for (const s of sockets) {
|
|
547
|
-
clearAttemptTimer(s);
|
|
548
590
|
if (s !== except) {
|
|
549
|
-
s
|
|
550
|
-
s.onerror = null;
|
|
551
|
-
s.onclose = null;
|
|
591
|
+
detach(s);
|
|
552
592
|
s.close();
|
|
553
593
|
}
|
|
554
594
|
}
|
|
555
595
|
};
|
|
556
|
-
const
|
|
557
|
-
|
|
596
|
+
const win = (ws, readyInfo, gatewayURL) => {
|
|
597
|
+
settled = true;
|
|
598
|
+
clearTimeoutTimer();
|
|
599
|
+
clearFailoverTimer();
|
|
600
|
+
clearReopenTimers();
|
|
601
|
+
signal.removeEventListener("abort", abort);
|
|
602
|
+
closeAll(ws);
|
|
603
|
+
resolve({ ws, readyInfo, gatewayURL });
|
|
604
|
+
};
|
|
605
|
+
const fail = (err) => {
|
|
606
|
+
settled = true;
|
|
607
|
+
clearTimeoutTimer();
|
|
608
|
+
clearFailoverTimer();
|
|
609
|
+
clearReopenTimers();
|
|
610
|
+
signal.removeEventListener("abort", abort);
|
|
611
|
+
closeAll();
|
|
612
|
+
reject(err);
|
|
613
|
+
};
|
|
614
|
+
const checkExhausted = () => {
|
|
615
|
+
if (settled || selected !== null || standbys.length > 0 || reopenTimers.size > 0) return;
|
|
558
616
|
if (sockets.every((s) => s.readyState === WebSocket.CLOSED || s.readyState === WebSocket.CLOSING)) {
|
|
559
|
-
|
|
560
|
-
clearTimeoutTimer();
|
|
561
|
-
signal.removeEventListener("abort", abort);
|
|
562
|
-
reject(new Error("all gateways failed to connect"));
|
|
617
|
+
fail(new Error("all gateways failed to connect"));
|
|
563
618
|
}
|
|
564
619
|
};
|
|
565
|
-
const
|
|
620
|
+
const select = (ws) => {
|
|
621
|
+
selected = ws;
|
|
622
|
+
dropStandby(ws);
|
|
623
|
+
try {
|
|
624
|
+
ws.send(JSON.stringify({ type: "proceed" }));
|
|
625
|
+
} catch {
|
|
626
|
+
socketDown(ws);
|
|
627
|
+
return;
|
|
628
|
+
}
|
|
629
|
+
clearFailoverTimer();
|
|
630
|
+
failoverTimer = setTimeout(() => failover(ws), failoverMs);
|
|
631
|
+
};
|
|
632
|
+
const failover = (deadSocket) => {
|
|
633
|
+
if (settled || deadSocket !== selected) return;
|
|
634
|
+
clearFailoverTimer();
|
|
635
|
+
detach(deadSocket);
|
|
636
|
+
deadSocket.close();
|
|
637
|
+
selected = null;
|
|
638
|
+
const next = standbys.shift();
|
|
639
|
+
if (next) {
|
|
640
|
+
select(next);
|
|
641
|
+
} else {
|
|
642
|
+
checkExhausted();
|
|
643
|
+
}
|
|
644
|
+
};
|
|
645
|
+
const redirect = (gatewayURL) => {
|
|
566
646
|
if (settled) return;
|
|
567
|
-
|
|
568
|
-
|
|
647
|
+
if (redirects >= maxPlacementRedirects) {
|
|
648
|
+
fail(new Error("too many placement redirects"));
|
|
649
|
+
return;
|
|
650
|
+
}
|
|
651
|
+
redirects++;
|
|
652
|
+
clearFailoverTimer();
|
|
569
653
|
closeAll();
|
|
570
|
-
|
|
654
|
+
standbys.length = 0;
|
|
655
|
+
selected = null;
|
|
656
|
+
try {
|
|
657
|
+
openGateway(gatewayURL);
|
|
658
|
+
} catch (err) {
|
|
659
|
+
fail(err instanceof Error ? err : new Error(String(err)));
|
|
660
|
+
}
|
|
661
|
+
};
|
|
662
|
+
const retryUnavailable = (ws, gatewayURL, retryAfterMs) => {
|
|
663
|
+
detach(ws);
|
|
664
|
+
ws.close();
|
|
665
|
+
const delay = Math.min(
|
|
666
|
+
maxGatewayRetryBackoffMs,
|
|
667
|
+
Math.max(minGatewayRetryBackoffMs, retryAfterMs ?? defaultGatewayRetryBackoffMs)
|
|
668
|
+
);
|
|
669
|
+
const timer = setTimeout(() => {
|
|
670
|
+
reopenTimers.delete(timer);
|
|
671
|
+
if (settled) return;
|
|
672
|
+
try {
|
|
673
|
+
openGateway(gatewayURL);
|
|
674
|
+
} catch (err) {
|
|
675
|
+
fail(err instanceof Error ? err : new Error(String(err)));
|
|
676
|
+
}
|
|
677
|
+
}, delay);
|
|
678
|
+
reopenTimers.add(timer);
|
|
679
|
+
};
|
|
680
|
+
const socketDown = (ws) => {
|
|
681
|
+
if (settled) return;
|
|
682
|
+
clearAttemptTimer(ws);
|
|
683
|
+
dropStandby(ws);
|
|
684
|
+
if (ws === selected) {
|
|
685
|
+
failover(ws);
|
|
686
|
+
} else {
|
|
687
|
+
checkExhausted();
|
|
688
|
+
}
|
|
689
|
+
};
|
|
690
|
+
const abort = () => {
|
|
691
|
+
if (settled) return;
|
|
692
|
+
fail(new PublisherStoppedError("publisher stopped"));
|
|
571
693
|
};
|
|
572
694
|
if (signal.aborted) {
|
|
573
695
|
abort();
|
|
@@ -580,10 +702,7 @@ var Publisher = class {
|
|
|
580
702
|
);
|
|
581
703
|
timeoutTimer = setTimeout(() => {
|
|
582
704
|
if (settled) return;
|
|
583
|
-
|
|
584
|
-
signal.removeEventListener("abort", abort);
|
|
585
|
-
closeAll();
|
|
586
|
-
reject(new Error(`gateway handshake timed out after ${timeoutMs}ms`));
|
|
705
|
+
fail(new Error(`gateway handshake timed out after ${timeoutMs}ms`));
|
|
587
706
|
}, timeoutMs);
|
|
588
707
|
const openGateway = (gatewayURL) => {
|
|
589
708
|
if (settled) return;
|
|
@@ -595,58 +714,51 @@ var Publisher = class {
|
|
|
595
714
|
const attemptTimer = setTimeout(() => {
|
|
596
715
|
attemptTimers.delete(ws);
|
|
597
716
|
if (settled || accepted) return;
|
|
598
|
-
ws
|
|
599
|
-
ws.onerror = null;
|
|
600
|
-
ws.onclose = null;
|
|
717
|
+
detach(ws);
|
|
601
718
|
ws.close();
|
|
602
719
|
try {
|
|
603
720
|
openGateway(gatewayURL);
|
|
604
721
|
} catch (err) {
|
|
605
|
-
|
|
606
|
-
clearTimeoutTimer();
|
|
607
|
-
signal.removeEventListener("abort", abort);
|
|
608
|
-
closeAll();
|
|
609
|
-
reject(err);
|
|
722
|
+
fail(err instanceof Error ? err : new Error(String(err)));
|
|
610
723
|
}
|
|
611
724
|
}, initialGatewayAttemptTimeoutMs);
|
|
612
725
|
attemptTimers.set(ws, attemptTimer);
|
|
613
726
|
ws.onmessage = (ev) => {
|
|
614
727
|
if (settled) return;
|
|
728
|
+
let msg;
|
|
615
729
|
try {
|
|
616
|
-
|
|
617
|
-
if (!accepted && msg.type === "accepted") {
|
|
618
|
-
accepted = true;
|
|
619
|
-
clearAttemptTimer(ws);
|
|
620
|
-
ws.send(JSON.stringify({ type: "proceed" }));
|
|
621
|
-
} else if (accepted && msg.type === "ready") {
|
|
622
|
-
settled = true;
|
|
623
|
-
clearTimeoutTimer();
|
|
624
|
-
signal.removeEventListener("abort", abort);
|
|
625
|
-
closeAll(ws);
|
|
626
|
-
resolve({ ws, readyInfo: msg, gatewayURL });
|
|
627
|
-
}
|
|
730
|
+
msg = JSON.parse(ev.data);
|
|
628
731
|
} catch {
|
|
732
|
+
return;
|
|
733
|
+
}
|
|
734
|
+
if (!accepted) {
|
|
735
|
+
if (msg.type === "unavailable") {
|
|
736
|
+
retryUnavailable(ws, gatewayURL, msg.retry_after_ms);
|
|
737
|
+
return;
|
|
738
|
+
}
|
|
739
|
+
if (msg.type !== "accepted") return;
|
|
740
|
+
accepted = true;
|
|
741
|
+
clearAttemptTimer(ws);
|
|
742
|
+
if (selected === null) select(ws);
|
|
743
|
+
else standbys.push(ws);
|
|
744
|
+
return;
|
|
745
|
+
}
|
|
746
|
+
if (ws !== selected) return;
|
|
747
|
+
if (msg.type === "ready") {
|
|
748
|
+
win(ws, msg, gatewayURL);
|
|
749
|
+
} else if (msg.type === "placement_redirect" && msg.gateway_url) {
|
|
750
|
+
redirect(msg.gateway_url);
|
|
629
751
|
}
|
|
630
752
|
};
|
|
631
|
-
ws.onerror = () =>
|
|
632
|
-
|
|
633
|
-
checkAllFailed();
|
|
634
|
-
};
|
|
635
|
-
ws.onclose = () => {
|
|
636
|
-
clearAttemptTimer(ws);
|
|
637
|
-
checkAllFailed();
|
|
638
|
-
};
|
|
753
|
+
ws.onerror = () => socketDown(ws);
|
|
754
|
+
ws.onclose = () => socketDown(ws);
|
|
639
755
|
};
|
|
640
756
|
try {
|
|
641
757
|
for (const gatewayURL of gatewayURLs) {
|
|
642
758
|
openGateway(gatewayURL);
|
|
643
759
|
}
|
|
644
760
|
} catch (err) {
|
|
645
|
-
|
|
646
|
-
clearTimeoutTimer();
|
|
647
|
-
signal.removeEventListener("abort", abort);
|
|
648
|
-
closeAll();
|
|
649
|
-
reject(err);
|
|
761
|
+
fail(err instanceof Error ? err : new Error(String(err)));
|
|
650
762
|
}
|
|
651
763
|
});
|
|
652
764
|
}
|
|
@@ -1167,6 +1279,8 @@ var Publisher = class {
|
|
|
1167
1279
|
const message = JSON.parse(data);
|
|
1168
1280
|
if (message.type === "assistant_text" && message.utterance_id && message.text) {
|
|
1169
1281
|
this.opts.callbacks?.onAssistantText?.({ utteranceId: message.utterance_id, text: message.text });
|
|
1282
|
+
} else if (message.type === "assistant_text_finished" && message.utterance_id) {
|
|
1283
|
+
this.opts.callbacks?.onAssistantTextFinished?.({ utteranceId: message.utterance_id });
|
|
1170
1284
|
} else if ((message.type === "user_text_accepted" || message.type === "user_text_rejected") && message.message_id) {
|
|
1171
1285
|
this.opts.callbacks?.onUserTextResult?.({
|
|
1172
1286
|
messageId: message.message_id,
|