@pollen-robotics/reachy-mini-sdk 1.12.0 → 1.13.0-dev.0.main.55a68f6
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/APP_CREATION_GUIDE.md +16 -10
- package/dist/animation/safe-return.d.ts +6 -4
- package/dist/animation/safe-return.d.ts.map +1 -1
- package/dist/animation/safe-return.js +12 -4
- package/dist/animation/safe-return.js.map +1 -1
- package/dist/lib/app-dx.test.d.ts +2 -0
- package/dist/lib/app-dx.test.d.ts.map +1 -0
- package/dist/lib/app-dx.test.js +100 -0
- package/dist/lib/app-dx.test.js.map +1 -0
- package/dist/lib/math.d.ts +3 -2
- package/dist/lib/math.d.ts.map +1 -1
- package/dist/lib/math.js +6 -2
- package/dist/lib/math.js.map +1 -1
- package/dist/lib/reachy-mini.d.ts +24 -0
- package/dist/lib/reachy-mini.d.ts.map +1 -1
- package/dist/lib/reachy-mini.js +53 -0
- package/dist/lib/reachy-mini.js.map +1 -1
- package/dist/lib/types.d.ts +16 -3
- package/dist/lib/types.d.ts.map +1 -1
- package/dist/lib/version.d.ts +1 -1
- package/dist/lib/version.d.ts.map +1 -1
- package/dist/lib/version.js +1 -1
- package/dist/lib/version.js.map +1 -1
- package/dist/reachy-mini-sdk.d.ts +1 -1
- package/dist/reachy-mini-sdk.d.ts.map +1 -1
- package/dist/reachy-mini-sdk.js.map +1 -1
- package/host/README.md +5 -4
- package/host/dist/chunks/{centralRest-K3a9U_Sk.js → centralRest-Bf6BR9KA.js} +345 -310
- package/host/dist/chunks/{index-B79tSfbK.js → index-B5svCSPt.js} +1 -1
- package/host/dist/chunks/{mountHost-CMP4uYnZ.js → mountHost-B2Eh6aMK.js} +1 -1
- package/host/dist/entry/auto.js +2 -2
- package/host/dist/entry/embed.js +2 -2
- package/host/dist/index.js +3 -3
- package/package.json +1 -1
|
@@ -1,19 +1,19 @@
|
|
|
1
|
-
var
|
|
1
|
+
var ne = Object.defineProperty, se = (s, e, t) => e in s ? ne(s, e, { enumerable: !0, configurable: !0, writable: !0, value: t }) : s[e] = t, A = (s, e, t) => (se(s, typeof e != "symbol" ? e + "" : e, t), t), Z = "https://huggingface.co";
|
|
2
2
|
async function D(s, e) {
|
|
3
|
-
var t,
|
|
4
|
-
const
|
|
5
|
-
|
|
6
|
-
const i = [`URL: ${
|
|
7
|
-
if ((
|
|
3
|
+
var t, r;
|
|
4
|
+
const n = new ie(s.url, s.status, (t = s.headers.get("X-Request-Id")) != null ? t : void 0);
|
|
5
|
+
n.message = `Api error with status ${n.statusCode}`;
|
|
6
|
+
const i = [`URL: ${n.url}`, n.requestId ? `Request ID: ${n.requestId}` : void 0].filter(Boolean).join(". ");
|
|
7
|
+
if ((r = s.headers.get("Content-Type")) != null && r.startsWith("application/json")) {
|
|
8
8
|
const o = await s.json();
|
|
9
|
-
|
|
9
|
+
n.message = o.error || o.message || n.message, n.data = o;
|
|
10
10
|
} else
|
|
11
|
-
|
|
12
|
-
throw
|
|
11
|
+
n.data = { message: await s.text() };
|
|
12
|
+
throw n.message += `. ${i}`, n;
|
|
13
13
|
}
|
|
14
14
|
var ie = class extends Error {
|
|
15
|
-
constructor(s, e, t,
|
|
16
|
-
super(
|
|
15
|
+
constructor(s, e, t, r) {
|
|
16
|
+
super(r), A(this, "statusCode"), A(this, "url"), A(this, "requestId"), A(this, "data"), this.statusCode = e, this.requestId = t, this.url = s;
|
|
17
17
|
}
|
|
18
18
|
};
|
|
19
19
|
new Promise((s) => {
|
|
@@ -32,10 +32,10 @@ async function B(s) {
|
|
|
32
32
|
var e, t;
|
|
33
33
|
if (typeof window > "u")
|
|
34
34
|
throw new Error("oauthHandleRedirect is only available in the browser");
|
|
35
|
-
const
|
|
36
|
-
if (
|
|
37
|
-
throw new Error(`${
|
|
38
|
-
const o =
|
|
35
|
+
const r = new URLSearchParams(window.location.search), [n, i] = [r.get("error"), r.get("error_description")];
|
|
36
|
+
if (n)
|
|
37
|
+
throw new Error(`${n}: ${i}`);
|
|
38
|
+
const o = r.get("code"), a = localStorage.getItem("huggingface.co:oauth:nonce");
|
|
39
39
|
if (!o)
|
|
40
40
|
throw new Error("Missing oauth code from query parameters in redirected URL");
|
|
41
41
|
if (!a)
|
|
@@ -43,7 +43,7 @@ async function B(s) {
|
|
|
43
43
|
const c = localStorage.getItem("huggingface.co:oauth:code_verifier");
|
|
44
44
|
if (!c)
|
|
45
45
|
throw new Error("Missing oauth code_verifier from localStorage");
|
|
46
|
-
const d =
|
|
46
|
+
const d = r.get("state");
|
|
47
47
|
if (!d)
|
|
48
48
|
throw new Error("Missing oauth state from query parameters in redirected URL");
|
|
49
49
|
let u;
|
|
@@ -121,7 +121,7 @@ async function ce(s) {
|
|
|
121
121
|
var e, t;
|
|
122
122
|
if (typeof window > "u")
|
|
123
123
|
throw new Error("oauthLogin is only available in the browser");
|
|
124
|
-
const
|
|
124
|
+
const r = s?.hubUrl || Z, n = `${new URL(r).origin}/.well-known/openid-configuration`, i = await fetch(n, {
|
|
125
125
|
headers: {
|
|
126
126
|
Accept: "application/json"
|
|
127
127
|
}
|
|
@@ -166,7 +166,7 @@ function de() {
|
|
|
166
166
|
return "info";
|
|
167
167
|
}
|
|
168
168
|
let C = de();
|
|
169
|
-
function
|
|
169
|
+
function $(s) {
|
|
170
170
|
const e = `[reachy:${s}]`;
|
|
171
171
|
return {
|
|
172
172
|
debug: (...t) => {
|
|
@@ -183,11 +183,11 @@ function O(s) {
|
|
|
183
183
|
}
|
|
184
184
|
};
|
|
185
185
|
}
|
|
186
|
-
function
|
|
186
|
+
function k(s) {
|
|
187
187
|
return s * Math.PI / 180;
|
|
188
188
|
}
|
|
189
189
|
function ue(s, e, t) {
|
|
190
|
-
const
|
|
190
|
+
const r = k(s), n = k(e), i = k(t), o = Math.cos(i), a = Math.sin(i), c = Math.cos(n), d = Math.sin(n), u = Math.cos(r), l = Math.sin(r);
|
|
191
191
|
return [
|
|
192
192
|
[o * c, o * d * l - a * u, o * d * u + a * l, 0],
|
|
193
193
|
[a * c, a * d * l + o * u, a * d * u - o * l, 0],
|
|
@@ -205,11 +205,11 @@ class _e {
|
|
|
205
205
|
*/
|
|
206
206
|
accept(e) {
|
|
207
207
|
if (e.type !== "message_chunk") return e;
|
|
208
|
-
const { id: t, index:
|
|
209
|
-
if (typeof t != "string" || typeof
|
|
208
|
+
const { id: t, index: r, count: n, data: i } = e;
|
|
209
|
+
if (typeof t != "string" || typeof r != "number" || typeof n != "number" || typeof i != "string" || n < 1 || n > he)
|
|
210
210
|
return null;
|
|
211
211
|
let o = this._partials.get(t);
|
|
212
|
-
return
|
|
212
|
+
return r === 0 && (o = [], this._partials.set(t, o)), !o || r !== o.length ? (this._partials.delete(t), null) : (o.push(i), o.length < n ? null : (this._partials.delete(t), JSON.parse(o.join(""))));
|
|
213
213
|
}
|
|
214
214
|
}
|
|
215
215
|
const ee = 4e3;
|
|
@@ -232,12 +232,12 @@ class pe {
|
|
|
232
232
|
* so its caller doesn't hang forever.
|
|
233
233
|
*/
|
|
234
234
|
slotRoundtrip(e, t) {
|
|
235
|
-
return new Promise((
|
|
236
|
-
const
|
|
237
|
-
|
|
235
|
+
return new Promise((r) => {
|
|
236
|
+
const n = this._replySlots.get(e);
|
|
237
|
+
n && n(null);
|
|
238
238
|
let i;
|
|
239
239
|
const o = (a) => {
|
|
240
|
-
i !== void 0 && (clearTimeout(i), i = void 0), this._replySlots.get(e) === o && this._replySlots.delete(e),
|
|
240
|
+
i !== void 0 && (clearTimeout(i), i = void 0), this._replySlots.get(e) === o && this._replySlots.delete(e), r(a);
|
|
241
241
|
};
|
|
242
242
|
this._replySlots.set(e, o), i = setTimeout(() => o(null), ee), t();
|
|
243
243
|
});
|
|
@@ -248,8 +248,8 @@ class pe {
|
|
|
248
248
|
* branches use that to decide whether the message was theirs to swallow.
|
|
249
249
|
*/
|
|
250
250
|
settleReplySlot(e, t) {
|
|
251
|
-
const
|
|
252
|
-
return
|
|
251
|
+
const r = this._replySlots.get(e);
|
|
252
|
+
return r ? (r(t), !0) : !1;
|
|
253
253
|
}
|
|
254
254
|
/* ─── JSON-RPC ───────────────────────────────────────────────────── */
|
|
255
255
|
/**
|
|
@@ -258,13 +258,13 @@ class pe {
|
|
|
258
258
|
* promise then rejects immediately), and await the matching
|
|
259
259
|
* response; rejects on timeout. Same shape as `slotRoundtrip`.
|
|
260
260
|
*/
|
|
261
|
-
rpcRoundtrip(e, t,
|
|
262
|
-
const
|
|
263
|
-
return n
|
|
261
|
+
rpcRoundtrip(e, t, r) {
|
|
262
|
+
const n = `rpc-${++this._rpcCounter}`;
|
|
263
|
+
return r(n) ? new Promise((i, o) => {
|
|
264
264
|
const a = setTimeout(() => {
|
|
265
|
-
this._pendingRpc.delete(
|
|
265
|
+
this._pendingRpc.delete(n), o(new Error(`rpcCall(${e}) timed out after ${t}ms`));
|
|
266
266
|
}, t);
|
|
267
|
-
this._pendingRpc.set(
|
|
267
|
+
this._pendingRpc.set(n, { resolve: i, reject: o, timer: a });
|
|
268
268
|
}) : Promise.reject(new Error(`rpcCall(${e}): data channel not open`));
|
|
269
269
|
}
|
|
270
270
|
/**
|
|
@@ -279,8 +279,8 @@ class pe {
|
|
|
279
279
|
const t = this._pendingRpc.get(e.id);
|
|
280
280
|
if (!t) return !0;
|
|
281
281
|
if (this._pendingRpc.delete(e.id), clearTimeout(t.timer), "error" in e && e.error) {
|
|
282
|
-
const
|
|
283
|
-
|
|
282
|
+
const r = e.error, n = new Error(r.message ?? "rpc error");
|
|
283
|
+
n.reason = r.data?.reason, t.reject(n);
|
|
284
284
|
} else
|
|
285
285
|
t.resolve(e.result);
|
|
286
286
|
return !0;
|
|
@@ -288,13 +288,13 @@ class pe {
|
|
|
288
288
|
/* ─── Motion completions (wake_up / goto_sleep) ──────────────────── */
|
|
289
289
|
/** FIFO waiter for one `wake_up` / `goto_sleep` ack; rejects on timeout. */
|
|
290
290
|
awaitMotion(e, t) {
|
|
291
|
-
return new Promise((
|
|
291
|
+
return new Promise((r, n) => {
|
|
292
292
|
const i = {
|
|
293
|
-
resolve:
|
|
294
|
-
reject:
|
|
293
|
+
resolve: r,
|
|
294
|
+
reject: n,
|
|
295
295
|
timer: setTimeout(() => {
|
|
296
296
|
const o = this._pendingMotion[e], a = o.indexOf(i);
|
|
297
|
-
a !== -1 && o.splice(a, 1),
|
|
297
|
+
a !== -1 && o.splice(a, 1), n(new Error(`${e} timed out after ${t}ms`));
|
|
298
298
|
}, t)
|
|
299
299
|
};
|
|
300
300
|
this._pendingMotion[e].push(i);
|
|
@@ -307,28 +307,28 @@ class pe {
|
|
|
307
307
|
* message then falls through to the caller's other branches).
|
|
308
308
|
*/
|
|
309
309
|
settleMotion(e, t) {
|
|
310
|
-
const
|
|
311
|
-
if (t.completed === !0 &&
|
|
312
|
-
const
|
|
313
|
-
return clearTimeout(
|
|
310
|
+
const r = this._pendingMotion[e];
|
|
311
|
+
if (t.completed === !0 && r.length > 0) {
|
|
312
|
+
const n = r.shift();
|
|
313
|
+
return clearTimeout(n.timer), n.resolve(), !0;
|
|
314
314
|
}
|
|
315
|
-
if (t.error &&
|
|
316
|
-
const
|
|
317
|
-
return clearTimeout(
|
|
315
|
+
if (t.error && r.length > 0) {
|
|
316
|
+
const n = r.shift();
|
|
317
|
+
return clearTimeout(n.timer), n.reject(new Error(`${e}: ${t.error}`)), !0;
|
|
318
318
|
}
|
|
319
319
|
return !1;
|
|
320
320
|
}
|
|
321
321
|
/* ─── Broadcast waiters ──────────────────────────────────────────── */
|
|
322
322
|
/** Await the first broadcast matching `predicate`; rejects on timeout. */
|
|
323
|
-
awaitBroadcast(e, { timeoutMs: t = 5e3, debugLabel:
|
|
324
|
-
return new Promise((
|
|
323
|
+
awaitBroadcast(e, { timeoutMs: t = 5e3, debugLabel: r = "" } = {}) {
|
|
324
|
+
return new Promise((n, i) => {
|
|
325
325
|
const o = {
|
|
326
326
|
predicate: e,
|
|
327
|
-
resolve:
|
|
327
|
+
resolve: n,
|
|
328
328
|
reject: i,
|
|
329
329
|
timer: setTimeout(() => {
|
|
330
330
|
const a = this._broadcastWaiters.indexOf(o);
|
|
331
|
-
a !== -1 && this._broadcastWaiters.splice(a, 1), i(new P(`broadcast timeout (${t} ms): ${
|
|
331
|
+
a !== -1 && this._broadcastWaiters.splice(a, 1), i(new P(`broadcast timeout (${t} ms): ${r}`));
|
|
332
332
|
}, t)
|
|
333
333
|
};
|
|
334
334
|
this._broadcastWaiters.push(o);
|
|
@@ -340,9 +340,9 @@ class pe {
|
|
|
340
340
|
*/
|
|
341
341
|
matchBroadcast(e) {
|
|
342
342
|
for (let t = this._broadcastWaiters.length - 1; t >= 0; t--) {
|
|
343
|
-
const
|
|
344
|
-
if (
|
|
345
|
-
return this._broadcastWaiters.splice(t, 1), clearTimeout(
|
|
343
|
+
const r = this._broadcastWaiters[t];
|
|
344
|
+
if (r.predicate(e))
|
|
345
|
+
return this._broadcastWaiters.splice(t, 1), clearTimeout(r.timer), r.resolve(e), !0;
|
|
346
346
|
}
|
|
347
347
|
return !1;
|
|
348
348
|
}
|
|
@@ -362,10 +362,10 @@ class pe {
|
|
|
362
362
|
clearTimeout(t.timer), t.reject(e);
|
|
363
363
|
this._pendingRpc.clear();
|
|
364
364
|
for (const t of Object.keys(this._pendingMotion)) {
|
|
365
|
-
const
|
|
366
|
-
for (;
|
|
367
|
-
const
|
|
368
|
-
clearTimeout(
|
|
365
|
+
const r = this._pendingMotion[t];
|
|
366
|
+
for (; r.length; ) {
|
|
367
|
+
const n = r.shift();
|
|
368
|
+
clearTimeout(n.timer), n.reject(e);
|
|
369
369
|
}
|
|
370
370
|
}
|
|
371
371
|
for (const t of this._broadcastWaiters)
|
|
@@ -373,7 +373,7 @@ class pe {
|
|
|
373
373
|
this._broadcastWaiters = [];
|
|
374
374
|
}
|
|
375
375
|
}
|
|
376
|
-
const M =
|
|
376
|
+
const M = $("session"), q = 3e3, G = 1e3, fe = 6e4, V = [0, 2e3, 4e3, 8e3, 8e3], me = 15e3, J = 1e3, ge = 2500, we = 8e3;
|
|
377
377
|
class be {
|
|
378
378
|
_deps;
|
|
379
379
|
// ICE-blip debounce. All handler slots are scoped to the lifetime
|
|
@@ -470,16 +470,16 @@ class be {
|
|
|
470
470
|
}
|
|
471
471
|
this._iceGraceReason = t, this._iceGraceTimer = setTimeout(() => {
|
|
472
472
|
this._iceGraceTimer = null;
|
|
473
|
-
const
|
|
473
|
+
const r = this._iceGraceReason;
|
|
474
474
|
this._iceGraceReason = null;
|
|
475
|
-
const
|
|
476
|
-
if (!(
|
|
477
|
-
if (
|
|
475
|
+
const n = this._deps.iceState();
|
|
476
|
+
if (!(n === "connected" || n === "completed")) {
|
|
477
|
+
if (r === "disconnected" && n === "disconnected") {
|
|
478
478
|
if (this.maybeBeginRedial(`ICE stuck in 'disconnected' for > ${e}ms`)) return;
|
|
479
479
|
this._emitError(new Error(`ICE stuck in 'disconnected' for > ${e}ms`));
|
|
480
480
|
return;
|
|
481
481
|
}
|
|
482
|
-
if (
|
|
482
|
+
if (r === "failed" || n === "failed") {
|
|
483
483
|
const i = new Error("ICE connection failed");
|
|
484
484
|
if (this._deps.rejectPendingSession(i)) {
|
|
485
485
|
this._redialing || this._emitError(i);
|
|
@@ -502,19 +502,19 @@ class be {
|
|
|
502
502
|
if (this._pendingVisibilityHandler) return;
|
|
503
503
|
const e = Date.now(), t = () => {
|
|
504
504
|
if (typeof document < "u" && document.hidden || (document.removeEventListener("visibilitychange", t), this._pendingVisibilityHandler = null, !this._deps.hasPc())) return;
|
|
505
|
-
const
|
|
506
|
-
if (!(
|
|
505
|
+
const r = this._deps.iceState();
|
|
506
|
+
if (!(r === "connected" || r === "completed")) {
|
|
507
507
|
if (Date.now() - e > fe) {
|
|
508
|
-
const
|
|
509
|
-
if (this._deps.rejectPendingSession(
|
|
510
|
-
this._redialing || this._emitError(
|
|
508
|
+
const n = new Error("Session expired while tab was backgrounded");
|
|
509
|
+
if (this._deps.rejectPendingSession(n)) {
|
|
510
|
+
this._redialing || this._emitError(n);
|
|
511
511
|
return;
|
|
512
512
|
}
|
|
513
513
|
if (this.maybeBeginRedial("Session expired while tab was backgrounded")) return;
|
|
514
|
-
this._emitError(
|
|
514
|
+
this._emitError(n);
|
|
515
515
|
return;
|
|
516
516
|
}
|
|
517
|
-
if (
|
|
517
|
+
if (r === "failed") {
|
|
518
518
|
this._scheduleIceGrace(G, "failed");
|
|
519
519
|
return;
|
|
520
520
|
}
|
|
@@ -547,15 +547,15 @@ class be {
|
|
|
547
547
|
if (this._onlineHandler || typeof window > "u") return;
|
|
548
548
|
const e = () => this._deps.emit("networkOnline", {}), t = () => this._deps.emit("networkOffline", {});
|
|
549
549
|
window.addEventListener("online", e), window.addEventListener("offline", t), this._onlineHandler = e, this._offlineHandler = t;
|
|
550
|
-
const
|
|
551
|
-
if (
|
|
552
|
-
const
|
|
553
|
-
effectiveType:
|
|
554
|
-
downlink:
|
|
555
|
-
rtt:
|
|
556
|
-
saveData:
|
|
550
|
+
const r = navigator.connection;
|
|
551
|
+
if (r && typeof r.addEventListener == "function") {
|
|
552
|
+
const n = () => this._deps.emit("networkChange", {
|
|
553
|
+
effectiveType: r.effectiveType,
|
|
554
|
+
downlink: r.downlink,
|
|
555
|
+
rtt: r.rtt,
|
|
556
|
+
saveData: r.saveData
|
|
557
557
|
});
|
|
558
|
-
|
|
558
|
+
r.addEventListener("change", n), this._connectionChangeHandler = n;
|
|
559
559
|
}
|
|
560
560
|
}
|
|
561
561
|
/** Counterpart to `installNetworkListeners`. */
|
|
@@ -592,10 +592,10 @@ class be {
|
|
|
592
592
|
* which flip `_redialing` off via `cancelRedial`.
|
|
593
593
|
*/
|
|
594
594
|
async _runRedialLoop(e, t) {
|
|
595
|
-
const
|
|
595
|
+
const r = V.length;
|
|
596
596
|
this._deps.teardownForRedial();
|
|
597
|
-
for (let i = 1; i <=
|
|
598
|
-
if (!this._redialing || (this._deps.emit("sessionReconnecting", { attempt: i, maxAttempts:
|
|
597
|
+
for (let i = 1; i <= r; i++) {
|
|
598
|
+
if (!this._redialing || (this._deps.emit("sessionReconnecting", { attempt: i, maxAttempts: r, cause: t }), await this._redialSleep(V[i - 1]), !this._redialing)) return;
|
|
599
599
|
try {
|
|
600
600
|
if (this._deps.isSignalingDown() && await this._deps.reconnectSignaling(), !this._redialing || (await ye(
|
|
601
601
|
this._deps.dial(e),
|
|
@@ -606,15 +606,15 @@ class be {
|
|
|
606
606
|
return;
|
|
607
607
|
} catch (o) {
|
|
608
608
|
M.warn(
|
|
609
|
-
`auto-reconnect attempt ${i}/${
|
|
609
|
+
`auto-reconnect attempt ${i}/${r} failed:`,
|
|
610
610
|
o
|
|
611
611
|
), this._redialing && this._deps.teardownForRedial();
|
|
612
612
|
}
|
|
613
613
|
}
|
|
614
614
|
if (!this._redialing) return;
|
|
615
615
|
this._redialing = !1;
|
|
616
|
-
const
|
|
617
|
-
M.warn(
|
|
616
|
+
const n = `Auto-reconnect gave up after ${r} attempts (${t})`;
|
|
617
|
+
M.warn(n), this._deps.emit("sessionStopped", { reason: "reconnect_failed", message: n }), this._emitError(new Error(n));
|
|
618
618
|
}
|
|
619
619
|
/**
|
|
620
620
|
* Cancellable backoff sleep — `cancelRedial` wakes it immediately.
|
|
@@ -667,25 +667,25 @@ class be {
|
|
|
667
667
|
this._lastDcInboundAt = e, this._dcSilenceNudged = !1;
|
|
668
668
|
return;
|
|
669
669
|
}
|
|
670
|
-
const
|
|
671
|
-
if (
|
|
670
|
+
const r = e - this._lastDcInboundAt;
|
|
671
|
+
if (r < ge) return;
|
|
672
672
|
if (!this._dcSilenceNudged) {
|
|
673
673
|
this._dcSilenceNudged = !0, this._deps.nudgeState();
|
|
674
674
|
return;
|
|
675
675
|
}
|
|
676
|
-
if (
|
|
676
|
+
if (r < we) return;
|
|
677
677
|
this._dcSilenceNudged = !1;
|
|
678
|
-
const
|
|
679
|
-
this.maybeBeginRedial(
|
|
678
|
+
const n = `No data-channel traffic for ${r}ms`;
|
|
679
|
+
this.maybeBeginRedial(n) || (this.stopDcWatchdog(), this._emitError(new Error(n)));
|
|
680
680
|
}
|
|
681
681
|
}
|
|
682
682
|
function ye(s, e, t) {
|
|
683
683
|
return Promise.race([
|
|
684
684
|
s,
|
|
685
|
-
new Promise((
|
|
685
|
+
new Promise((r, n) => setTimeout(() => n(new Error(t)), e))
|
|
686
686
|
]);
|
|
687
687
|
}
|
|
688
|
-
const z = "0.0.0-managed-by-ci", Se =
|
|
688
|
+
const z = "0.0.0-managed-by-ci", Se = $("sdk");
|
|
689
689
|
function ve() {
|
|
690
690
|
if (typeof window > "u" || !window.location.hash) return;
|
|
691
691
|
const s = window.location.hash.startsWith("#") ? window.location.hash.slice(1) : window.location.hash;
|
|
@@ -697,9 +697,9 @@ function ve() {
|
|
|
697
697
|
}
|
|
698
698
|
const t = e.get("hf_token");
|
|
699
699
|
if (!t) return;
|
|
700
|
-
const
|
|
700
|
+
const r = e.get("hf_username") || "user", n = e.get("hf_token_expires"), i = n && !Number.isNaN(new Date(n).getTime()) ? n : new Date(Date.now() + 365 * 24 * 60 * 60 * 1e3).toISOString();
|
|
701
701
|
try {
|
|
702
|
-
sessionStorage.setItem("hf_token", t), sessionStorage.setItem("hf_username",
|
|
702
|
+
sessionStorage.setItem("hf_token", t), sessionStorage.setItem("hf_username", r), sessionStorage.setItem("hf_token_expires", i);
|
|
703
703
|
} catch (c) {
|
|
704
704
|
Se.warn("could not persist pre-seeded HF credentials:", c);
|
|
705
705
|
}
|
|
@@ -728,15 +728,15 @@ function Re() {
|
|
|
728
728
|
}
|
|
729
729
|
return null;
|
|
730
730
|
}
|
|
731
|
-
function
|
|
731
|
+
function ke(s) {
|
|
732
732
|
const e = s.split(`\r
|
|
733
733
|
`);
|
|
734
734
|
let t = !1;
|
|
735
|
-
for (const
|
|
736
|
-
if (
|
|
735
|
+
for (const r of e)
|
|
736
|
+
if (r.startsWith("m=audio") ? t = !0 : r.startsWith("m=") && (t = !1), t && r === "a=sendrecv") return !0;
|
|
737
737
|
return !1;
|
|
738
738
|
}
|
|
739
|
-
const j = "hf_token", x = "hf_username", F = "hf_token_expires", U = "hf_token_last_seen",
|
|
739
|
+
const j = "hf_token", x = "hf_username", F = "hf_token_expires", U = "hf_token_last_seen", Ie = 1440 * 60 * 1e3;
|
|
740
740
|
function Ee(s) {
|
|
741
741
|
try {
|
|
742
742
|
sessionStorage.setItem(j, s.token), sessionStorage.setItem(x, s.username), sessionStorage.setItem(F, s.expires), sessionStorage.setItem(U, (/* @__PURE__ */ new Date()).toISOString());
|
|
@@ -745,22 +745,22 @@ function Ee(s) {
|
|
|
745
745
|
}
|
|
746
746
|
function Te(s = Date.now()) {
|
|
747
747
|
try {
|
|
748
|
-
const e = sessionStorage.getItem(j), t = sessionStorage.getItem(x),
|
|
749
|
-
if (!e || !
|
|
750
|
-
if (new Date(
|
|
751
|
-
return
|
|
752
|
-
const
|
|
753
|
-
if (
|
|
754
|
-
const i = new Date(
|
|
755
|
-
if (!Number.isFinite(i) || s - i >
|
|
756
|
-
return
|
|
748
|
+
const e = sessionStorage.getItem(j), t = sessionStorage.getItem(x), r = sessionStorage.getItem(F);
|
|
749
|
+
if (!e || !r) return null;
|
|
750
|
+
if (new Date(r).getTime() <= s)
|
|
751
|
+
return O(), null;
|
|
752
|
+
const n = sessionStorage.getItem(U);
|
|
753
|
+
if (n !== null) {
|
|
754
|
+
const i = new Date(n).getTime();
|
|
755
|
+
if (!Number.isFinite(i) || s - i > Ie)
|
|
756
|
+
return O(), null;
|
|
757
757
|
}
|
|
758
|
-
return sessionStorage.setItem(U, new Date(s).toISOString()), { token: e, username: t ?? "", expires:
|
|
758
|
+
return sessionStorage.setItem(U, new Date(s).toISOString()), { token: e, username: t ?? "", expires: r };
|
|
759
759
|
} catch {
|
|
760
760
|
return null;
|
|
761
761
|
}
|
|
762
762
|
}
|
|
763
|
-
function
|
|
763
|
+
function O() {
|
|
764
764
|
try {
|
|
765
765
|
sessionStorage.removeItem(j), sessionStorage.removeItem(x), sessionStorage.removeItem(F), sessionStorage.removeItem(U);
|
|
766
766
|
} catch {
|
|
@@ -787,12 +787,12 @@ function De() {
|
|
|
787
787
|
function K() {
|
|
788
788
|
return "u" + Math.random().toString(36).slice(2, 11) + Date.now().toString(36);
|
|
789
789
|
}
|
|
790
|
-
function
|
|
790
|
+
function N(s) {
|
|
791
791
|
let e = "";
|
|
792
|
-
for (let
|
|
792
|
+
for (let r = 0; r < s.length; r += 32768)
|
|
793
793
|
e += String.fromCharCode.apply(
|
|
794
794
|
null,
|
|
795
|
-
Array.from(s.subarray(
|
|
795
|
+
Array.from(s.subarray(r, r + 32768))
|
|
796
796
|
);
|
|
797
797
|
return btoa(e);
|
|
798
798
|
}
|
|
@@ -800,7 +800,7 @@ async function Ue(s) {
|
|
|
800
800
|
const e = new TextEncoder().encode(s), t = await new Response(
|
|
801
801
|
new Blob([e]).stream().pipeThrough(new CompressionStream("gzip"))
|
|
802
802
|
).arrayBuffer();
|
|
803
|
-
return
|
|
803
|
+
return N(new Uint8Array(t));
|
|
804
804
|
}
|
|
805
805
|
function Y(s) {
|
|
806
806
|
const e = Math.round(Number(s) || 0);
|
|
@@ -829,7 +829,7 @@ function X(s) {
|
|
|
829
829
|
return "wav-base64";
|
|
830
830
|
}
|
|
831
831
|
}
|
|
832
|
-
const _ =
|
|
832
|
+
const _ = $("sdk"), Q = 750, Le = 5e3;
|
|
833
833
|
class Be extends EventTarget {
|
|
834
834
|
// ─── Config ──────────────────────────────────────────────────────────
|
|
835
835
|
_signalingUrl;
|
|
@@ -870,6 +870,8 @@ class Be extends EventTarget {
|
|
|
870
870
|
_pendingRemoteIce = [];
|
|
871
871
|
// ─── Audio ───────────────────────────────────────────────────────────
|
|
872
872
|
_micStream = null;
|
|
873
|
+
_robotAudioTrack = null;
|
|
874
|
+
_outgoingAudioTrack = null;
|
|
873
875
|
_micMuted = !0;
|
|
874
876
|
_audioMuted = !0;
|
|
875
877
|
_micSupported = !1;
|
|
@@ -913,8 +915,8 @@ class Be extends EventTarget {
|
|
|
913
915
|
selectedRobotId: () => this._selectedRobotId,
|
|
914
916
|
rejectPendingSession: (t) => {
|
|
915
917
|
if (!this._sessionReject) return !1;
|
|
916
|
-
const
|
|
917
|
-
return this._sessionResolve = null, this._sessionReject = null,
|
|
918
|
+
const r = this._sessionReject;
|
|
919
|
+
return this._sessionResolve = null, this._sessionReject = null, r(t), !0;
|
|
918
920
|
},
|
|
919
921
|
reconnectSignaling: () => this.connect(),
|
|
920
922
|
// The private dial skips the public startSession()'s
|
|
@@ -924,7 +926,7 @@ class Be extends EventTarget {
|
|
|
924
926
|
nudgeState: () => {
|
|
925
927
|
this.requestState();
|
|
926
928
|
},
|
|
927
|
-
emit: (t,
|
|
929
|
+
emit: (t, r) => this._emit(t, r)
|
|
928
930
|
}, { autoReconnect: e.autoReconnect !== !1 });
|
|
929
931
|
}
|
|
930
932
|
// ─── Read-only properties ────────────────────────────────────────────
|
|
@@ -967,6 +969,14 @@ class Be extends EventTarget {
|
|
|
967
969
|
get peerConnection() {
|
|
968
970
|
return this._pc;
|
|
969
971
|
}
|
|
972
|
+
/**
|
|
973
|
+
* The robot's microphone as a live audio track, or `null` until the
|
|
974
|
+
* session's audio arrives (see the `audioTrack` event). Feed it to Web
|
|
975
|
+
* Audio, `MediaRecorder` or `SpeechRecognition.start(track)`.
|
|
976
|
+
*/
|
|
977
|
+
get robotAudioTrack() {
|
|
978
|
+
return this._robotAudioTrack;
|
|
979
|
+
}
|
|
970
980
|
/**
|
|
971
981
|
* Build version of this SDK (npm package `version`), injected from
|
|
972
982
|
* package.json at build time. This is the JS SDK's OWN version and is
|
|
@@ -989,12 +999,12 @@ class Be extends EventTarget {
|
|
|
989
999
|
* SDK is already `connected` still triggers the auto-start.
|
|
990
1000
|
*/
|
|
991
1001
|
_maybeAutoStart() {
|
|
992
|
-
if (!this._autoStartFromUrl || this._autoStartAttempted || !this._preselectedRobotId || this._state !== "connected" || !this._robots.find((
|
|
1002
|
+
if (!this._autoStartFromUrl || this._autoStartAttempted || !this._preselectedRobotId || this._state !== "connected" || !this._robots.find((r) => r.id === this._preselectedRobotId)) return;
|
|
993
1003
|
this._autoStartAttempted = !0;
|
|
994
1004
|
const t = this._preselectedRobotId;
|
|
995
1005
|
setTimeout(() => {
|
|
996
|
-
this._state === "connected" && this.startSession(t).catch((
|
|
997
|
-
_.warn("autoStartFromUrl: startSession rejected:",
|
|
1006
|
+
this._state === "connected" && this.startSession(t).catch((r) => {
|
|
1007
|
+
_.warn("autoStartFromUrl: startSession rejected:", r);
|
|
998
1008
|
});
|
|
999
1009
|
}, 0);
|
|
1000
1010
|
}
|
|
@@ -1011,8 +1021,8 @@ class Be extends EventTarget {
|
|
|
1011
1021
|
username: this._username ?? "",
|
|
1012
1022
|
expires: typeof this._tokenExpires == "string" ? this._tokenExpires : this._tokenExpires.toISOString()
|
|
1013
1023
|
}), !0;
|
|
1014
|
-
const
|
|
1015
|
-
return
|
|
1024
|
+
const r = Te();
|
|
1025
|
+
return r && r.username ? (this._token = r.token, this._username = r.username, this._tokenExpires = r.expires, !0) : !1;
|
|
1016
1026
|
} catch (e) {
|
|
1017
1027
|
return _.error("authenticate failed:", e), !1;
|
|
1018
1028
|
}
|
|
@@ -1020,15 +1030,15 @@ class Be extends EventTarget {
|
|
|
1020
1030
|
async login(e) {
|
|
1021
1031
|
const t = {};
|
|
1022
1032
|
this._clientId && (t.clientId = this._clientId);
|
|
1023
|
-
let
|
|
1033
|
+
let r = await ce(t);
|
|
1024
1034
|
if (e?.prompt) {
|
|
1025
|
-
const
|
|
1026
|
-
|
|
1035
|
+
const n = new URL(r);
|
|
1036
|
+
n.searchParams.set("prompt", e.prompt), r = n.toString();
|
|
1027
1037
|
}
|
|
1028
|
-
window.location.href =
|
|
1038
|
+
window.location.href = r;
|
|
1029
1039
|
}
|
|
1030
1040
|
logout() {
|
|
1031
|
-
|
|
1041
|
+
O(), this._username = null, this._tokenExpires = null, this.disconnect();
|
|
1032
1042
|
}
|
|
1033
1043
|
// ─── Lifecycle ───────────────────────────────────────────────────────
|
|
1034
1044
|
async connect(e) {
|
|
@@ -1044,12 +1054,12 @@ class Be extends EventTarget {
|
|
|
1044
1054
|
headers: { Authorization: `Bearer ${this._token}` }
|
|
1045
1055
|
}
|
|
1046
1056
|
);
|
|
1047
|
-
} catch (
|
|
1048
|
-
throw this._sseAbortController = null,
|
|
1057
|
+
} catch (r) {
|
|
1058
|
+
throw this._sseAbortController = null, r;
|
|
1049
1059
|
}
|
|
1050
1060
|
if (!t.ok)
|
|
1051
1061
|
throw this._sseAbortController = null, new Error(`HTTP ${t.status}`);
|
|
1052
|
-
return new Promise((
|
|
1062
|
+
return new Promise((r, n) => {
|
|
1053
1063
|
let i = !1;
|
|
1054
1064
|
const o = t.body.getReader(), a = new TextDecoder();
|
|
1055
1065
|
let c = "";
|
|
@@ -1070,25 +1080,25 @@ class Be extends EventTarget {
|
|
|
1070
1080
|
type: "setPeerStatus",
|
|
1071
1081
|
roles: ["listener"],
|
|
1072
1082
|
meta: { name: this._appName }
|
|
1073
|
-
}), this._emit("connected", { peerId: f.peerId }),
|
|
1083
|
+
}), this._emit("connected", { peerId: f.peerId }), r()), this._handleSignalingMessage(f);
|
|
1074
1084
|
} catch {
|
|
1075
1085
|
}
|
|
1076
1086
|
}
|
|
1077
1087
|
} catch (u) {
|
|
1078
1088
|
if (u.name !== "AbortError" && this._emit("error", { source: "signaling", error: u }), !i) {
|
|
1079
|
-
|
|
1089
|
+
n(u);
|
|
1080
1090
|
return;
|
|
1081
1091
|
}
|
|
1082
1092
|
}
|
|
1083
|
-
this._state !== "disconnected" && (this._state = "disconnected", this._emit("disconnected", { reason: "SSE closed" })), i ||
|
|
1093
|
+
this._state !== "disconnected" && (this._state = "disconnected", this._emit("disconnected", { reason: "SSE closed" })), i || n(new Error("Connection closed before welcome"));
|
|
1084
1094
|
})();
|
|
1085
1095
|
});
|
|
1086
1096
|
}
|
|
1087
1097
|
async autoConnect(e = {}) {
|
|
1088
1098
|
const {
|
|
1089
1099
|
token: t,
|
|
1090
|
-
pickRobot:
|
|
1091
|
-
autoPickIfSingle:
|
|
1100
|
+
pickRobot: r,
|
|
1101
|
+
autoPickIfSingle: n = !0,
|
|
1092
1102
|
filterBusy: i = !0,
|
|
1093
1103
|
wakeOnConnect: o = !0
|
|
1094
1104
|
} = e;
|
|
@@ -1121,10 +1131,10 @@ class Be extends EventTarget {
|
|
|
1121
1131
|
const u = await this._fetchOwnedRobots({ filterBusy: i });
|
|
1122
1132
|
if (u.length === 0)
|
|
1123
1133
|
throw new Error("No reachable robots");
|
|
1124
|
-
if (
|
|
1134
|
+
if (n && u.length === 1 && !u[0].busy)
|
|
1125
1135
|
c = u[0].id, d = u[0].name;
|
|
1126
|
-
else if (
|
|
1127
|
-
const l = await
|
|
1136
|
+
else if (r) {
|
|
1137
|
+
const l = await r(u);
|
|
1128
1138
|
if (!l) throw new Error("Robot selection cancelled");
|
|
1129
1139
|
c = l, d = u.find((m) => m.id === l)?.name ?? null;
|
|
1130
1140
|
} else
|
|
@@ -1149,11 +1159,11 @@ class Be extends EventTarget {
|
|
|
1149
1159
|
headers: { Authorization: `Bearer ${this._token}` }
|
|
1150
1160
|
});
|
|
1151
1161
|
if (!t.ok) throw new Error(`HTTP ${t.status}`);
|
|
1152
|
-
const
|
|
1153
|
-
for (const i of
|
|
1162
|
+
const r = await t.json(), n = /* @__PURE__ */ new Map();
|
|
1163
|
+
for (const i of r.robots || []) {
|
|
1154
1164
|
if (e && i.busy) continue;
|
|
1155
1165
|
const o = i.meta?.install_id ?? i.meta?.hardware_id ?? i.peerId;
|
|
1156
|
-
|
|
1166
|
+
n.set(o, {
|
|
1157
1167
|
id: i.peerId,
|
|
1158
1168
|
name: i.robotName ?? i.meta?.name ?? null,
|
|
1159
1169
|
busy: !!i.busy,
|
|
@@ -1162,26 +1172,26 @@ class Be extends EventTarget {
|
|
|
1162
1172
|
lastSeenAgeSeconds: i.last_seen_age_seconds ?? null
|
|
1163
1173
|
});
|
|
1164
1174
|
}
|
|
1165
|
-
return Array.from(
|
|
1175
|
+
return Array.from(n.values()).sort(
|
|
1166
1176
|
(i, o) => (i.lastSeenAgeSeconds ?? 1 / 0) - (o.lastSeenAgeSeconds ?? 1 / 0)
|
|
1167
1177
|
);
|
|
1168
1178
|
} catch (t) {
|
|
1169
|
-
return _.warn("/api/robot-status unavailable, using SSE list:", t), (this._robots || []).map((
|
|
1170
|
-
id:
|
|
1171
|
-
name:
|
|
1179
|
+
return _.warn("/api/robot-status unavailable, using SSE list:", t), (this._robots || []).map((r) => ({
|
|
1180
|
+
id: r.id,
|
|
1181
|
+
name: r.meta?.name ?? null,
|
|
1172
1182
|
busy: !1,
|
|
1173
1183
|
activeApp: null,
|
|
1174
|
-
meta:
|
|
1184
|
+
meta: r.meta ?? {},
|
|
1175
1185
|
lastSeenAgeSeconds: null
|
|
1176
1186
|
}));
|
|
1177
1187
|
}
|
|
1178
1188
|
}
|
|
1179
1189
|
_waitForRobotInList(e, t) {
|
|
1180
|
-
return this._robots?.find((
|
|
1190
|
+
return this._robots?.find((r) => r.id === e) ? Promise.resolve() : new Promise((r, n) => {
|
|
1181
1191
|
const i = () => {
|
|
1182
|
-
this._robots?.find((a) => a.id === e) && (this.removeEventListener("robotsChanged", i), clearTimeout(o),
|
|
1192
|
+
this._robots?.find((a) => a.id === e) && (this.removeEventListener("robotsChanged", i), clearTimeout(o), r());
|
|
1183
1193
|
}, o = setTimeout(() => {
|
|
1184
|
-
this.removeEventListener("robotsChanged", i),
|
|
1194
|
+
this.removeEventListener("robotsChanged", i), n(new Error(`Timeout waiting for robot ${e} in list`));
|
|
1185
1195
|
}, t);
|
|
1186
1196
|
this.addEventListener("robotsChanged", i);
|
|
1187
1197
|
});
|
|
@@ -1193,9 +1203,9 @@ class Be extends EventTarget {
|
|
|
1193
1203
|
if (this._state !== "connected") throw new Error("Not connected");
|
|
1194
1204
|
this._selectedRobotId = e, this._iceConnected = !1, this._dcOpen = !1, this._micSupported = !1, this._pendingRemoteIce = [];
|
|
1195
1205
|
try {
|
|
1196
|
-
const t = window,
|
|
1197
|
-
if (!
|
|
1198
|
-
const
|
|
1206
|
+
const t = window, r = t.AudioContext ?? t.webkitAudioContext;
|
|
1207
|
+
if (!r) throw new Error("AudioContext not supported");
|
|
1208
|
+
const n = new r(), i = n.createMediaStreamDestination(), o = n.createOscillator(), a = n.createGain();
|
|
1199
1209
|
a.gain.value = 0, o.connect(a).connect(i), o.start();
|
|
1200
1210
|
const c = i.stream;
|
|
1201
1211
|
c.getAudioTracks().forEach((d) => {
|
|
@@ -1206,48 +1216,48 @@ class Be extends EventTarget {
|
|
|
1206
1216
|
}
|
|
1207
1217
|
return this._pc = new RTCPeerConnection({
|
|
1208
1218
|
iceServers: [{ urls: "stun:stun.l.google.com:19302" }]
|
|
1209
|
-
}), this._supervisor.installNetworkListeners(), new Promise((t,
|
|
1210
|
-
this._sessionResolve = t, this._sessionReject =
|
|
1211
|
-
if (
|
|
1219
|
+
}), this._supervisor.installNetworkListeners(), new Promise((t, r) => {
|
|
1220
|
+
this._sessionResolve = t, this._sessionReject = r, this._pc.ontrack = (n) => {
|
|
1221
|
+
if (n.track.kind === "video") {
|
|
1212
1222
|
const i = this._videoJitterBufferTargetMs;
|
|
1213
1223
|
try {
|
|
1214
|
-
|
|
1224
|
+
n.receiver.jitterBufferTarget = i;
|
|
1215
1225
|
} catch {
|
|
1216
1226
|
}
|
|
1217
1227
|
try {
|
|
1218
|
-
|
|
1228
|
+
n.receiver.playoutDelayHint = i / 1e3;
|
|
1219
1229
|
} catch {
|
|
1220
1230
|
}
|
|
1221
|
-
this._emit("videoTrack", { track:
|
|
1222
|
-
}
|
|
1223
|
-
}, this._pc.onicecandidate = async (
|
|
1224
|
-
|
|
1231
|
+
this._emit("videoTrack", { track: n.track, stream: n.streams[0] });
|
|
1232
|
+
} else n.track.kind === "audio" && (this._robotAudioTrack = n.track, this._emit("audioTrack", { track: n.track, stream: n.streams[0] }));
|
|
1233
|
+
}, this._pc.onicecandidate = async (n) => {
|
|
1234
|
+
n.candidate && this._sessionId && await this._sendToServer({
|
|
1225
1235
|
type: "peer",
|
|
1226
1236
|
sessionId: this._sessionId,
|
|
1227
1237
|
ice: {
|
|
1228
|
-
candidate:
|
|
1229
|
-
sdpMLineIndex:
|
|
1230
|
-
sdpMid:
|
|
1238
|
+
candidate: n.candidate.candidate,
|
|
1239
|
+
sdpMLineIndex: n.candidate.sdpMLineIndex,
|
|
1240
|
+
sdpMid: n.candidate.sdpMid
|
|
1231
1241
|
}
|
|
1232
1242
|
});
|
|
1233
1243
|
}, this._pc.oniceconnectionstatechange = () => {
|
|
1234
|
-
const
|
|
1235
|
-
if (
|
|
1236
|
-
if (this._emit("iceStateChange", { state:
|
|
1244
|
+
const n = this._pc?.iceConnectionState;
|
|
1245
|
+
if (n) {
|
|
1246
|
+
if (this._emit("iceStateChange", { state: n }), n === "connected" || n === "completed") {
|
|
1237
1247
|
this._supervisor.onIceHealed(), this._iceConnected = !0, this._checkSessionReady();
|
|
1238
1248
|
return;
|
|
1239
1249
|
}
|
|
1240
|
-
if (
|
|
1250
|
+
if (n === "disconnected") {
|
|
1241
1251
|
this._supervisor.onIceDisconnected();
|
|
1242
1252
|
return;
|
|
1243
1253
|
}
|
|
1244
|
-
if (
|
|
1254
|
+
if (n === "failed") {
|
|
1245
1255
|
this._supervisor.onIceFailed();
|
|
1246
1256
|
return;
|
|
1247
1257
|
}
|
|
1248
1258
|
}
|
|
1249
|
-
}, this._pc.ondatachannel = (
|
|
1250
|
-
const i =
|
|
1259
|
+
}, this._pc.ondatachannel = (n) => {
|
|
1260
|
+
const i = n.channel;
|
|
1251
1261
|
if (i.label === "pose") {
|
|
1252
1262
|
this._lastPoseSeq = null, i.onmessage = (a) => {
|
|
1253
1263
|
const c = JSON.parse(a.data);
|
|
@@ -1267,12 +1277,12 @@ class Be extends EventTarget {
|
|
|
1267
1277
|
const c = o.accept(JSON.parse(a.data));
|
|
1268
1278
|
c && this._handleRobotMessage(c);
|
|
1269
1279
|
};
|
|
1270
|
-
}, this._sendToServer({ type: "startSession", peerId: e }).then((
|
|
1271
|
-
if (
|
|
1272
|
-
this._failSessionRejected(
|
|
1280
|
+
}, this._sendToServer({ type: "startSession", peerId: e }).then((n) => {
|
|
1281
|
+
if (n?.type === "sessionRejected") {
|
|
1282
|
+
this._failSessionRejected(n);
|
|
1273
1283
|
return;
|
|
1274
1284
|
}
|
|
1275
|
-
|
|
1285
|
+
n?.sessionId && (this._sessionId = n.sessionId);
|
|
1276
1286
|
});
|
|
1277
1287
|
});
|
|
1278
1288
|
}
|
|
@@ -1289,10 +1299,10 @@ class Be extends EventTarget {
|
|
|
1289
1299
|
*/
|
|
1290
1300
|
_closeTransport(e) {
|
|
1291
1301
|
if (this._pending.settleAll(e), this._sessionReject) {
|
|
1292
|
-
const
|
|
1293
|
-
this._sessionResolve = null, this._sessionReject = null,
|
|
1302
|
+
const r = this._sessionReject;
|
|
1303
|
+
this._sessionResolve = null, this._sessionReject = null, r(e);
|
|
1294
1304
|
}
|
|
1295
|
-
this._sessionResolve = null, this._supervisor.clearIceGrace(), this._supervisor.uninstallNetworkListeners(), this._supervisor.stopDcWatchdog(), this._stateRefreshInterval && (clearInterval(this._stateRefreshInterval), this._stateRefreshInterval = null), this._latencyMonitorId && (clearInterval(this._latencyMonitorId), this._latencyMonitorId = null), this._micStream && (this._micStream.getTracks().forEach((
|
|
1305
|
+
this._sessionResolve = null, this._supervisor.clearIceGrace(), this._supervisor.uninstallNetworkListeners(), this._supervisor.stopDcWatchdog(), this._stateRefreshInterval && (clearInterval(this._stateRefreshInterval), this._stateRefreshInterval = null), this._latencyMonitorId && (clearInterval(this._latencyMonitorId), this._latencyMonitorId = null), this._micStream && (this._micStream.getTracks().forEach((r) => r.stop()), this._micStream = null), this._robotAudioTrack = null, this._micMuted = !0, this._micSupported = !1, this._pc && (this._pc.close(), this._pc = null), this._dc && (this._dc.close(), this._dc = null), this._iceConnected = !1, this._dcOpen = !1;
|
|
1296
1306
|
const t = this._sessionId;
|
|
1297
1307
|
return this._sessionId = null, t;
|
|
1298
1308
|
}
|
|
@@ -1303,12 +1313,12 @@ class Be extends EventTarget {
|
|
|
1303
1313
|
t.reason = e.reason ?? null, t.activeApp = e.activeApp ?? null, this._closeTransport(t), this._supervisor.redialing || this._emit("sessionRejected", { reason: e.reason, activeApp: e.activeApp });
|
|
1304
1314
|
}
|
|
1305
1315
|
async stopSession() {
|
|
1306
|
-
this._supervisor.cancelRedial(), this._logSubscribers.clear(), this._updateProgressSubscribers.clear();
|
|
1316
|
+
this._supervisor.cancelRedial(), this._logSubscribers.clear(), this._updateProgressSubscribers.clear(), this._outgoingAudioTrack = null;
|
|
1307
1317
|
const e = this._closeTransport(new Error("Session stopped"));
|
|
1308
1318
|
e && await this._sendToServer({ type: "endSession", sessionId: e }), this._state === "streaming" && (this._state = "connected", this._emit("sessionStopped", { reason: "user" }));
|
|
1309
1319
|
}
|
|
1310
1320
|
disconnect() {
|
|
1311
|
-
this._supervisor.cancelRedial(), this._sseAbortController && (this._sseAbortController.abort(), this._sseAbortController = null), this._logSubscribers.clear(), this._updateProgressSubscribers.clear();
|
|
1321
|
+
this._supervisor.cancelRedial(), this._sseAbortController && (this._sseAbortController.abort(), this._sseAbortController = null), this._logSubscribers.clear(), this._updateProgressSubscribers.clear(), this._outgoingAudioTrack = null;
|
|
1312
1322
|
const e = this._closeTransport(new Error("Disconnected"));
|
|
1313
1323
|
e && this._token && this._sendToServer({ type: "endSession", sessionId: e }), this._robots = [], this._state = "disconnected", this._emit("disconnected", { reason: "user" });
|
|
1314
1324
|
}
|
|
@@ -1391,32 +1401,32 @@ class Be extends EventTarget {
|
|
|
1391
1401
|
* @returns `true` if the command was queued on the data channel,
|
|
1392
1402
|
* `false` if the channel is not open.
|
|
1393
1403
|
*/
|
|
1394
|
-
setTarget({ head: e, antennas: t, body_yaw:
|
|
1395
|
-
const
|
|
1404
|
+
setTarget({ head: e, antennas: t, body_yaw: r } = {}) {
|
|
1405
|
+
const n = { type: "set_full_target" };
|
|
1396
1406
|
if (e !== void 0) {
|
|
1397
1407
|
if (!Array.isArray(e) || e.length !== 16 || !e.every((i) => Number.isFinite(i)))
|
|
1398
1408
|
throw new TypeError(
|
|
1399
1409
|
`setTarget: head must be a 16-element flat row-major 4×4 matrix of finite numbers; got ${Array.isArray(e) ? `Array(${e.length})` : typeof e}`
|
|
1400
1410
|
);
|
|
1401
|
-
|
|
1411
|
+
n.head = e;
|
|
1402
1412
|
}
|
|
1403
1413
|
if (t !== void 0) {
|
|
1404
1414
|
if (!Array.isArray(t) || t.length !== 2 || !t.every((i) => Number.isFinite(i)))
|
|
1405
1415
|
throw new TypeError(
|
|
1406
1416
|
`setTarget: antennas must be [rightRad, leftRad] (2 finite numbers); got ${Array.isArray(t) ? `Array(${t.length})` : typeof t}`
|
|
1407
1417
|
);
|
|
1408
|
-
|
|
1418
|
+
n.antennas = t;
|
|
1409
1419
|
}
|
|
1410
|
-
if (
|
|
1411
|
-
if (!Number.isFinite(
|
|
1420
|
+
if (r !== void 0) {
|
|
1421
|
+
if (!Number.isFinite(r))
|
|
1412
1422
|
throw new TypeError(
|
|
1413
|
-
`setTarget: body_yaw must be a finite number (radians); got ${
|
|
1423
|
+
`setTarget: body_yaw must be a finite number (radians); got ${r}`
|
|
1414
1424
|
);
|
|
1415
|
-
|
|
1425
|
+
n.body_yaw = r;
|
|
1416
1426
|
}
|
|
1417
|
-
return this._sendCommand(
|
|
1427
|
+
return this._sendCommand(n);
|
|
1418
1428
|
}
|
|
1419
|
-
gotoTarget({ head: e, antennas: t, body_yaw:
|
|
1429
|
+
gotoTarget({ head: e, antennas: t, body_yaw: r, duration: n }) {
|
|
1420
1430
|
const i = { type: "goto_target" };
|
|
1421
1431
|
if (e !== void 0) {
|
|
1422
1432
|
if (!Array.isArray(e) || e.length !== 16 || !e.every((o) => Number.isFinite(o)))
|
|
@@ -1432,40 +1442,40 @@ class Be extends EventTarget {
|
|
|
1432
1442
|
);
|
|
1433
1443
|
i.antennas = t;
|
|
1434
1444
|
}
|
|
1435
|
-
if (
|
|
1436
|
-
if (!Number.isFinite(
|
|
1445
|
+
if (r !== void 0) {
|
|
1446
|
+
if (!Number.isFinite(r))
|
|
1437
1447
|
throw new TypeError(
|
|
1438
|
-
`gotoTarget: body_yaw must be a finite number (radians); got ${
|
|
1448
|
+
`gotoTarget: body_yaw must be a finite number (radians); got ${r}`
|
|
1439
1449
|
);
|
|
1440
|
-
i.body_yaw =
|
|
1450
|
+
i.body_yaw = r;
|
|
1441
1451
|
}
|
|
1442
|
-
if (!Number.isFinite(
|
|
1452
|
+
if (!Number.isFinite(n) || n <= 0)
|
|
1443
1453
|
throw new TypeError(
|
|
1444
|
-
`gotoTarget: duration must be a positive finite number (seconds); got ${
|
|
1454
|
+
`gotoTarget: duration must be a positive finite number (seconds); got ${n}`
|
|
1445
1455
|
);
|
|
1446
|
-
return i.duration =
|
|
1456
|
+
return i.duration = n, this._sendCommand(i);
|
|
1447
1457
|
}
|
|
1448
|
-
setHeadRpyDeg(e, t,
|
|
1449
|
-
return this.setTarget({ head: ue(e, t,
|
|
1458
|
+
setHeadRpyDeg(e, t, r) {
|
|
1459
|
+
return this.setTarget({ head: ue(e, t, r).flat() });
|
|
1450
1460
|
}
|
|
1451
1461
|
setAntennasDeg(e, t) {
|
|
1452
|
-
return this.setTarget({ antennas: [
|
|
1462
|
+
return this.setTarget({ antennas: [k(e), k(t)] });
|
|
1453
1463
|
}
|
|
1454
1464
|
setBodyYawDeg(e) {
|
|
1455
|
-
return this.setTarget({ body_yaw:
|
|
1465
|
+
return this.setTarget({ body_yaw: k(e) });
|
|
1456
1466
|
}
|
|
1457
1467
|
playSound(e) {
|
|
1458
1468
|
return this._sendCommand({ type: "play_sound", file: e });
|
|
1459
1469
|
}
|
|
1460
1470
|
playRecordedMove(e, {
|
|
1461
1471
|
dataset: t,
|
|
1462
|
-
initialGotoDuration:
|
|
1472
|
+
initialGotoDuration: r
|
|
1463
1473
|
} = {}) {
|
|
1464
1474
|
return this._sendCommand({
|
|
1465
1475
|
type: "play_recorded_move",
|
|
1466
1476
|
move_name: e,
|
|
1467
1477
|
...t ? { dataset_name: t } : {},
|
|
1468
|
-
...
|
|
1478
|
+
...r && r > 0 ? { initial_goto_duration: r } : {}
|
|
1469
1479
|
});
|
|
1470
1480
|
}
|
|
1471
1481
|
/**
|
|
@@ -1492,11 +1502,11 @@ class Be extends EventTarget {
|
|
|
1492
1502
|
*/
|
|
1493
1503
|
preloadDatasetAndWait(e, { timeoutMs: t = 12e4 } = {}) {
|
|
1494
1504
|
return this.preloadDataset(e) ? this._pending.awaitBroadcast(
|
|
1495
|
-
(
|
|
1505
|
+
(r) => r.command === "preload_dataset" && r.dataset_name === e,
|
|
1496
1506
|
{ timeoutMs: t, debugLabel: `preload_dataset(${e})` }
|
|
1497
|
-
).then((
|
|
1498
|
-
if (
|
|
1499
|
-
throw
|
|
1507
|
+
).then((r) => r.status === "ok").catch((r) => {
|
|
1508
|
+
if (r instanceof P) return null;
|
|
1509
|
+
throw r;
|
|
1500
1510
|
}) : Promise.reject(new Error("Data channel not open"));
|
|
1501
1511
|
}
|
|
1502
1512
|
clearIncomingAudio() {
|
|
@@ -1555,11 +1565,11 @@ class Be extends EventTarget {
|
|
|
1555
1565
|
return e === "enabled" || e === "gravity_compensation";
|
|
1556
1566
|
}
|
|
1557
1567
|
async ensureAwake(e = 1e3) {
|
|
1558
|
-
if (this._robotState?.motor_mode === void 0 && await new Promise((
|
|
1559
|
-
const
|
|
1560
|
-
this.removeEventListener("state",
|
|
1561
|
-
}, i = setTimeout(
|
|
1562
|
-
this.addEventListener("state",
|
|
1568
|
+
if (this._robotState?.motor_mode === void 0 && await new Promise((r) => {
|
|
1569
|
+
const n = () => {
|
|
1570
|
+
this.removeEventListener("state", n), clearTimeout(i), r();
|
|
1571
|
+
}, i = setTimeout(n, e);
|
|
1572
|
+
this.addEventListener("state", n), this.requestState();
|
|
1563
1573
|
}), this._robotState?.motor_mode === "gravity_compensation")
|
|
1564
1574
|
return _.info("ensureAwake: gravity compensation inherited, flipping to enabled (no emote)"), this.setMotorMode("enabled"), this.requestState(), !0;
|
|
1565
1575
|
if (this.isAwake())
|
|
@@ -1568,8 +1578,8 @@ class Be extends EventTarget {
|
|
|
1568
1578
|
const t = Date.now();
|
|
1569
1579
|
try {
|
|
1570
1580
|
await this.wakeUp({ timeoutMs: Le }), _.info(`ensureAwake: wake-up trajectory done in ${Date.now() - t}ms`);
|
|
1571
|
-
} catch (
|
|
1572
|
-
_.warn(`ensureAwake: wake-up not confirmed after ${Date.now() - t}ms (continuing):`,
|
|
1581
|
+
} catch (r) {
|
|
1582
|
+
_.warn(`ensureAwake: wake-up not confirmed after ${Date.now() - t}ms (continuing):`, r);
|
|
1573
1583
|
}
|
|
1574
1584
|
return !0;
|
|
1575
1585
|
}
|
|
@@ -1659,7 +1669,7 @@ class Be extends EventTarget {
|
|
|
1659
1669
|
return this._slotRoundtrip("delete_hf_token", { type: "delete_hf_token" });
|
|
1660
1670
|
}
|
|
1661
1671
|
applyAudioConfig(e, { verify: t = !0 } = {}) {
|
|
1662
|
-
return this._slotRoundtrip("apply_audio_config", { type: "apply_audio_config", config: e, verify: t }).then((
|
|
1672
|
+
return this._slotRoundtrip("apply_audio_config", { type: "apply_audio_config", config: e, verify: t }).then((r) => r === !0);
|
|
1663
1673
|
}
|
|
1664
1674
|
readAudioParameter(e) {
|
|
1665
1675
|
return this._slotRoundtrip("read_audio_parameter", { type: "read_audio_parameter", name: e });
|
|
@@ -1695,11 +1705,11 @@ class Be extends EventTarget {
|
|
|
1695
1705
|
* reach this matcher - use the typed wrappers for those. Pass `match`
|
|
1696
1706
|
* for replies that don't follow the `command` echo convention.
|
|
1697
1707
|
*/
|
|
1698
|
-
request(e, { timeoutMs: t = ee, match:
|
|
1708
|
+
request(e, { timeoutMs: t = ee, match: r } = {}) {
|
|
1699
1709
|
if (!this._sendCommand(e))
|
|
1700
1710
|
return Promise.reject(new Error("Data channel not open"));
|
|
1701
|
-
const
|
|
1702
|
-
return this._pending.awaitBroadcast(
|
|
1711
|
+
const n = r ?? ((i) => i.command === e.type);
|
|
1712
|
+
return this._pending.awaitBroadcast(n, { timeoutMs: t, debugLabel: `request(${e.type})` }).catch((i) => {
|
|
1703
1713
|
if (i instanceof P) return null;
|
|
1704
1714
|
throw i;
|
|
1705
1715
|
});
|
|
@@ -1707,11 +1717,11 @@ class Be extends EventTarget {
|
|
|
1707
1717
|
subscribeLogs({ onLine: e, onError: t }) {
|
|
1708
1718
|
if (typeof e != "function")
|
|
1709
1719
|
throw new TypeError("subscribeLogs: onLine callback is required");
|
|
1710
|
-
const
|
|
1711
|
-
this._logSubscribers.add(
|
|
1720
|
+
const r = { onLine: e, onError: t }, n = this._logSubscribers.size === 0;
|
|
1721
|
+
this._logSubscribers.add(r), n && this._sendCommand({ type: "subscribe_logs" });
|
|
1712
1722
|
let i = !1;
|
|
1713
1723
|
return () => {
|
|
1714
|
-
i || (i = !0, this._logSubscribers.delete(
|
|
1724
|
+
i || (i = !0, this._logSubscribers.delete(r), this._logSubscribers.size === 0 && this._sendCommand({ type: "unsubscribe_logs" }));
|
|
1715
1725
|
};
|
|
1716
1726
|
}
|
|
1717
1727
|
requestState() {
|
|
@@ -1745,24 +1755,49 @@ class Be extends EventTarget {
|
|
|
1745
1755
|
t.enabled = !e;
|
|
1746
1756
|
});
|
|
1747
1757
|
}
|
|
1758
|
+
/**
|
|
1759
|
+
* Stream an audio track to the robot's speaker in real time (TTS output,
|
|
1760
|
+
* a WebAudio graph, the user's own mic for teleop…). Pass `null` to go
|
|
1761
|
+
* back to silence. The track survives auto-reconnects; the app keeps
|
|
1762
|
+
* ownership of it (the SDK never stops it).
|
|
1763
|
+
*
|
|
1764
|
+
* Resolves `true` once the track is on the wire, `false` when there is
|
|
1765
|
+
* no live session yet (it is then applied as soon as one starts) or when
|
|
1766
|
+
* the robot didn't offer two-way audio. Cleared by `stopSession()` /
|
|
1767
|
+
* `disconnect()`. `setMicMuted()` only mutes the SDK's placeholder, not
|
|
1768
|
+
* this track — stop or disable the track itself to go quiet.
|
|
1769
|
+
* For clips that must stay in sync with motion, prefer
|
|
1770
|
+
* `playMove(motion, { audioBlob })` or `uploadAudio` + `playUploadedAudio`.
|
|
1771
|
+
*/
|
|
1772
|
+
async setOutgoingAudioTrack(e) {
|
|
1773
|
+
if (e && e.kind !== "audio")
|
|
1774
|
+
throw new TypeError(`setOutgoingAudioTrack: expected an audio track, got "${e.kind}"`);
|
|
1775
|
+
return this._outgoingAudioTrack = e, this._applyOutgoingAudioTrack();
|
|
1776
|
+
}
|
|
1777
|
+
async _applyOutgoingAudioTrack() {
|
|
1778
|
+
const e = this._pc?.getTransceivers().find((r) => r.receiver.track.kind === "audio")?.sender;
|
|
1779
|
+
if (!e || !this._micSupported) return !1;
|
|
1780
|
+
const t = this._micStream?.getAudioTracks()[0] ?? null;
|
|
1781
|
+
return await e.replaceTrack(this._outgoingAudioTrack ?? t), !0;
|
|
1782
|
+
}
|
|
1748
1783
|
// ─── Video helper ────────────────────────────────────────────────────
|
|
1749
1784
|
attachVideo(e) {
|
|
1750
1785
|
this._videoElement = e, e.muted = this._audioMuted;
|
|
1751
|
-
const t = (
|
|
1752
|
-
const i =
|
|
1786
|
+
const t = (n) => {
|
|
1787
|
+
const i = n;
|
|
1753
1788
|
e.srcObject = i.detail.stream, e.playsInline = !0, "requestVideoFrameCallback" in e && this._startLatencyMonitor(e);
|
|
1754
|
-
},
|
|
1789
|
+
}, r = () => {
|
|
1755
1790
|
e.srcObject = null;
|
|
1756
1791
|
};
|
|
1757
|
-
return this.addEventListener("videoTrack", t), this.addEventListener("sessionStopped",
|
|
1758
|
-
this.removeEventListener("videoTrack", t), this.removeEventListener("sessionStopped",
|
|
1792
|
+
return this.addEventListener("videoTrack", t), this.addEventListener("sessionStopped", r), () => {
|
|
1793
|
+
this.removeEventListener("videoTrack", t), this.removeEventListener("sessionStopped", r), this._latencyMonitorId && (clearInterval(this._latencyMonitorId), this._latencyMonitorId = null), e.srcObject = null, this._videoElement = null;
|
|
1759
1794
|
};
|
|
1760
1795
|
}
|
|
1761
1796
|
// ─── Daemon-side recorded-move playback ──────────────────────────────
|
|
1762
1797
|
async playMove(e, {
|
|
1763
1798
|
audioBlob: t = null,
|
|
1764
|
-
audioLeadMs:
|
|
1765
|
-
description:
|
|
1799
|
+
audioLeadMs: r = -100,
|
|
1800
|
+
description: n = "move",
|
|
1766
1801
|
encoding: i = "gzip+base64",
|
|
1767
1802
|
playFrequency: o = 100,
|
|
1768
1803
|
initialGotoDuration: a = 0,
|
|
@@ -1779,7 +1814,7 @@ class Be extends EventTarget {
|
|
|
1779
1814
|
const l = K();
|
|
1780
1815
|
this._activeMoveUploadId = l;
|
|
1781
1816
|
const m = {
|
|
1782
|
-
description:
|
|
1817
|
+
description: n,
|
|
1783
1818
|
time: e.time,
|
|
1784
1819
|
set_target_data: e.set_target_data
|
|
1785
1820
|
}, g = JSON.stringify(m);
|
|
@@ -1796,7 +1831,7 @@ class Be extends EventTarget {
|
|
|
1796
1831
|
type: "upload_move_start",
|
|
1797
1832
|
upload_id: l,
|
|
1798
1833
|
total_chunks: w,
|
|
1799
|
-
description:
|
|
1834
|
+
description: n,
|
|
1800
1835
|
encoding: v
|
|
1801
1836
|
});
|
|
1802
1837
|
for (let h = 0; h < w; h++) {
|
|
@@ -1810,7 +1845,7 @@ class Be extends EventTarget {
|
|
|
1810
1845
|
}), d({ phase: "upload", sent: h + 1, total: w });
|
|
1811
1846
|
}
|
|
1812
1847
|
if (this._sendCommand({ type: "upload_move_finish", upload_id: l }), d({ phase: "uploaded", sent: w, total: w }), t) {
|
|
1813
|
-
const h = new Uint8Array(await t.arrayBuffer()), p =
|
|
1848
|
+
const h = new Uint8Array(await t.arrayBuffer()), p = N(h), R = Math.ceil(p.length / y) || 1;
|
|
1814
1849
|
d({
|
|
1815
1850
|
phase: "audio-starting",
|
|
1816
1851
|
sent: 0,
|
|
@@ -1821,7 +1856,7 @@ class Be extends EventTarget {
|
|
|
1821
1856
|
upload_id: l,
|
|
1822
1857
|
total_chunks: R,
|
|
1823
1858
|
encoding: X(t),
|
|
1824
|
-
description:
|
|
1859
|
+
description: n
|
|
1825
1860
|
});
|
|
1826
1861
|
for (let T = 0; T < R; T++) {
|
|
1827
1862
|
this._dc.bufferedAmount > L && await this._awaitDataChannelDrain();
|
|
@@ -1840,7 +1875,7 @@ class Be extends EventTarget {
|
|
|
1840
1875
|
upload_id: l,
|
|
1841
1876
|
play_frequency: o,
|
|
1842
1877
|
initial_goto_duration: a,
|
|
1843
|
-
audio_lead_ms:
|
|
1878
|
+
audio_lead_ms: r
|
|
1844
1879
|
});
|
|
1845
1880
|
let b;
|
|
1846
1881
|
try {
|
|
@@ -1877,16 +1912,16 @@ class Be extends EventTarget {
|
|
|
1877
1912
|
const t = e ?? this._activeMoveUploadId;
|
|
1878
1913
|
return t ? this._sendCommand({ type: "cancel_move", upload_id: t }) : !1;
|
|
1879
1914
|
}
|
|
1880
|
-
async uploadAudio(e, { description: t = "audio", onProgress:
|
|
1915
|
+
async uploadAudio(e, { description: t = "audio", onProgress: r = () => {
|
|
1881
1916
|
} } = {}) {
|
|
1882
1917
|
if (!this._dc || this._dc.readyState !== "open")
|
|
1883
1918
|
throw new Error("data channel not open");
|
|
1884
1919
|
if (!(e instanceof Blob))
|
|
1885
1920
|
throw new TypeError("uploadAudio: expected a Blob");
|
|
1886
|
-
const
|
|
1887
|
-
|
|
1921
|
+
const n = K(), i = new Uint8Array(await e.arrayBuffer()), o = N(i), a = Math.ceil(o.length / y) || 1;
|
|
1922
|
+
r({ phase: "audio-starting", sent: 0, total: a, bytes: o.length }), this._sendCommand({
|
|
1888
1923
|
type: "upload_audio_start",
|
|
1889
|
-
upload_id:
|
|
1924
|
+
upload_id: n,
|
|
1890
1925
|
total_chunks: a,
|
|
1891
1926
|
encoding: X(e),
|
|
1892
1927
|
description: t
|
|
@@ -1896,24 +1931,24 @@ class Be extends EventTarget {
|
|
|
1896
1931
|
const d = c * y;
|
|
1897
1932
|
this._sendCommand({
|
|
1898
1933
|
type: "upload_audio_chunk",
|
|
1899
|
-
upload_id:
|
|
1934
|
+
upload_id: n,
|
|
1900
1935
|
chunk_index: c,
|
|
1901
1936
|
chunk: o.slice(d, d + y)
|
|
1902
|
-
}),
|
|
1937
|
+
}), r({ phase: "audio-upload", sent: c + 1, total: a });
|
|
1903
1938
|
}
|
|
1904
|
-
return this._sendCommand({ type: "upload_audio_finish", upload_id:
|
|
1939
|
+
return this._sendCommand({ type: "upload_audio_finish", upload_id: n }), r({ phase: "audio-uploaded", sent: a, total: a }), n;
|
|
1905
1940
|
}
|
|
1906
1941
|
async playUploadedAudio(e, { timeoutMs: t = 8e3 } = {}) {
|
|
1907
1942
|
if (!this._dc || this._dc.readyState !== "open")
|
|
1908
1943
|
throw new Error("data channel not open");
|
|
1909
|
-
const
|
|
1944
|
+
const r = this._waitForBroadcast(
|
|
1910
1945
|
(i) => i?.type === "play_uploaded_audio" && i?.upload_id === e && (i.started === !0 || typeof i.error == "string"),
|
|
1911
1946
|
{ timeoutMs: t, debugLabel: "play_uploaded_audio started" }
|
|
1912
1947
|
);
|
|
1913
1948
|
this._sendCommand({ type: "play_uploaded_audio", upload_id: e });
|
|
1914
|
-
const
|
|
1915
|
-
if (typeof
|
|
1916
|
-
return this._activeAudioUploadId = e,
|
|
1949
|
+
const n = await r;
|
|
1950
|
+
if (typeof n.error == "string") throw new Error(n.error);
|
|
1951
|
+
return this._activeAudioUploadId = e, n;
|
|
1917
1952
|
}
|
|
1918
1953
|
cancelAudio(e = null) {
|
|
1919
1954
|
const t = e ?? this._activeAudioUploadId;
|
|
@@ -1943,13 +1978,13 @@ class Be extends EventTarget {
|
|
|
1943
1978
|
body: JSON.stringify(e)
|
|
1944
1979
|
});
|
|
1945
1980
|
if (!t.ok) {
|
|
1946
|
-
let
|
|
1981
|
+
let r = "";
|
|
1947
1982
|
try {
|
|
1948
|
-
|
|
1983
|
+
r = await t.text();
|
|
1949
1984
|
} catch {
|
|
1950
1985
|
}
|
|
1951
1986
|
return _.warn(
|
|
1952
|
-
`/send rejected (${t.status}) for type=${e?.type}; body=${
|
|
1987
|
+
`/send rejected (${t.status}) for type=${e?.type}; body=${r || "<empty>"}`
|
|
1953
1988
|
), null;
|
|
1954
1989
|
}
|
|
1955
1990
|
return await t.json();
|
|
@@ -1967,11 +2002,11 @@ class Be extends EventTarget {
|
|
|
1967
2002
|
* `conversation.say`). Rejects on the JSON-RPC error, a closed channel, or
|
|
1968
2003
|
* timeout.
|
|
1969
2004
|
*/
|
|
1970
|
-
rpcCall(e, t = {},
|
|
1971
|
-
const
|
|
2005
|
+
rpcCall(e, t = {}, r = {}) {
|
|
2006
|
+
const n = r.timeoutMs ?? 2e4;
|
|
1972
2007
|
return this._pending.rpcRoundtrip(
|
|
1973
2008
|
e,
|
|
1974
|
-
|
|
2009
|
+
n,
|
|
1975
2010
|
(i) => this._sendCommand({ jsonrpc: "2.0", id: i, method: e, params: t })
|
|
1976
2011
|
);
|
|
1977
2012
|
}
|
|
@@ -1980,19 +2015,19 @@ class Be extends EventTarget {
|
|
|
1980
2015
|
* robot/app, e.g. `conversation.turn`. Returns an unsubscribe function.
|
|
1981
2016
|
*/
|
|
1982
2017
|
onNotification(e, t) {
|
|
1983
|
-
let
|
|
1984
|
-
return
|
|
2018
|
+
let r = this._rpcListeners.get(e);
|
|
2019
|
+
return r || (r = /* @__PURE__ */ new Set(), this._rpcListeners.set(e, r)), r.add(t), () => {
|
|
1985
2020
|
this._rpcListeners.get(e)?.delete(t);
|
|
1986
2021
|
};
|
|
1987
2022
|
}
|
|
1988
2023
|
_handleRpcMessage(e) {
|
|
1989
2024
|
if (!this._pending.settleRpcResponse(e) && typeof e.method == "string") {
|
|
1990
2025
|
const t = e.params ?? {};
|
|
1991
|
-
for (const
|
|
2026
|
+
for (const r of this._rpcListeners.get(e.method) ?? [])
|
|
1992
2027
|
try {
|
|
1993
|
-
|
|
1994
|
-
} catch (
|
|
1995
|
-
_.error(`onNotification(${e.method}) threw:`,
|
|
2028
|
+
r(t);
|
|
2029
|
+
} catch (n) {
|
|
2030
|
+
_.error(`onNotification(${e.method}) threw:`, n);
|
|
1996
2031
|
}
|
|
1997
2032
|
}
|
|
1998
2033
|
}
|
|
@@ -2028,19 +2063,19 @@ class Be extends EventTarget {
|
|
|
2028
2063
|
}
|
|
2029
2064
|
}
|
|
2030
2065
|
_handleEndSession(e) {
|
|
2031
|
-
const t = e.reason,
|
|
2066
|
+
const t = e.reason, r = t === "robot_busy_local_app" ? "Robot is busy: a local Python app is running" : t === "local_app_started" ? "Disconnected: a local Python app started on the robot" : t === "robot_busy_local" ? "Robot is busy: another session is already active" : null;
|
|
2032
2067
|
if (this._sessionReject) {
|
|
2033
|
-
const
|
|
2034
|
-
|
|
2068
|
+
const n = new Error(
|
|
2069
|
+
r || `Session ended before it could start: ${t || "unknown reason"}`
|
|
2035
2070
|
);
|
|
2036
|
-
|
|
2071
|
+
n.reason = t ?? null, this._supervisor.redialing || this._emit("sessionRejected", { reason: t, activeApp: null }), this._supervisor.clearIceGrace(), this._supervisor.uninstallNetworkListeners(), this._pc && (this._pc.close(), this._pc = null), this._micStream && (this._micStream.getTracks().forEach((o) => o.stop()), this._micStream = null), this._robotAudioTrack = null, this._iceConnected = !1, this._dcOpen = !1, this._micMuted = !0, this._micSupported = !1;
|
|
2037
2072
|
const i = this._sessionReject;
|
|
2038
|
-
this._sessionResolve = null, this._sessionReject = null, i(
|
|
2073
|
+
this._sessionResolve = null, this._sessionReject = null, i(n);
|
|
2039
2074
|
return;
|
|
2040
2075
|
}
|
|
2041
2076
|
this._state === "streaming" && (this._emit("sessionStopped", {
|
|
2042
2077
|
reason: t || "remote_end",
|
|
2043
|
-
message:
|
|
2078
|
+
message: r
|
|
2044
2079
|
}), this.stopSession().catch(() => {
|
|
2045
2080
|
}));
|
|
2046
2081
|
}
|
|
@@ -2050,25 +2085,25 @@ class Be extends EventTarget {
|
|
|
2050
2085
|
if (e.sdp) {
|
|
2051
2086
|
const t = e.sdp;
|
|
2052
2087
|
if (t.type === "offer") {
|
|
2053
|
-
const
|
|
2054
|
-
if (this._micSupported =
|
|
2088
|
+
const n = ke(t.sdp);
|
|
2089
|
+
if (this._micSupported = n, this._emit("micSupported", { supported: n }), n && this._micStream)
|
|
2055
2090
|
for (const o of this._micStream.getAudioTracks())
|
|
2056
2091
|
this._pc.addTrack(o, this._micStream);
|
|
2057
2092
|
await this._pc.setRemoteDescription(new RTCSessionDescription(t));
|
|
2058
2093
|
const i = await this._pc.createAnswer();
|
|
2059
|
-
await this._pc.setLocalDescription(i), await this._sendToServer({
|
|
2094
|
+
await this._pc.setLocalDescription(i), this._outgoingAudioTrack && await this._applyOutgoingAudioTrack().catch((o) => _.warn("re-applying outgoing audio failed:", o)), await this._sendToServer({
|
|
2060
2095
|
type: "peer",
|
|
2061
2096
|
sessionId: this._sessionId,
|
|
2062
2097
|
sdp: { type: "answer", sdp: i.sdp }
|
|
2063
2098
|
});
|
|
2064
2099
|
} else
|
|
2065
2100
|
await this._pc.setRemoteDescription(new RTCSessionDescription(t));
|
|
2066
|
-
const
|
|
2067
|
-
if (
|
|
2101
|
+
const r = this._pendingRemoteIce;
|
|
2102
|
+
if (r && r.length) {
|
|
2068
2103
|
this._pendingRemoteIce = [];
|
|
2069
|
-
for (const
|
|
2104
|
+
for (const n of r)
|
|
2070
2105
|
try {
|
|
2071
|
-
await this._pc.addIceCandidate(new RTCIceCandidate(
|
|
2106
|
+
await this._pc.addIceCandidate(new RTCIceCandidate(n));
|
|
2072
2107
|
} catch (i) {
|
|
2073
2108
|
_.warn("buffered ICE candidate rejected:", i);
|
|
2074
2109
|
}
|
|
@@ -2140,30 +2175,30 @@ class Be extends EventTarget {
|
|
|
2140
2175
|
}
|
|
2141
2176
|
if (!((e.command === "wake_up" || e.command === "goto_sleep") && this._pending.settleMotion(e.command, e))) {
|
|
2142
2177
|
if (e.type === "log_line") {
|
|
2143
|
-
for (const
|
|
2178
|
+
for (const r of this._logSubscribers)
|
|
2144
2179
|
try {
|
|
2145
|
-
|
|
2146
|
-
} catch (
|
|
2147
|
-
_.error("subscribeLogs onLine threw:",
|
|
2180
|
+
r.onLine({ timestamp: e.timestamp, line: e.line });
|
|
2181
|
+
} catch (n) {
|
|
2182
|
+
_.error("subscribeLogs onLine threw:", n);
|
|
2148
2183
|
}
|
|
2149
2184
|
return;
|
|
2150
2185
|
}
|
|
2151
2186
|
if (e.type === "log_stream_error") {
|
|
2152
|
-
for (const
|
|
2153
|
-
if (typeof
|
|
2187
|
+
for (const r of this._logSubscribers)
|
|
2188
|
+
if (typeof r.onError == "function")
|
|
2154
2189
|
try {
|
|
2155
|
-
|
|
2156
|
-
} catch (
|
|
2157
|
-
_.error("subscribeLogs onError threw:",
|
|
2190
|
+
r.onError(e.error);
|
|
2191
|
+
} catch (n) {
|
|
2192
|
+
_.error("subscribeLogs onError threw:", n);
|
|
2158
2193
|
}
|
|
2159
2194
|
return;
|
|
2160
2195
|
}
|
|
2161
2196
|
if (e.command === "start_update") {
|
|
2162
2197
|
if (typeof e.error == "string") {
|
|
2163
|
-
const
|
|
2164
|
-
for (const
|
|
2198
|
+
const r = { status: "failed", error: e.error };
|
|
2199
|
+
for (const n of this._updateProgressSubscribers)
|
|
2165
2200
|
try {
|
|
2166
|
-
r
|
|
2201
|
+
n(r);
|
|
2167
2202
|
} catch (i) {
|
|
2168
2203
|
_.error("startDaemonUpdate onProgress threw:", i);
|
|
2169
2204
|
}
|
|
@@ -2171,22 +2206,22 @@ class Be extends EventTarget {
|
|
|
2171
2206
|
return;
|
|
2172
2207
|
}
|
|
2173
2208
|
if (e.type === "update_progress") {
|
|
2174
|
-
const
|
|
2209
|
+
const r = {
|
|
2175
2210
|
status: e.status,
|
|
2176
2211
|
line: typeof e.line == "string" ? e.line : void 0,
|
|
2177
2212
|
error: typeof e.error == "string" ? e.error : void 0
|
|
2178
2213
|
};
|
|
2179
|
-
for (const
|
|
2214
|
+
for (const n of this._updateProgressSubscribers)
|
|
2180
2215
|
try {
|
|
2181
|
-
r
|
|
2216
|
+
n(r);
|
|
2182
2217
|
} catch (i) {
|
|
2183
2218
|
_.error("startDaemonUpdate onProgress threw:", i);
|
|
2184
2219
|
}
|
|
2185
2220
|
return;
|
|
2186
2221
|
}
|
|
2187
2222
|
if (e.state && (t || Date.now() - this._lastPoseFrameAt >= Q)) {
|
|
2188
|
-
const
|
|
2189
|
-
|
|
2223
|
+
const r = e.state;
|
|
2224
|
+
r.head_pose && (this._robotState.head = r.head_pose.flat()), r.antennas && (this._robotState.antennas = [r.antennas[0], r.antennas[1]]), r.head_joint_positions && (this._robotState.head_joint_positions = r.head_joint_positions), typeof r.body_yaw == "number" && (this._robotState.body_yaw = r.body_yaw), r.motor_mode && (this._robotState.motor_mode = r.motor_mode), typeof r.is_move_running == "boolean" && (this._robotState.is_move_running = r.is_move_running), r.face_target && (this._robotState.face_target = r.face_target), "doa" in r && (this._robotState.doa = r.doa ?? void 0), "imu" in r && (this._robotState.imu = r.imu ?? void 0), this._emit("state", { ...this._robotState });
|
|
2190
2225
|
}
|
|
2191
2226
|
e.error && this._emit("error", { source: "robot", error: e.error }), this._pending.matchBroadcast(e);
|
|
2192
2227
|
}
|
|
@@ -2198,14 +2233,14 @@ class Be extends EventTarget {
|
|
|
2198
2233
|
if (!e.srcObject || e.paused) return;
|
|
2199
2234
|
const t = e.buffered;
|
|
2200
2235
|
if (t.length > 0) {
|
|
2201
|
-
const
|
|
2202
|
-
|
|
2236
|
+
const r = t.end(t.length - 1), n = r - e.currentTime;
|
|
2237
|
+
n > 0.5 && (_.debug(`video latency correction: was ${n.toFixed(2)}s behind`), e.currentTime = r - 0.1);
|
|
2203
2238
|
}
|
|
2204
2239
|
}, 2e3);
|
|
2205
2240
|
}
|
|
2206
2241
|
}
|
|
2207
|
-
const Pe = "pollen-robotics/reachy_mini",
|
|
2208
|
-
function
|
|
2242
|
+
const Pe = "pollen-robotics/reachy_mini", Oe = `https://api.github.com/repos/${Pe}/releases/latest`, te = "reachy.daemonLatestRelease.v1", Ne = 360 * 60 * 1e3, re = "1.8.2";
|
|
2243
|
+
function I(s) {
|
|
2209
2244
|
if (typeof s != "string") return null;
|
|
2210
2245
|
const e = s.trim().replace(/^v/i, "").match(/^(\d+)\.(\d+)\.(\d+)/);
|
|
2211
2246
|
return e ? {
|
|
@@ -2217,18 +2252,18 @@ function k(s) {
|
|
|
2217
2252
|
function H(s, e) {
|
|
2218
2253
|
return s.major - e.major || s.minor - e.minor || s.patch - e.patch;
|
|
2219
2254
|
}
|
|
2220
|
-
function
|
|
2221
|
-
const t =
|
|
2222
|
-
return !t || !
|
|
2255
|
+
function $e(s, e) {
|
|
2256
|
+
const t = I(s), r = I(e);
|
|
2257
|
+
return !t || !r ? !1 : H(t, r) < 0;
|
|
2223
2258
|
}
|
|
2224
2259
|
function qe(s, e) {
|
|
2225
|
-
const t =
|
|
2260
|
+
const t = I(s);
|
|
2226
2261
|
if (!t) return null;
|
|
2227
|
-
const
|
|
2228
|
-
return
|
|
2262
|
+
const r = I(re);
|
|
2263
|
+
return r && H(t, r) < 0 ? "block" : $e(s, e) ? "notice" : null;
|
|
2229
2264
|
}
|
|
2230
2265
|
function Ge(s) {
|
|
2231
|
-
const e =
|
|
2266
|
+
const e = I(s), t = I(re);
|
|
2232
2267
|
return !!e && !!t && H(e, t) >= 0;
|
|
2233
2268
|
}
|
|
2234
2269
|
function je() {
|
|
@@ -2246,19 +2281,19 @@ function je() {
|
|
|
2246
2281
|
}
|
|
2247
2282
|
async function Ve() {
|
|
2248
2283
|
const s = je();
|
|
2249
|
-
if (s && Date.now() - s.at <
|
|
2284
|
+
if (s && Date.now() - s.at < Ne) return s.value;
|
|
2250
2285
|
try {
|
|
2251
|
-
const e = await fetch(
|
|
2286
|
+
const e = await fetch(Oe, {
|
|
2252
2287
|
headers: { Accept: "application/vnd.github+json" }
|
|
2253
2288
|
});
|
|
2254
2289
|
if (!e.ok)
|
|
2255
2290
|
return s?.value ?? null;
|
|
2256
|
-
const t = await e.json(),
|
|
2291
|
+
const t = await e.json(), r = typeof t.tag_name == "string" ? t.tag_name : null, n = r ? r.replace(/^v/i, "") : null;
|
|
2257
2292
|
try {
|
|
2258
|
-
localStorage.setItem(te, JSON.stringify({ value:
|
|
2293
|
+
localStorage.setItem(te, JSON.stringify({ value: n, at: Date.now() }));
|
|
2259
2294
|
} catch {
|
|
2260
2295
|
}
|
|
2261
|
-
return
|
|
2296
|
+
return n;
|
|
2262
2297
|
} catch {
|
|
2263
2298
|
return s?.value ?? null;
|
|
2264
2299
|
}
|
|
@@ -2272,14 +2307,14 @@ function Fe(s) {
|
|
|
2272
2307
|
function He(s) {
|
|
2273
2308
|
const e = Fe(s);
|
|
2274
2309
|
if (!e) return null;
|
|
2275
|
-
const t = s.meta?.name ?? s.name,
|
|
2310
|
+
const t = s.meta?.name ?? s.name, r = typeof s.meta?.transport == "string" && s.meta.transport.length > 0 ? s.meta.transport : null, n = typeof s.meta?.hardware_id == "string" && s.meta.hardware_id.length > 0 ? s.meta.hardware_id : null;
|
|
2276
2311
|
return {
|
|
2277
2312
|
id: e,
|
|
2278
2313
|
meta: t ? { name: t } : void 0,
|
|
2279
2314
|
busy: s.busy === !0,
|
|
2280
2315
|
activeApp: typeof s.activeApp == "string" && s.activeApp.trim().length > 0 ? s.activeApp : null,
|
|
2281
|
-
transport:
|
|
2282
|
-
hardwareId:
|
|
2316
|
+
transport: r,
|
|
2317
|
+
hardwareId: n
|
|
2283
2318
|
};
|
|
2284
2319
|
}
|
|
2285
2320
|
async function Je(s) {
|
|
@@ -2287,9 +2322,9 @@ async function Je(s) {
|
|
|
2287
2322
|
if (!t) return { ok: !1, robots: [], reason: "No HF token" };
|
|
2288
2323
|
if (!e)
|
|
2289
2324
|
return { ok: !1, robots: [], reason: "No signaling URL" };
|
|
2290
|
-
const
|
|
2325
|
+
const r = `${e.replace(/\/$/, "")}/api/robot-status`, n = new AbortController(), i = setTimeout(() => n.abort(), xe), o = s.signal ? We([n.signal, s.signal]) : n.signal;
|
|
2291
2326
|
try {
|
|
2292
|
-
const a = await fetch(
|
|
2327
|
+
const a = await fetch(r, {
|
|
2293
2328
|
method: "GET",
|
|
2294
2329
|
headers: {
|
|
2295
2330
|
Authorization: `Bearer ${t}`,
|
|
@@ -2326,12 +2361,12 @@ function We(s) {
|
|
|
2326
2361
|
return e.signal;
|
|
2327
2362
|
}
|
|
2328
2363
|
export {
|
|
2329
|
-
|
|
2364
|
+
re as M,
|
|
2330
2365
|
Be as R,
|
|
2331
2366
|
Je as a,
|
|
2332
|
-
|
|
2367
|
+
$ as c,
|
|
2333
2368
|
qe as d,
|
|
2334
2369
|
Ve as f,
|
|
2335
|
-
|
|
2370
|
+
I as p,
|
|
2336
2371
|
Ge as s
|
|
2337
2372
|
};
|