@burdenoff/website-sdk 2026.1101.4 → 2026.1102.1
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 +59 -20
- package/dist/avatar-live-view/index.d.mts +1 -1
- package/dist/avatar-live-view/index.d.ts +1 -1
- package/dist/avatar-live-view/index.js +71 -24
- package/dist/avatar-live-view/index.js.map +1 -1
- package/dist/avatar-live-view/index.mjs +69 -22
- package/dist/avatar-live-view/index.mjs.map +1 -1
- package/dist/{chunk-23H4JUL4.js → chunk-OIQHIGGU.js} +20 -3
- package/dist/chunk-OIQHIGGU.js.map +1 -0
- package/dist/{chunk-BX2USEWF.mjs → chunk-QOHPLTGT.mjs} +19 -4
- package/dist/chunk-QOHPLTGT.mjs.map +1 -0
- package/dist/{explore-avatar-live-config-B171o1Yo.d.ts → explore-avatar-live-config-C1ILEcY8.d.ts} +16 -4
- package/dist/{explore-avatar-live-config-BGsGwbcq.d.mts → explore-avatar-live-config-D-hO90-A.d.mts} +16 -4
- package/dist/index.d.mts +17 -7
- package/dist/index.d.ts +17 -7
- package/dist/index.js +18 -15
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +15 -12
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
- package/dist/chunk-23H4JUL4.js.map +0 -1
- package/dist/chunk-BX2USEWF.mjs.map +0 -1
package/README.md
CHANGED
|
@@ -298,8 +298,9 @@ publishes audio, video or data, and it sends the avatar nothing to say.
|
|
|
298
298
|
live: {
|
|
299
299
|
site: 'healthybowl',
|
|
300
300
|
load: () => import('@burdenoff/website-sdk/avatar-live'),
|
|
301
|
-
turnstileSiteKey: TURNSTILE_SITE_KEY,
|
|
302
301
|
manifestVersion: 'hb-en-1', // the version of `suggestedQuestions`
|
|
302
|
+
// Optional: used only where the server checks for bots (see "The bot check is the server's setting").
|
|
303
|
+
turnstileSiteKey: TURNSTILE_SITE_KEY,
|
|
303
304
|
},
|
|
304
305
|
}}
|
|
305
306
|
/>
|
|
@@ -339,7 +340,24 @@ publishes audio, video or data, and it sends the avatar nothing to say.
|
|
|
339
340
|
- **Needs the panel under an `ExploreChatProvider`.** The live avatar reads the
|
|
340
341
|
provider's conversation. Without a provider, on a shared (read-only)
|
|
341
342
|
conversation, in a locale whose strings have not been reviewed yet (English
|
|
342
|
-
only, for now), or with an incomplete `live
|
|
343
|
+
only, for now), or with an incomplete `live` (no `site`, `load` or
|
|
344
|
+
`manifestVersion`, or a `turnstileSiteKey` or `allowTestSiteKey` of the wrong
|
|
345
|
+
shape), the Avatar view stays as it was.
|
|
346
|
+
- **The bot check is the server's setting (web API contract v1.2, additive).**
|
|
347
|
+
The availability answer says whether the server checks for bots when a
|
|
348
|
+
session is created: `"botCheck": {"mode": "off"}` or
|
|
349
|
+
`{"mode": "turnstile"}`. With `off`, Start loads the room module and creates
|
|
350
|
+
the session, and nothing else: no Cloudflare script, no widget, no WebCrypto
|
|
351
|
+
needed and no `x-web-avatar-bot-token` header; the server's own guards and
|
|
352
|
+
caps decide. With `turnstile`, Start runs the Cloudflare Turnstile check with
|
|
353
|
+
the page's own `turnstileSiteKey`, as before; without a key the page may use
|
|
354
|
+
(none, or one of Cloudflare's test keys where `allowTestSiteKey` is `false`)
|
|
355
|
+
the Avatar view stays as it was. A server older than v1.2 sends no `botCheck`
|
|
356
|
+
and always checks, so it is read as `turnstile`. Any other `botCheck` (an
|
|
357
|
+
unknown mode, another field, another shape) leaves the view as it was. So
|
|
358
|
+
turning the bot check on or off is a server config change: a site needs no
|
|
359
|
+
new build for it, as long as its build carries a site key for `turnstile` and
|
|
360
|
+
its CSP allows Cloudflare (below).
|
|
343
361
|
- **One answer: the first, to a suggested question.** The avatar service
|
|
344
362
|
accepts a conversation only when it holds exactly two messages: the first user
|
|
345
363
|
message (a suggested question) and the first assistant answer, completed. The
|
|
@@ -356,8 +374,8 @@ publishes audio, video or data, and it sends the avatar nothing to say.
|
|
|
356
374
|
the conversation has its first answer, a consent card explains what happens
|
|
357
375
|
and links to `/privacy#live-avatar`; with no answer yet, the view asks the
|
|
358
376
|
visitor to choose a suggested question in Chat first. Start runs a
|
|
359
|
-
Cloudflare Turnstile check (action `avatar_start`)
|
|
360
|
-
joins its room: the video, the captions, an "AI avatar · not a real person"
|
|
377
|
+
Cloudflare Turnstile check (action `avatar_start`) where the server checks
|
|
378
|
+
for bots, creates the session and joins its room: the video, the captions, an "AI avatar · not a real person"
|
|
361
379
|
badge, a countdown, Stop and Continue in Chat. Where a browser holds sound
|
|
362
380
|
back (Safari, iOS), a "Tap to turn on sound" button appears. A refusal (busy,
|
|
363
381
|
limits, region, language, paused, a question the avatar cannot read) is one
|
|
@@ -379,6 +397,14 @@ publishes audio, video or data, and it sends the avatar nothing to say.
|
|
|
379
397
|
digest for all of them (the card's title, intro, processing, storage and
|
|
380
398
|
privacy-link lines, each ending with a line feed: 760 bytes, SHA-256
|
|
381
399
|
`2e02b051ceb1163c14bc58fa63a954a12c0d1f2695029a6d4805922d74c793f7`).
|
|
400
|
+
`web-consent-2026-11-03` is the same card without "When you start,
|
|
401
|
+
Cloudflare checks for bots.", for a server whose bot check is `off` (716
|
|
402
|
+
bytes, SHA-256
|
|
403
|
+
`bb7516df3cf3a910c6ec1623391f859e6c48e7e7d305d4fb333f18d4115da203`).
|
|
404
|
+
Each version says which bot check its words describe, and the card is shown
|
|
405
|
+
only where the server's `botCheck` is the same: a server that runs no bot
|
|
406
|
+
check must name `web-consent-2026-11-03`, and one that checks must name a
|
|
407
|
+
version that says so, or the view stays as it was.
|
|
382
408
|
`web-consent-2026-10-31` (which names the product, "a suggested Healthy Bowl
|
|
383
409
|
question") and `web-consent-2026-11` stay, unchanged, for servers that still
|
|
384
410
|
name them.
|
|
@@ -389,22 +415,24 @@ publishes audio, video or data, and it sends the avatar nothing to say.
|
|
|
389
415
|
apps-first hand-over, so it does not say which.
|
|
390
416
|
- **Requests.** All three go to the gateway without credentials. The create
|
|
391
417
|
request carries `content-type: application/json`, `idempotency-key` (a UUID
|
|
392
|
-
v4) and `x-web-avatar-bot-token` (the
|
|
393
|
-
verifies and does not forward); the
|
|
394
|
-
carry no header of the SDK's own. The conversation token is sent in the create
|
|
418
|
+
v4) and, only where the server checks for bots, `x-web-avatar-bot-token` (the
|
|
419
|
+
Turnstile token, which the gateway verifies and does not forward); the
|
|
420
|
+
availability request and the end request carry no header of the SDK's own. The conversation token is sent in the create
|
|
395
421
|
body only. Neither it, nor the session's end secret, nor the room token, nor
|
|
396
422
|
the bot check's token is ever written into the page, the console or storage by
|
|
397
423
|
the live avatar (the chat keeps its own copy of the conversation in
|
|
398
424
|
`localStorage`, as it always has).
|
|
399
|
-
- **Bot-check binding (web API contract v1.1, additive
|
|
425
|
+
- **Bot-check binding (web API contract v1.1, additive; `turnstile` mode
|
|
426
|
+
only).** The Turnstile widget
|
|
400
427
|
is rendered with `cData` set to
|
|
401
428
|
`base64url_nopad(SHA-256(UTF-8("boff-web-avatar-cdata/v1\n" + site + "\n" + locale + "\n" + conversationToken + "\n" + messageId)))`,
|
|
402
429
|
made with WebCrypto from the exact values the create body then carries, before
|
|
403
430
|
the widget is rendered, so the gateway can check that the token was minted for
|
|
404
431
|
this request. The action stays `avatar_start`, and nothing else in v1
|
|
405
|
-
changes.
|
|
406
|
-
cannot start the live avatar: Start loads
|
|
407
|
-
check's script there, and shows the view
|
|
432
|
+
changes. Where the server checks for bots, a browser without WebCrypto (a
|
|
433
|
+
page that is not a secure context) cannot start the live avatar: Start loads
|
|
434
|
+
neither the room module nor the bot check's script there, and shows the view
|
|
435
|
+
as it was. Pinned vector: site
|
|
408
436
|
`healthybowl`, locale `en`, conversation token
|
|
409
437
|
`ct_vector_0123456789abcdefghijklmnopqrstuvwx`, message id
|
|
410
438
|
`11111111-2222-4333-8444-555555555555` give
|
|
@@ -418,7 +446,9 @@ publishes audio, video or data, and it sends the avatar nothing to say.
|
|
|
418
446
|
preflight.
|
|
419
447
|
- **Your page's headers.** A site with a Content Security Policy must allow:
|
|
420
448
|
- `script-src` and `frame-src`: `https://challenges.cloudflare.com` (the
|
|
421
|
-
Turnstile bot check)
|
|
449
|
+
Turnstile bot check). Only needed where the server's bot check is
|
|
450
|
+
`turnstile`; keep it anyway, so that turning the bot check on later is a
|
|
451
|
+
server change and not a new release of the site;
|
|
422
452
|
- `connect-src`, the gateway origin (the three requests);
|
|
423
453
|
- `connect-src`, the media room: `wss://<project>.livekit.cloud`. For a
|
|
424
454
|
LiveKit Cloud room the media library also asks
|
|
@@ -587,14 +617,23 @@ A site adds these lines.
|
|
|
587
617
|
usual place whenever the banner is not on screen.
|
|
588
618
|
|
|
589
619
|
4. **The build env var** `VITE_AVATAR_TURNSTILE_SITE_KEY`: the site's
|
|
590
|
-
Cloudflare Turnstile site key
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
`
|
|
620
|
+
Cloudflare Turnstile site key, used only where the server checks for bots
|
|
621
|
+
(its availability's `botCheck` is `turnstile`). The server decides whether
|
|
622
|
+
the live avatar is offered on the site (its reviewed site list, its pause,
|
|
623
|
+
its caps) and whether it checks for bots, so the key is no longer the
|
|
624
|
+
opt-in: when it is unset or empty, `websiteAvatarLive` returns the live
|
|
625
|
+
config without a key, which runs where the server's bot check is `off` and
|
|
626
|
+
stays the still picture where it is `turnstile`. On alpha
|
|
627
|
+
(`VITE_DEPLOY_ENV=alpha`) it accepts Cloudflare's always-pass test key
|
|
628
|
+
`1x00000000000000000000AA` (the alpha gateway runs Turnstile in dummy mode)
|
|
629
|
+
or a real key; everywhere else, production included, only a real-looking key
|
|
630
|
+
(`0x…`, letters, digits, `_` and `-`, 18 to 64 characters) that is not one of
|
|
631
|
+
Cloudflare's test keys (`1x…AA`, `2x…AB`, `1x…BB`, `2x…BB`, `3x…FF`, or
|
|
632
|
+
anything of their shape). A key that is set but refused returns `undefined`
|
|
633
|
+
(the still picture and "Live avatar coming soon"), never a live avatar
|
|
634
|
+
without it. It also sets `allowTestSiteKey` (true on alpha only), so the
|
|
635
|
+
view itself refuses a test key on any other build. Pass `enabled: false` to
|
|
636
|
+
keep the still picture on a build whatever the server offers. Install
|
|
598
637
|
`livekit-client` on the site (see [Live avatar](#live-avatar-opt-in-receive-only)),
|
|
599
638
|
and declare the variable in `vite-env.d.ts`.
|
|
600
639
|
`websiteAvatarLive` trusts `VITE_DEPLOY_ENV`, so a production build must
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as react from 'react';
|
|
2
2
|
import { ReactNode } from 'react';
|
|
3
|
-
import { E as ExplorePanelAvatarLive, a as ExploreLocale, A as AvatarConversation } from '../explore-avatar-live-config-
|
|
3
|
+
import { E as ExplorePanelAvatarLive, a as ExploreLocale, A as AvatarConversation } from '../explore-avatar-live-config-D-hO90-A.mjs';
|
|
4
4
|
import '../types-CndbmBK-.mjs';
|
|
5
5
|
import '../use-explore-chat-zRuoAin6.mjs';
|
|
6
6
|
import '../explore-types-Bb2Ih3d8.mjs';
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as react from 'react';
|
|
2
2
|
import { ReactNode } from 'react';
|
|
3
|
-
import { E as ExplorePanelAvatarLive, a as ExploreLocale, A as AvatarConversation } from '../explore-avatar-live-config-
|
|
3
|
+
import { E as ExplorePanelAvatarLive, a as ExploreLocale, A as AvatarConversation } from '../explore-avatar-live-config-C1ILEcY8.js';
|
|
4
4
|
import '../types-CndbmBK-.js';
|
|
5
5
|
import '../use-explore-chat-DunjG-3p.js';
|
|
6
6
|
import '../explore-types-Bb2Ih3d8.js';
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var
|
|
3
|
+
var chunkOIQHIGGU_js = require('../chunk-OIQHIGGU.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');
|
|
@@ -35,6 +35,20 @@ var AVAILABILITY_REASONS = /* @__PURE__ */ new Map([
|
|
|
35
35
|
["busy", "busy"],
|
|
36
36
|
["limits", "limits"]
|
|
37
37
|
]);
|
|
38
|
+
var BOT_CHECK_MODES = /* @__PURE__ */ new Set([
|
|
39
|
+
"off",
|
|
40
|
+
"turnstile"
|
|
41
|
+
]);
|
|
42
|
+
function readBotCheck(value) {
|
|
43
|
+
if (value === void 0) return "turnstile";
|
|
44
|
+
if (!isRecord(value)) return null;
|
|
45
|
+
const keys = Object.keys(value);
|
|
46
|
+
const { mode } = value;
|
|
47
|
+
if (keys.length !== 1 || keys[0] !== "mode" || typeof mode !== "string" || !BOT_CHECK_MODES.has(mode)) {
|
|
48
|
+
return null;
|
|
49
|
+
}
|
|
50
|
+
return mode === "off" ? "off" : "turnstile";
|
|
51
|
+
}
|
|
38
52
|
function readAvailability(status, body) {
|
|
39
53
|
if (status !== 200 || !isRecord(body)) return INERT;
|
|
40
54
|
const { available, reason } = body;
|
|
@@ -43,10 +57,14 @@ function readAvailability(status, body) {
|
|
|
43
57
|
}
|
|
44
58
|
if (reason === "ok") {
|
|
45
59
|
const { consentVersion, maxSessionSeconds } = body;
|
|
46
|
-
|
|
60
|
+
const botCheck = readBotCheck(body.botCheck);
|
|
61
|
+
if (available !== true || typeof consentVersion !== "string" || !chunkOIQHIGGU_js.isAvatarVersion(consentVersion) || typeof maxSessionSeconds !== "number" || !Number.isInteger(maxSessionSeconds) || maxSessionSeconds < 1 || botCheck === null) {
|
|
47
62
|
return INERT;
|
|
48
63
|
}
|
|
49
|
-
return {
|
|
64
|
+
return {
|
|
65
|
+
kind: "available",
|
|
66
|
+
offer: { consentVersion, maxSessionSeconds, botCheck }
|
|
67
|
+
};
|
|
50
68
|
}
|
|
51
69
|
const meaning = available ? void 0 : AVAILABILITY_REASONS.get(reason);
|
|
52
70
|
return meaning === void 0 || meaning === "inert" ? INERT : { kind: "refused", reason: meaning };
|
|
@@ -128,7 +146,7 @@ function deadline(timeoutMs, outer) {
|
|
|
128
146
|
};
|
|
129
147
|
}
|
|
130
148
|
async function requestAvailability(target) {
|
|
131
|
-
if (!
|
|
149
|
+
if (!chunkOIQHIGGU_js.isAvatarSite(target.site) || !LOCALE.test(target.locale)) return INERT;
|
|
132
150
|
const query = new URLSearchParams({
|
|
133
151
|
site: target.site,
|
|
134
152
|
locale: target.locale
|
|
@@ -169,7 +187,7 @@ async function requestCreate(target) {
|
|
|
169
187
|
...target.headers,
|
|
170
188
|
"Content-Type": "application/json",
|
|
171
189
|
"Idempotency-Key": target.idempotencyKey,
|
|
172
|
-
"x-web-avatar-bot-token": target.botToken
|
|
190
|
+
...target.botToken === void 0 ? {} : { "x-web-avatar-bot-token": target.botToken }
|
|
173
191
|
},
|
|
174
192
|
body: payload,
|
|
175
193
|
signal: timer.signal
|
|
@@ -457,7 +475,8 @@ var CONSENT = /* @__PURE__ */ new Map([
|
|
|
457
475
|
intro: "This is an AI avatar, not a real person. It reads the assistant's first eligible answer to a suggested question aloud for up to a minute. The answer is AI-generated and can be wrong.",
|
|
458
476
|
processing: "When you start, Cloudflare checks for bots. The answer text goes to Google to create the voice. Your browser connects to LiveKit, which sees your IP address. LiveKit fetches our temporary audio file and passes the voice to Protoface, which makes the avatar video streamed through LiveKit.",
|
|
459
477
|
storage: "Your microphone and camera are not used. We do not record the live session. We temporarily store the generated voice file and keep a record of this consent. The privacy notice explains our safeguards, storage periods and the providers' processing. For people aged eighteen and over.",
|
|
460
|
-
privacyLink: "How we handle this"
|
|
478
|
+
privacyLink: "How we handle this",
|
|
479
|
+
botCheck: "turnstile"
|
|
461
480
|
}
|
|
462
481
|
}
|
|
463
482
|
],
|
|
@@ -471,7 +490,8 @@ var CONSENT = /* @__PURE__ */ new Map([
|
|
|
471
490
|
intro: "This is an AI avatar, not a real person. It reads the assistant's first eligible answer to a suggested question aloud for up to a minute. The answer is AI-generated and can be wrong.",
|
|
472
491
|
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.",
|
|
473
492
|
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.",
|
|
474
|
-
privacyLink: "How we handle this"
|
|
493
|
+
privacyLink: "How we handle this",
|
|
494
|
+
botCheck: "turnstile"
|
|
475
495
|
}
|
|
476
496
|
}
|
|
477
497
|
],
|
|
@@ -486,13 +506,30 @@ var CONSENT = /* @__PURE__ */ new Map([
|
|
|
486
506
|
intro: "This is an AI avatar, not a real person. It reads the assistant's first eligible answer to a suggested question aloud for up to a minute. The answer is AI-generated and can be wrong.",
|
|
487
507
|
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.",
|
|
488
508
|
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.",
|
|
489
|
-
privacyLink: "How we handle this"
|
|
509
|
+
privacyLink: "How we handle this",
|
|
510
|
+
botCheck: "turnstile"
|
|
511
|
+
}
|
|
512
|
+
}
|
|
513
|
+
],
|
|
514
|
+
[
|
|
515
|
+
// The words of web-consent-2026-11-02 without "When you start, Cloudflare checks for bots.", for a server that runs
|
|
516
|
+
// no bot check (its availability's botCheck is `off`). Product-neutral too: one notice and one digest for every site.
|
|
517
|
+
"web-consent-2026-11-03",
|
|
518
|
+
{
|
|
519
|
+
en: {
|
|
520
|
+
title: "Live AI avatar (beta)",
|
|
521
|
+
introProduct: null,
|
|
522
|
+
intro: "This is an AI avatar, not a real person. It reads the assistant's first eligible answer to a suggested question aloud for up to a minute. The answer is AI-generated and can be wrong.",
|
|
523
|
+
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.",
|
|
524
|
+
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.",
|
|
525
|
+
privacyLink: "How we handle this",
|
|
526
|
+
botCheck: "off"
|
|
490
527
|
}
|
|
491
528
|
}
|
|
492
529
|
]
|
|
493
530
|
]);
|
|
494
531
|
function avatarConsentCopy(version, locale) {
|
|
495
|
-
if (!
|
|
532
|
+
if (!chunkOIQHIGGU_js.isAvatarLiveLocaleReviewed(locale)) return null;
|
|
496
533
|
return CONSENT.get(version)?.[locale] ?? null;
|
|
497
534
|
}
|
|
498
535
|
|
|
@@ -757,7 +794,11 @@ function AvatarLiveView({
|
|
|
757
794
|
return;
|
|
758
795
|
}
|
|
759
796
|
const copy = avatarConsentCopy(result.offer.consentVersion, locale2);
|
|
760
|
-
if (copy === null) {
|
|
797
|
+
if (copy === null || copy.botCheck !== result.offer.botCheck) {
|
|
798
|
+
go(INERT2);
|
|
799
|
+
return;
|
|
800
|
+
}
|
|
801
|
+
if (result.offer.botCheck === "turnstile" && chunkOIQHIGGU_js.turnstileSiteKeyOf(live2) === null) {
|
|
761
802
|
go(INERT2);
|
|
762
803
|
return;
|
|
763
804
|
}
|
|
@@ -853,11 +894,12 @@ function AvatarLiveView({
|
|
|
853
894
|
if (current.name !== "consent") return;
|
|
854
895
|
const { live: live2, base: base2, headers: headers2 } = latest.current;
|
|
855
896
|
if (base2 === null) return;
|
|
856
|
-
|
|
897
|
+
const { offer, messageId } = current;
|
|
898
|
+
const siteKey = offer.botCheck === "turnstile" ? chunkOIQHIGGU_js.turnstileSiteKeyOf(live2) : null;
|
|
899
|
+
if (offer.botCheck === "turnstile" && (siteKey === null || !canBindBotCheck())) {
|
|
857
900
|
go(INERT2);
|
|
858
901
|
return;
|
|
859
902
|
}
|
|
860
|
-
const { offer, messageId } = current;
|
|
861
903
|
const conversationToken = conversationRef.current?.getConversationToken() ?? null;
|
|
862
904
|
const idempotencyKey = newIdempotencyKey();
|
|
863
905
|
if (conversationToken === null || !isAvatarConversationToken(conversationToken) || idempotencyKey === null) {
|
|
@@ -874,31 +916,36 @@ function AvatarLiveView({
|
|
|
874
916
|
};
|
|
875
917
|
const run = { cancelled: null, turnstile: null };
|
|
876
918
|
startRef.current = run;
|
|
877
|
-
go({ name: "bot-check", offer, messageId });
|
|
878
919
|
const module = loadModule(live2.load);
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
920
|
+
let turnstile = null;
|
|
921
|
+
if (siteKey === null) {
|
|
922
|
+
go({ name: "creating" });
|
|
923
|
+
} else {
|
|
924
|
+
go({ name: "bot-check", offer, messageId });
|
|
925
|
+
turnstile = runTurnstile(
|
|
926
|
+
botBoxRef.current,
|
|
927
|
+
siteKey,
|
|
928
|
+
"avatar_start",
|
|
929
|
+
avatarBotBinding(body2)
|
|
930
|
+
);
|
|
931
|
+
run.turnstile = turnstile;
|
|
932
|
+
}
|
|
886
933
|
void (async () => {
|
|
887
934
|
let loaded;
|
|
888
935
|
let botToken;
|
|
889
936
|
try {
|
|
890
|
-
[loaded, botToken] = await Promise.all([module, turnstile
|
|
937
|
+
[loaded, botToken] = await Promise.all([module, turnstile?.token]);
|
|
891
938
|
} catch {
|
|
892
|
-
turnstile
|
|
939
|
+
turnstile?.cancel();
|
|
893
940
|
if (run.cancelled === null) {
|
|
894
941
|
startRef.current = null;
|
|
895
942
|
go(INERT2);
|
|
896
943
|
}
|
|
897
944
|
return;
|
|
898
945
|
}
|
|
899
|
-
turnstile
|
|
946
|
+
turnstile?.cancel();
|
|
900
947
|
if (run.cancelled !== null) return;
|
|
901
|
-
go({ name: "creating" });
|
|
948
|
+
if (turnstile !== null) go({ name: "creating" });
|
|
902
949
|
const result = await requestCreate({
|
|
903
950
|
base: base2,
|
|
904
951
|
headers: headers2,
|