@burdenoff/website-sdk 2026.1104.1 → 2026.1104.3
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 +45 -0
- package/dist/avatar-live/index.d.mts +2 -2
- package/dist/avatar-live/index.d.ts +2 -2
- package/dist/avatar-live/index.js +29 -4
- package/dist/avatar-live/index.js.map +1 -1
- package/dist/avatar-live/index.mjs +29 -4
- package/dist/avatar-live/index.mjs.map +1 -1
- package/dist/avatar-live-view/index.d.mts +2 -2
- package/dist/avatar-live-view/index.d.ts +2 -2
- package/dist/avatar-live-view/index.js +130 -13
- package/dist/avatar-live-view/index.js.map +1 -1
- package/dist/avatar-live-view/index.mjs +125 -8
- package/dist/avatar-live-view/index.mjs.map +1 -1
- package/dist/{chunk-K3QZGJEH.mjs → chunk-7MSB3EUI.mjs} +4 -3
- package/dist/chunk-7MSB3EUI.mjs.map +1 -0
- package/dist/{chunk-7O2I32ZN.js → chunk-WSEQ2I6I.js} +4 -3
- package/dist/chunk-WSEQ2I6I.js.map +1 -0
- package/dist/{explore-avatar-live-config-N4WhJzgS.d.mts → explore-avatar-live-config-B6_p0q1c.d.mts} +14 -1
- package/dist/{explore-avatar-live-config-CAfN5eAX.d.ts → explore-avatar-live-config-DRpS-mqQ.d.ts} +14 -1
- package/dist/index.d.mts +10 -4
- package/dist/index.d.ts +10 -4
- package/dist/index.js +10 -7
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +6 -3
- package/dist/index.mjs.map +1 -1
- package/dist/{types-CndbmBK-.d.mts → types-CXqaLlNB.d.mts} +14 -1
- package/dist/{types-CndbmBK-.d.ts → types-CXqaLlNB.d.ts} +14 -1
- package/package.json +1 -1
- package/dist/chunk-7O2I32ZN.js.map +0 -1
- package/dist/chunk-K3QZGJEH.mjs.map +0 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var
|
|
3
|
+
var chunkWSEQ2I6I_js = require('../chunk-WSEQ2I6I.js');
|
|
4
4
|
var chunkO4GS3XPZ_js = require('../chunk-O4GS3XPZ.js');
|
|
5
5
|
var chunkC6OJIHNO_js = require('../chunk-C6OJIHNO.js');
|
|
6
6
|
require('../chunk-ZSTFX7FV.js');
|
|
@@ -68,7 +68,7 @@ function readAvailability(status, body) {
|
|
|
68
68
|
const { consentVersion, maxSessionSeconds } = body;
|
|
69
69
|
const botCheck = readBotCheck(body.botCheck);
|
|
70
70
|
const questions = readQuestions(body.questions);
|
|
71
|
-
if (available !== true || typeof consentVersion !== "string" || !
|
|
71
|
+
if (available !== true || typeof consentVersion !== "string" || !chunkWSEQ2I6I_js.isAvatarVersion(consentVersion) || typeof maxSessionSeconds !== "number" || !Number.isInteger(maxSessionSeconds) || maxSessionSeconds < 1 || botCheck === null || questions === null) {
|
|
72
72
|
return INERT;
|
|
73
73
|
}
|
|
74
74
|
return {
|
|
@@ -121,7 +121,8 @@ function readCreated(body) {
|
|
|
121
121
|
endSecret,
|
|
122
122
|
endsAt,
|
|
123
123
|
join: { livekitUrl, participantToken, workerIdentity },
|
|
124
|
-
captions: { locale, text }
|
|
124
|
+
captions: { locale, text },
|
|
125
|
+
excerpt: body.excerpt === true
|
|
125
126
|
}
|
|
126
127
|
};
|
|
127
128
|
}
|
|
@@ -160,7 +161,7 @@ function deadline(timeoutMs, outer) {
|
|
|
160
161
|
};
|
|
161
162
|
}
|
|
162
163
|
async function requestAvailability(target) {
|
|
163
|
-
if (!
|
|
164
|
+
if (!chunkWSEQ2I6I_js.isAvatarSite(target.site) || !LOCALE.test(target.locale)) return INERT;
|
|
164
165
|
const query = new URLSearchParams({
|
|
165
166
|
site: target.site,
|
|
166
167
|
locale: target.locale
|
|
@@ -294,6 +295,7 @@ var EN = {
|
|
|
294
295
|
failed: "The live avatar couldn't start.",
|
|
295
296
|
interrupted: "The live avatar stopped early.",
|
|
296
297
|
answerInChat: "The full answer is in Chat.",
|
|
298
|
+
excerpt: "The avatar reads the first part of this answer. The full answer is in Chat.",
|
|
297
299
|
backToChat: "Back to Chat",
|
|
298
300
|
busy: "The live avatar is busy right now. Please try again in a few minutes.",
|
|
299
301
|
limits: "The live avatar has reached its limit for now. Please try again later.",
|
|
@@ -351,6 +353,8 @@ var ZH = {
|
|
|
351
353
|
failed: "\u5B9E\u65F6\u865A\u62DF\u5F62\u8C61\u65E0\u6CD5\u542F\u52A8\u3002",
|
|
352
354
|
interrupted: "\u5B9E\u65F6\u865A\u62DF\u5F62\u8C61\u63D0\u524D\u505C\u6B62\u4E86\u3002",
|
|
353
355
|
answerInChat: "\u5B8C\u6574\u56DE\u7B54\u5728\u804A\u5929\u4E2D\u3002",
|
|
356
|
+
// TRANSLATION REVIEW PENDING (BOFF-9797): draft, the note for a part-read answer (Stage B).
|
|
357
|
+
excerpt: "\u865A\u62DF\u5F62\u8C61\u6717\u8BFB\u8FD9\u4E2A\u56DE\u7B54\u7684\u7B2C\u4E00\u90E8\u5206\u3002\u5B8C\u6574\u56DE\u7B54\u5728\u804A\u5929\u4E2D\u3002",
|
|
354
358
|
backToChat: "\u8FD4\u56DE\u804A\u5929",
|
|
355
359
|
busy: "\u5B9E\u65F6\u865A\u62DF\u5F62\u8C61\u76EE\u524D\u7E41\u5FD9\uFF0C\u8BF7\u51E0\u5206\u949F\u540E\u518D\u8BD5\u3002",
|
|
356
360
|
limits: "\u5B9E\u65F6\u865A\u62DF\u5F62\u8C61\u6682\u65F6\u5DF2\u8FBE\u5230\u4F7F\u7528\u4E0A\u9650\uFF0C\u8BF7\u7A0D\u540E\u518D\u8BD5\u3002",
|
|
@@ -410,6 +414,8 @@ var HI = {
|
|
|
410
414
|
failed: "\u0932\u093E\u0907\u0935 \u0905\u0935\u0924\u093E\u0930 \u0936\u0941\u0930\u0942 \u0928\u0939\u0940\u0902 \u0939\u094B \u0938\u0915\u093E\u0964",
|
|
411
415
|
interrupted: "\u0932\u093E\u0907\u0935 \u0905\u0935\u0924\u093E\u0930 \u092C\u0940\u091A \u092E\u0947\u0902 \u0939\u0940 \u0930\u0941\u0915 \u0917\u092F\u093E\u0964",
|
|
412
416
|
answerInChat: "\u092A\u0942\u0930\u093E \u0909\u0924\u094D\u0924\u0930 \u091A\u0948\u091F \u092E\u0947\u0902 \u0939\u0948\u0964",
|
|
417
|
+
// TRANSLATION REVIEW PENDING (BOFF-9797): draft, the note for a part-read answer (Stage B).
|
|
418
|
+
excerpt: "\u0905\u0935\u0924\u093E\u0930 \u0907\u0938 \u0909\u0924\u094D\u0924\u0930 \u0915\u093E \u092A\u0939\u0932\u093E \u092D\u093E\u0917 \u092A\u0922\u093C\u0924\u093E \u0939\u0948\u0964 \u092A\u0942\u0930\u093E \u0909\u0924\u094D\u0924\u0930 \u091A\u0948\u091F \u092E\u0947\u0902 \u0939\u0948\u0964",
|
|
413
419
|
backToChat: "\u091A\u0948\u091F \u092A\u0930 \u0935\u093E\u092A\u0938 \u091C\u093E\u090F\u0901",
|
|
414
420
|
busy: "\u0932\u093E\u0907\u0935 \u0905\u0935\u0924\u093E\u0930 \u0905\u092D\u0940 \u0935\u094D\u092F\u0938\u094D\u0924 \u0939\u0948\u0964 \u0915\u0943\u092A\u092F\u093E \u0915\u0941\u091B \u092E\u093F\u0928\u091F \u092C\u093E\u0926 \u092B\u093F\u0930 \u0915\u094B\u0936\u093F\u0936 \u0915\u0930\u0947\u0902\u0964",
|
|
415
421
|
limits: "\u0932\u093E\u0907\u0935 \u0905\u0935\u0924\u093E\u0930 \u0905\u092D\u0940 \u0905\u092A\u0928\u0940 \u0938\u0940\u092E\u093E \u0924\u0915 \u092A\u0939\u0941\u0901\u091A \u0917\u092F\u093E \u0939\u0948\u0964 \u0915\u0943\u092A\u092F\u093E \u092C\u093E\u0926 \u092E\u0947\u0902 \u092B\u093F\u0930 \u0915\u094B\u0936\u093F\u0936 \u0915\u0930\u0947\u0902\u0964",
|
|
@@ -469,6 +475,8 @@ var ES = {
|
|
|
469
475
|
failed: "No se pudo iniciar el avatar en vivo.",
|
|
470
476
|
interrupted: "El avatar en vivo se detuvo antes de tiempo.",
|
|
471
477
|
answerInChat: "La respuesta completa est\xE1 en el chat.",
|
|
478
|
+
// TRANSLATION REVIEW PENDING (BOFF-9797): draft, the note for a part-read answer (Stage B).
|
|
479
|
+
excerpt: "El avatar lee la primera parte de esta respuesta. La respuesta completa est\xE1 en el chat.",
|
|
472
480
|
backToChat: "Volver al chat",
|
|
473
481
|
busy: "El avatar en vivo est\xE1 ocupado en este momento. Vuelve a intentarlo en unos minutos.",
|
|
474
482
|
limits: "El avatar en vivo ha alcanzado su l\xEDmite por ahora. Vuelve a intentarlo m\xE1s tarde.",
|
|
@@ -528,6 +536,8 @@ var AR = {
|
|
|
528
536
|
failed: "\u062A\u0639\u0630\u0651\u0631 \u0628\u062F\u0621 \u0627\u0644\u0623\u0641\u0627\u062A\u0627\u0631 \u0627\u0644\u0645\u0628\u0627\u0634\u0631.",
|
|
529
537
|
interrupted: "\u062A\u0648\u0642\u0641 \u0627\u0644\u0623\u0641\u0627\u062A\u0627\u0631 \u0627\u0644\u0645\u0628\u0627\u0634\u0631 \u0642\u0628\u0644 \u0623\u0646 \u064A\u0646\u062A\u0647\u064A.",
|
|
530
538
|
answerInChat: "\u0627\u0644\u0625\u062C\u0627\u0628\u0629 \u0627\u0644\u0643\u0627\u0645\u0644\u0629 \u0645\u0648\u062C\u0648\u062F\u0629 \u0641\u064A \u0627\u0644\u062F\u0631\u062F\u0634\u0629.",
|
|
539
|
+
// TRANSLATION REVIEW PENDING (BOFF-9797): draft, the note for a part-read answer (Stage B).
|
|
540
|
+
excerpt: "\u064A\u0642\u0631\u0623 \u0627\u0644\u0623\u0641\u0627\u062A\u0627\u0631 \u0627\u0644\u062C\u0632\u0621 \u0627\u0644\u0623\u0648\u0644 \u0645\u0646 \u0647\u0630\u0647 \u0627\u0644\u0625\u062C\u0627\u0628\u0629. \u0627\u0644\u0625\u062C\u0627\u0628\u0629 \u0627\u0644\u0643\u0627\u0645\u0644\u0629 \u0645\u0648\u062C\u0648\u062F\u0629 \u0641\u064A \u0627\u0644\u062F\u0631\u062F\u0634\u0629.",
|
|
531
541
|
backToChat: "\u0627\u0644\u0639\u0648\u062F\u0629 \u0625\u0644\u0649 \u0627\u0644\u062F\u0631\u062F\u0634\u0629",
|
|
532
542
|
busy: "\u0627\u0644\u0623\u0641\u0627\u062A\u0627\u0631 \u0627\u0644\u0645\u0628\u0627\u0634\u0631 \u0645\u0634\u063A\u0648\u0644 \u0627\u0644\u0622\u0646. \u064A\u064F\u0631\u062C\u0649 \u0627\u0644\u0645\u062D\u0627\u0648\u0644\u0629 \u0645\u0631\u0629 \u0623\u062E\u0631\u0649 \u0628\u0639\u062F \u0628\u0636\u0639 \u062F\u0642\u0627\u0626\u0642.",
|
|
533
543
|
limits: "\u0628\u0644\u063A \u0627\u0644\u0623\u0641\u0627\u062A\u0627\u0631 \u0627\u0644\u0645\u0628\u0627\u0634\u0631 \u062D\u062F\u0651\u0647 \u0641\u064A \u0627\u0644\u0648\u0642\u062A \u0627\u0644\u062D\u0627\u0644\u064A. \u064A\u064F\u0631\u062C\u0649 \u0627\u0644\u0645\u062D\u0627\u0648\u0644\u0629 \u0644\u0627\u062D\u0642\u064B\u0627.",
|
|
@@ -587,6 +597,8 @@ var TA = {
|
|
|
587
597
|
failed: "\u0BA8\u0BC7\u0BB0\u0BB2\u0BC8 \u0B85\u0BB5\u0BA4\u0BBE\u0BB0\u0BC8\u0BA4\u0BCD \u0BA4\u0BCA\u0B9F\u0B99\u0BCD\u0B95 \u0BAE\u0BC1\u0B9F\u0BBF\u0BAF\u0BB5\u0BBF\u0BB2\u0BCD\u0BB2\u0BC8.",
|
|
588
598
|
interrupted: "\u0BA8\u0BC7\u0BB0\u0BB2\u0BC8 \u0B85\u0BB5\u0BA4\u0BBE\u0BB0\u0BCD \u0B87\u0B9F\u0BC8\u0BAF\u0BBF\u0BB2\u0BC7\u0BAF\u0BC7 \u0BA8\u0BBF\u0BA9\u0BCD\u0BB1\u0BC1\u0BB5\u0BBF\u0B9F\u0BCD\u0B9F\u0BA4\u0BC1.",
|
|
589
599
|
answerInChat: "\u0BAE\u0BC1\u0BB4\u0BC1\u0BAA\u0BCD \u0BAA\u0BA4\u0BBF\u0BB2\u0BCD \u0B85\u0BB0\u0B9F\u0BCD\u0B9F\u0BC8\u0BAF\u0BBF\u0BB2\u0BCD \u0B89\u0BB3\u0BCD\u0BB3\u0BA4\u0BC1.",
|
|
600
|
+
// TRANSLATION REVIEW PENDING (BOFF-9797): draft, the note for a part-read answer (Stage B).
|
|
601
|
+
excerpt: "\u0B85\u0BB5\u0BA4\u0BBE\u0BB0\u0BCD \u0B87\u0BA8\u0BCD\u0BA4\u0BAA\u0BCD \u0BAA\u0BA4\u0BBF\u0BB2\u0BBF\u0BA9\u0BCD \u0BAE\u0BC1\u0BA4\u0BB2\u0BCD \u0BAA\u0B95\u0BC1\u0BA4\u0BBF\u0BAF\u0BC8\u0BAA\u0BCD \u0BAA\u0B9F\u0BBF\u0B95\u0BCD\u0B95\u0BBF\u0BB1\u0BA4\u0BC1. \u0BAE\u0BC1\u0BB4\u0BC1\u0BAA\u0BCD \u0BAA\u0BA4\u0BBF\u0BB2\u0BCD \u0B85\u0BB0\u0B9F\u0BCD\u0B9F\u0BC8\u0BAF\u0BBF\u0BB2\u0BCD \u0B89\u0BB3\u0BCD\u0BB3\u0BA4\u0BC1.",
|
|
590
602
|
backToChat: "\u0B85\u0BB0\u0B9F\u0BCD\u0B9F\u0BC8\u0B95\u0BCD\u0B95\u0BC1\u0BA4\u0BCD \u0BA4\u0BBF\u0BB0\u0BC1\u0BAE\u0BCD\u0BAA\u0BC1",
|
|
591
603
|
busy: "\u0BA8\u0BC7\u0BB0\u0BB2\u0BC8 \u0B85\u0BB5\u0BA4\u0BBE\u0BB0\u0BCD \u0B87\u0BAA\u0BCD\u0BAA\u0BCB\u0BA4\u0BC1 \u0BB5\u0BC7\u0BB1\u0BC1 \u0BAA\u0BAF\u0BA9\u0BCD\u0BAA\u0BBE\u0B9F\u0BCD\u0B9F\u0BBF\u0BB2\u0BCD \u0B89\u0BB3\u0BCD\u0BB3\u0BA4\u0BC1. \u0B9A\u0BBF\u0BB2 \u0BA8\u0BBF\u0BAE\u0BBF\u0B9F\u0B99\u0BCD\u0B95\u0BB3\u0BBF\u0BB2\u0BCD \u0BAE\u0BC0\u0BA3\u0BCD\u0B9F\u0BC1\u0BAE\u0BCD \u0BAE\u0BC1\u0BAF\u0BB2\u0BB5\u0BC1\u0BAE\u0BCD.",
|
|
592
604
|
limits: "\u0BA8\u0BC7\u0BB0\u0BB2\u0BC8 \u0B85\u0BB5\u0BA4\u0BBE\u0BB0\u0BCD \u0BA4\u0BB1\u0BCD\u0BAA\u0BCB\u0BA4\u0BC8\u0B95\u0BCD\u0B95\u0BC1\u0BA4\u0BCD \u0BA4\u0BA9\u0BCD \u0BB5\u0BB0\u0BAE\u0BCD\u0BAA\u0BC8 \u0B8E\u0B9F\u0BCD\u0B9F\u0BBF\u0BB5\u0BBF\u0B9F\u0BCD\u0B9F\u0BA4\u0BC1. \u0BAA\u0BBF\u0BB1\u0B95\u0BC1 \u0BAE\u0BC0\u0BA3\u0BCD\u0B9F\u0BC1\u0BAE\u0BCD \u0BAE\u0BC1\u0BAF\u0BB2\u0BB5\u0BC1\u0BAE\u0BCD.",
|
|
@@ -734,10 +746,46 @@ var CONSENT = /* @__PURE__ */ new Map([
|
|
|
734
746
|
questions: "any"
|
|
735
747
|
}
|
|
736
748
|
}
|
|
749
|
+
],
|
|
750
|
+
[
|
|
751
|
+
// Stage B (operator decision 2026-11-04): web-consent-2026-11-05 with only its timing sentence changed. A session
|
|
752
|
+
// lasts up to three minutes, sized by the server to the answer's audio; an answer longer than that is read in part,
|
|
753
|
+
// which the avatar says and the Avatar tab notes (`excerpt`), and the full answer stays in Chat. A cap still
|
|
754
|
+
// applies, so the words never say every answer is read whole (gitops docs/avatar-web/en-web-consent-2026-11-12-b.txt).
|
|
755
|
+
"web-consent-2026-11-12-b",
|
|
756
|
+
{
|
|
757
|
+
en: {
|
|
758
|
+
title: "Live AI avatar (beta)",
|
|
759
|
+
introProduct: null,
|
|
760
|
+
intro: "This is an AI avatar, not a real person. It reads aloud the first answer in a new chat started in the Avatar tab, provided it passes the speech checks, whether you chose a suggested question or typed your own. It reads for up to three minutes; if an answer is longer, it reads the first part, says so, and the full answer stays in Chat. The answer is AI-generated and can be wrong. Don't put personal details in a question you type.",
|
|
761
|
+
processing: "When you start, Cloudflare checks for bots. The answer text goes to Google to create the voice. Our server sends that voice through LiveKit to Protoface, which makes the avatar video streamed through LiveKit. Your browser connects to LiveKit, which sees your IP address.",
|
|
762
|
+
storage: "Your microphone and camera are not used. We do not record the live session or store the generated voice. We keep a record of this consent. The privacy notice explains our safeguards, storage periods and the providers' processing. For people aged eighteen and over.",
|
|
763
|
+
privacyLink: "How we handle this",
|
|
764
|
+
botCheck: "turnstile",
|
|
765
|
+
questions: "any"
|
|
766
|
+
}
|
|
767
|
+
}
|
|
768
|
+
],
|
|
769
|
+
[
|
|
770
|
+
// The words of web-consent-2026-11-12-b without "When you start, Cloudflare checks for bots.", for a server that runs
|
|
771
|
+
// no bot check (gitops docs/avatar-web/en-web-consent-2026-11-13-b.txt).
|
|
772
|
+
"web-consent-2026-11-13-b",
|
|
773
|
+
{
|
|
774
|
+
en: {
|
|
775
|
+
title: "Live AI avatar (beta)",
|
|
776
|
+
introProduct: null,
|
|
777
|
+
intro: "This is an AI avatar, not a real person. It reads aloud the first answer in a new chat started in the Avatar tab, provided it passes the speech checks, whether you chose a suggested question or typed your own. It reads for up to three minutes; if an answer is longer, it reads the first part, says so, and the full answer stays in Chat. The answer is AI-generated and can be wrong. Don't put personal details in a question you type.",
|
|
778
|
+
processing: "The answer text goes to Google to create the voice. Our server sends that voice through LiveKit to Protoface, which makes the avatar video streamed through LiveKit. Your browser connects to LiveKit, which sees your IP address.",
|
|
779
|
+
storage: "Your microphone and camera are not used. We do not record the live session or store the generated voice. We keep a record of this consent. The privacy notice explains our safeguards, storage periods and the providers' processing. For people aged eighteen and over.",
|
|
780
|
+
privacyLink: "How we handle this",
|
|
781
|
+
botCheck: "off",
|
|
782
|
+
questions: "any"
|
|
783
|
+
}
|
|
784
|
+
}
|
|
737
785
|
]
|
|
738
786
|
]);
|
|
739
787
|
function avatarConsentCopy(version, locale) {
|
|
740
|
-
if (!
|
|
788
|
+
if (!chunkWSEQ2I6I_js.isAvatarLiveLocaleReviewed(locale)) return null;
|
|
741
789
|
return CONSENT.get(version)?.[locale] ?? null;
|
|
742
790
|
}
|
|
743
791
|
|
|
@@ -859,6 +907,8 @@ var PRIVACY_HREF = "/privacy#live-avatar";
|
|
|
859
907
|
var SPEAKER_WAIT_MS = 3e4;
|
|
860
908
|
var END_GRACE_MS = 1e4;
|
|
861
909
|
var CLOCK_TOLERANCE_MS = 5e3;
|
|
910
|
+
var UNHEARD_GRACE_MS = 5e3;
|
|
911
|
+
var PLAYOUT_TAIL_MS = 5e3;
|
|
862
912
|
var SERVICE_MAX_AGE_MS = 15 * 6e4;
|
|
863
913
|
var ANSWER_OFFER_MS = SERVICE_MAX_AGE_MS - 6e4;
|
|
864
914
|
var MAX_TIMER_MS = 2147483647;
|
|
@@ -868,6 +918,12 @@ var USED_ON_KEY = "boff.explore.avatarUsedOn";
|
|
|
868
918
|
var PRIMARY = '[data-avatar-primary], [data-boff-explore="panel-continue-chat"]';
|
|
869
919
|
var IDLE = { name: "idle" };
|
|
870
920
|
var INERT2 = { name: "inert" };
|
|
921
|
+
function stopAttending(handle) {
|
|
922
|
+
if (handle.unheard !== null) clearTimeout(handle.unheard);
|
|
923
|
+
if (handle.tail !== null) clearTimeout(handle.tail);
|
|
924
|
+
handle.unheard = null;
|
|
925
|
+
handle.tail = null;
|
|
926
|
+
}
|
|
871
927
|
var REFUSAL_TEXT = {
|
|
872
928
|
busy: "busy",
|
|
873
929
|
limits: "limits",
|
|
@@ -1151,6 +1207,7 @@ function AvatarLiveView({
|
|
|
1151
1207
|
const handle = sessionRef.current;
|
|
1152
1208
|
if (!handle || handle.done) return;
|
|
1153
1209
|
handle.done = true;
|
|
1210
|
+
stopAttending(handle);
|
|
1154
1211
|
sessionRef.current = null;
|
|
1155
1212
|
if (reason !== null) {
|
|
1156
1213
|
sendEnd({
|
|
@@ -1180,6 +1237,33 @@ function AvatarLiveView({
|
|
|
1180
1237
|
}
|
|
1181
1238
|
go({ name: "live", session: current.session });
|
|
1182
1239
|
}, [go]);
|
|
1240
|
+
const attend = react.useCallback(() => {
|
|
1241
|
+
const handle = sessionRef.current;
|
|
1242
|
+
if (!handle || handle.done || latest.current.live.endUnattended !== true) {
|
|
1243
|
+
return;
|
|
1244
|
+
}
|
|
1245
|
+
const current = phaseRef.current.name;
|
|
1246
|
+
if (current !== "pending" && current !== "live") return;
|
|
1247
|
+
const away = !inSight();
|
|
1248
|
+
if (away && handle.playedOut && current === "live") {
|
|
1249
|
+
finish("finished", "user");
|
|
1250
|
+
return;
|
|
1251
|
+
}
|
|
1252
|
+
if (!(away && handle.soundHeld && handle.voiceArrived)) {
|
|
1253
|
+
if (handle.unheard !== null) {
|
|
1254
|
+
clearTimeout(handle.unheard);
|
|
1255
|
+
handle.unheard = null;
|
|
1256
|
+
}
|
|
1257
|
+
return;
|
|
1258
|
+
}
|
|
1259
|
+
if (handle.unheard !== null) return;
|
|
1260
|
+
handle.unheard = setTimeout(() => {
|
|
1261
|
+
handle.unheard = null;
|
|
1262
|
+
if (sessionRef.current === handle && !handle.done && latest.current.live.endUnattended === true && handle.soundHeld && handle.voiceArrived && !inSight()) {
|
|
1263
|
+
finish("interrupted", "user");
|
|
1264
|
+
}
|
|
1265
|
+
}, UNHEARD_GRACE_MS);
|
|
1266
|
+
}, [finish, inSight]);
|
|
1183
1267
|
const cancelStart = react.useCallback((reason) => {
|
|
1184
1268
|
const run = startRef.current;
|
|
1185
1269
|
if (!run) return;
|
|
@@ -1207,7 +1291,7 @@ function AvatarLiveView({
|
|
|
1207
1291
|
go(INERT2);
|
|
1208
1292
|
return;
|
|
1209
1293
|
}
|
|
1210
|
-
if (result.offer.botCheck === "turnstile" &&
|
|
1294
|
+
if (result.offer.botCheck === "turnstile" && chunkWSEQ2I6I_js.turnstileSiteKeyOf(live2) === null) {
|
|
1211
1295
|
setMode("suggested");
|
|
1212
1296
|
go(INERT2);
|
|
1213
1297
|
return;
|
|
@@ -1256,13 +1340,22 @@ function AvatarLiveView({
|
|
|
1256
1340
|
joined: null,
|
|
1257
1341
|
endsAt,
|
|
1258
1342
|
speakerArrived: false,
|
|
1343
|
+
voiceArrived: false,
|
|
1344
|
+
soundHeld: false,
|
|
1345
|
+
playedOut: false,
|
|
1346
|
+
unheard: null,
|
|
1347
|
+
tail: null,
|
|
1259
1348
|
done: false
|
|
1260
1349
|
};
|
|
1261
1350
|
setBlocked(false);
|
|
1262
1351
|
setNow(received);
|
|
1263
1352
|
go({
|
|
1264
1353
|
name: "pending",
|
|
1265
|
-
session: {
|
|
1354
|
+
session: {
|
|
1355
|
+
endsAt,
|
|
1356
|
+
captions: session.captions,
|
|
1357
|
+
excerpt: session.excerpt
|
|
1358
|
+
}
|
|
1266
1359
|
});
|
|
1267
1360
|
},
|
|
1268
1361
|
[go]
|
|
@@ -1335,7 +1428,7 @@ function AvatarLiveView({
|
|
|
1335
1428
|
return;
|
|
1336
1429
|
}
|
|
1337
1430
|
const refusedFrom = exchangeAtStart.offerUntil - ANSWER_OFFER_MS + SERVICE_MAX_AGE_MS;
|
|
1338
|
-
const siteKey = offer.botCheck === "turnstile" ?
|
|
1431
|
+
const siteKey = offer.botCheck === "turnstile" ? chunkWSEQ2I6I_js.turnstileSiteKeyOf(live2) : null;
|
|
1339
1432
|
if (offer.botCheck === "turnstile" && (siteKey === null || !canBindBotCheck())) {
|
|
1340
1433
|
go(INERT2);
|
|
1341
1434
|
return;
|
|
@@ -1581,6 +1674,9 @@ function AvatarLiveView({
|
|
|
1581
1674
|
check();
|
|
1582
1675
|
}
|
|
1583
1676
|
}, [showing, behindChat, check, leave, offeredNow]);
|
|
1677
|
+
react.useEffect(() => {
|
|
1678
|
+
attend();
|
|
1679
|
+
}, [showing, attend]);
|
|
1584
1680
|
react.useEffect(() => {
|
|
1585
1681
|
if (askedLocale.current === locale) return;
|
|
1586
1682
|
askedLocale.current = locale;
|
|
@@ -1667,12 +1763,29 @@ function AvatarLiveView({
|
|
|
1667
1763
|
const wasLive = phaseRef.current.name === "live";
|
|
1668
1764
|
switch (event.type) {
|
|
1669
1765
|
case "speaker-track":
|
|
1670
|
-
if (event.kind !== "video")
|
|
1766
|
+
if (event.kind !== "video") {
|
|
1767
|
+
handle.voiceArrived = true;
|
|
1768
|
+
attend();
|
|
1769
|
+
return;
|
|
1770
|
+
}
|
|
1671
1771
|
handle.speakerArrived = true;
|
|
1672
1772
|
if (!inSight()) goLive();
|
|
1673
1773
|
return;
|
|
1674
1774
|
case "playback-blocked":
|
|
1675
1775
|
setBlocked(event.blocked);
|
|
1776
|
+
handle.soundHeld = event.sound ?? event.blocked;
|
|
1777
|
+
attend();
|
|
1778
|
+
return;
|
|
1779
|
+
case "speech-ended":
|
|
1780
|
+
if (latest.current.live.endUnattended !== true || handle.tail !== null || handle.playedOut) {
|
|
1781
|
+
return;
|
|
1782
|
+
}
|
|
1783
|
+
handle.tail = setTimeout(() => {
|
|
1784
|
+
handle.tail = null;
|
|
1785
|
+
if (sessionRef.current !== handle || handle.done) return;
|
|
1786
|
+
handle.playedOut = true;
|
|
1787
|
+
attend();
|
|
1788
|
+
}, PLAYOUT_TAIL_MS);
|
|
1676
1789
|
return;
|
|
1677
1790
|
case "speaker-left":
|
|
1678
1791
|
finish(
|
|
@@ -1686,7 +1799,7 @@ function AvatarLiveView({
|
|
|
1686
1799
|
return;
|
|
1687
1800
|
}
|
|
1688
1801
|
},
|
|
1689
|
-
[finish, goLive, inSight]
|
|
1802
|
+
[attend, finish, goLive, inSight]
|
|
1690
1803
|
);
|
|
1691
1804
|
react.useEffect(() => {
|
|
1692
1805
|
if (phase.name !== "pending") return;
|
|
@@ -1773,10 +1886,12 @@ function AvatarLiveView({
|
|
|
1773
1886
|
const onVisibility = () => {
|
|
1774
1887
|
if (document.visibilityState === "hidden") {
|
|
1775
1888
|
leave("hidden");
|
|
1889
|
+
attend();
|
|
1776
1890
|
return;
|
|
1777
1891
|
}
|
|
1778
1892
|
const current = phaseRef.current.name;
|
|
1779
1893
|
if (current === "pending" || current === "live") setNow(Date.now());
|
|
1894
|
+
attend();
|
|
1780
1895
|
};
|
|
1781
1896
|
window.addEventListener("pagehide", onPageHide);
|
|
1782
1897
|
document.addEventListener("visibilitychange", onVisibility);
|
|
@@ -1784,7 +1899,7 @@ function AvatarLiveView({
|
|
|
1784
1899
|
window.removeEventListener("pagehide", onPageHide);
|
|
1785
1900
|
document.removeEventListener("visibilitychange", onVisibility);
|
|
1786
1901
|
};
|
|
1787
|
-
}, [leave]);
|
|
1902
|
+
}, [attend, leave]);
|
|
1788
1903
|
react.useEffect(
|
|
1789
1904
|
() => () => {
|
|
1790
1905
|
const controller = checkRef.current;
|
|
@@ -1803,6 +1918,7 @@ function AvatarLiveView({
|
|
|
1803
1918
|
sessionRef.current = null;
|
|
1804
1919
|
if (handle && !handle.done) {
|
|
1805
1920
|
handle.done = true;
|
|
1921
|
+
stopAttending(handle);
|
|
1806
1922
|
sendEnd({
|
|
1807
1923
|
base: handle.base,
|
|
1808
1924
|
headers: handle.headers,
|
|
@@ -2061,6 +2177,7 @@ function AvatarLiveView({
|
|
|
2061
2177
|
]
|
|
2062
2178
|
}
|
|
2063
2179
|
);
|
|
2180
|
+
const speakingLine = (session) => session.excerpt ? S.excerpt : S.speaking;
|
|
2064
2181
|
const liveBody = (session) => /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
2065
2182
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2066
2183
|
"section",
|
|
@@ -2274,7 +2391,7 @@ function AvatarLiveView({
|
|
|
2274
2391
|
break;
|
|
2275
2392
|
case "pending":
|
|
2276
2393
|
case "live":
|
|
2277
|
-
status = phase.name === "live" ?
|
|
2394
|
+
status = phase.name === "live" ? speakingLine(phase.session) : S.connecting;
|
|
2278
2395
|
top2 = badge;
|
|
2279
2396
|
media2 = liveMedia(phase.name === "live");
|
|
2280
2397
|
body2 = liveBody(phase.session);
|
|
@@ -2400,7 +2517,7 @@ function AvatarLiveView({
|
|
|
2400
2517
|
"bot-check": S.botCheck,
|
|
2401
2518
|
creating: S.connecting,
|
|
2402
2519
|
pending: S.connecting,
|
|
2403
|
-
live:
|
|
2520
|
+
live: phase.name === "live" ? speakingLine(phase.session) : "",
|
|
2404
2521
|
ended: phase.name === "ended" ? S[phase.how] : ""
|
|
2405
2522
|
};
|
|
2406
2523
|
const outcome = phase.name === "needs-answer" || phase.name === "refused" || phase.name === "ended";
|