@burdenoff/website-sdk 2026.1104.3 → 2026.1104.4
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 +24 -4
- package/dist/avatar-live-view/index.js +67 -42
- package/dist/avatar-live-view/index.js.map +1 -1
- package/dist/avatar-live-view/index.mjs +66 -41
- package/dist/avatar-live-view/index.mjs.map +1 -1
- package/dist/{chunk-5JQGE3XI.mjs → chunk-7HE33NBS.mjs} +4 -111
- package/dist/chunk-7HE33NBS.mjs.map +1 -0
- package/dist/chunk-JZS6FQT6.mjs +127 -0
- package/dist/chunk-JZS6FQT6.mjs.map +1 -0
- package/dist/{chunk-22OT6E26.js → chunk-MBVXDFVC.js} +18 -127
- package/dist/chunk-MBVXDFVC.js.map +1 -0
- package/dist/chunk-N7E6Z2GF.js +132 -0
- package/dist/chunk-N7E6Z2GF.js.map +1 -0
- package/dist/components/explore.d.mts +1 -1
- package/dist/components/explore.d.ts +1 -1
- package/dist/components/explore.js +20 -20
- package/dist/components/explore.mjs +2 -2
- package/dist/{explore-BV4dRwoC.d.ts → explore-Dfru4j4m.d.ts} +45 -31
- package/dist/{explore-BgEeGPvY.d.mts → explore-ei8uoko9.d.mts} +45 -31
- package/dist/index.d.mts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +61 -61
- package/dist/index.mjs +4 -3
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
- package/dist/chunk-22OT6E26.js.map +0 -1
- package/dist/chunk-5JQGE3XI.mjs.map +0 -1
- package/dist/chunk-O4GS3XPZ.js +0 -10
- package/dist/chunk-O4GS3XPZ.js.map +0 -1
- package/dist/chunk-TT3MHN42.mjs +0 -8
- package/dist/chunk-TT3MHN42.mjs.map +0 -1
package/README.md
CHANGED
|
@@ -387,9 +387,14 @@ publishes audio, video or data, and it sends the avatar nothing to say.
|
|
|
387
387
|
browser's own note of a session today, kept in `localStorage` as
|
|
388
388
|
`boff.explore.avatarUsedOn`), the box asks ordinary questions, without
|
|
389
389
|
`surface`, and the answer shows in the tab as text, with "Read the answer and
|
|
390
|
-
sources in Chat".
|
|
391
|
-
`
|
|
392
|
-
|
|
390
|
+
sources in Chat". The text is the answer's words, not its markdown: the form
|
|
391
|
+
the chat's read-aloud says (`answerSpeechText`), so a link is its label, a
|
|
392
|
+
table its rows, and the marks of emphasis, headings and quotes go, and on
|
|
393
|
+
this screen list markers as well (each item keeps its own line); citation
|
|
394
|
+
markers such as `[1]` stay, as in the chat. Pass `currentPath` to
|
|
395
|
+
`ExplorePanel` (as `SiteAssistantDock` does) so a page change calls off a
|
|
396
|
+
"Start when ready" at once; without it, the window's path is checked before
|
|
397
|
+
the create.
|
|
393
398
|
- **One answer: the first, to a suggested question.** The avatar service
|
|
394
399
|
accepts a conversation only when it holds exactly two messages: the first user
|
|
395
400
|
message (a suggested question) and the first assistant answer, completed. The
|
|
@@ -421,7 +426,22 @@ publishes audio, video or data, and it sends the avatar nothing to say.
|
|
|
421
426
|
back (Safari, iOS), a "Tap to turn on sound" button appears. A refusal (busy,
|
|
422
427
|
limits, region, language, paused, a question the avatar cannot read) is one
|
|
423
428
|
short sentence and "Continue in Chat". A network or CORS failure, or a route
|
|
424
|
-
that is not there, shows the view as it was before
|
|
429
|
+
that is not there, shows the view as it was before, until the create request
|
|
430
|
+
has been sent: from then on the server may have made the session, so a create
|
|
431
|
+
that gets no answer (its request failing on the way, its body cut off, or
|
|
432
|
+
nothing within 30 s) says "The live avatar couldn't start." with the way back
|
|
433
|
+
to Chat, never "Live avatar coming soon". The 30 s are a timer raced against
|
|
434
|
+
the request, so the view leaves "Connecting…" by then whatever the network
|
|
435
|
+
does. A create is never sent again by itself (the bot check's token is good
|
|
436
|
+
for one, and a second create could be paid twice), and a 201 that arrives
|
|
437
|
+
after the 30 s is never joined: its session is ended at once with its own
|
|
438
|
+
secret (reason `client_error`, or the visitor's own where they had stopped it
|
|
439
|
+
first). For that, only a request with no answer yet is aborted at 30 s: an
|
|
440
|
+
answer whose status is in by then is read to its end, so a 201 whose body is
|
|
441
|
+
still on its way keeps its secret. A request aborted with no answer at all
|
|
442
|
+
brings nothing back where the browser honours the abort, so a session the
|
|
443
|
+
server made for it is ended by the server's own deadlines (`no_show`). A 401,
|
|
444
|
+
403, 404 or 405 answer is still the view as it was before.
|
|
425
445
|
- **Ending.** Stop, closing the panel, leaving the page (`pagehide`), and the
|
|
426
446
|
live avatar going off under a session (the panel's locale changing to one
|
|
427
447
|
whose strings have not been reviewed) all end the session with a `keepalive`
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
var chunkWSEQ2I6I_js = require('../chunk-WSEQ2I6I.js');
|
|
4
|
-
var
|
|
4
|
+
var chunkN7E6Z2GF_js = require('../chunk-N7E6Z2GF.js');
|
|
5
5
|
var chunkC6OJIHNO_js = require('../chunk-C6OJIHNO.js');
|
|
6
6
|
require('../chunk-ZSTFX7FV.js');
|
|
7
7
|
var react = require('react');
|
|
@@ -182,7 +182,7 @@ async function requestAvailability(target) {
|
|
|
182
182
|
timer.done();
|
|
183
183
|
}
|
|
184
184
|
}
|
|
185
|
-
|
|
185
|
+
function requestCreate(target) {
|
|
186
186
|
const { body } = target;
|
|
187
187
|
const payload = JSON.stringify({
|
|
188
188
|
site: body.site,
|
|
@@ -192,27 +192,45 @@ async function requestCreate(target) {
|
|
|
192
192
|
consentVersion: body.consentVersion,
|
|
193
193
|
manifestVersion: body.manifestVersion
|
|
194
194
|
});
|
|
195
|
-
const
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
195
|
+
const controller = new AbortController();
|
|
196
|
+
let answered = false;
|
|
197
|
+
const answer = (async () => {
|
|
198
|
+
try {
|
|
199
|
+
const response = await fetch(`${target.base}/sessions`, {
|
|
200
|
+
method: "POST",
|
|
201
|
+
credentials: "omit",
|
|
202
|
+
cache: "no-store",
|
|
203
|
+
headers: {
|
|
204
|
+
...target.headers,
|
|
205
|
+
"Content-Type": "application/json",
|
|
206
|
+
"Idempotency-Key": target.idempotencyKey,
|
|
207
|
+
...target.botToken === void 0 ? {} : { "x-web-avatar-bot-token": target.botToken }
|
|
208
|
+
},
|
|
209
|
+
body: payload,
|
|
210
|
+
signal: controller.signal
|
|
211
|
+
});
|
|
212
|
+
answered = true;
|
|
213
|
+
return readCreate(response.status, await readJson(response));
|
|
214
|
+
} catch {
|
|
215
|
+
return FAILED;
|
|
216
|
+
}
|
|
217
|
+
})();
|
|
218
|
+
return new Promise((resolve) => {
|
|
219
|
+
let late = false;
|
|
220
|
+
const timer = setTimeout(() => {
|
|
221
|
+
late = true;
|
|
222
|
+
if (!answered) controller.abort();
|
|
223
|
+
resolve(FAILED);
|
|
224
|
+
}, CREATE_TIMEOUT_MS);
|
|
225
|
+
void answer.then((result) => {
|
|
226
|
+
if (late) {
|
|
227
|
+
target.onLate?.(result);
|
|
228
|
+
return;
|
|
229
|
+
}
|
|
230
|
+
clearTimeout(timer);
|
|
231
|
+
resolve(result);
|
|
209
232
|
});
|
|
210
|
-
|
|
211
|
-
} catch {
|
|
212
|
-
return INERT;
|
|
213
|
-
} finally {
|
|
214
|
-
timer.done();
|
|
215
|
-
}
|
|
233
|
+
});
|
|
216
234
|
}
|
|
217
235
|
function sendEnd(target) {
|
|
218
236
|
try {
|
|
@@ -1361,21 +1379,21 @@ function AvatarLiveView({
|
|
|
1361
1379
|
[go]
|
|
1362
1380
|
);
|
|
1363
1381
|
const settle = react.useCallback(
|
|
1364
|
-
(result,
|
|
1382
|
+
(result, givenUp, context) => {
|
|
1365
1383
|
const created = result.kind === "created" ? {
|
|
1366
1384
|
sessionId: result.session.sessionId,
|
|
1367
1385
|
secret: result.session.endSecret
|
|
1368
1386
|
} : result.kind === "unusable" ? { sessionId: result.sessionId, secret: result.endSecret } : null;
|
|
1369
1387
|
const claimed = created !== null || result.kind === "refused" && result.reason === "answer_claimed";
|
|
1370
1388
|
if (claimed) claimedRef.current.add(context.messageId);
|
|
1371
|
-
if (
|
|
1389
|
+
if (givenUp !== null) {
|
|
1372
1390
|
if (created !== null) {
|
|
1373
1391
|
sendEnd({
|
|
1374
1392
|
base: context.base,
|
|
1375
1393
|
headers: context.headers,
|
|
1376
1394
|
sessionId: created.sessionId,
|
|
1377
1395
|
secret: created.secret,
|
|
1378
|
-
reason:
|
|
1396
|
+
reason: givenUp
|
|
1379
1397
|
});
|
|
1380
1398
|
}
|
|
1381
1399
|
const shown2 = phaseRef.current;
|
|
@@ -1484,21 +1502,21 @@ function AvatarLiveView({
|
|
|
1484
1502
|
return;
|
|
1485
1503
|
}
|
|
1486
1504
|
if (turnstile !== null) go({ name: "creating" });
|
|
1505
|
+
const context = { module: loaded, offer, messageId, base: base2, headers: headers2 };
|
|
1487
1506
|
const result = await requestCreate({
|
|
1488
1507
|
base: base2,
|
|
1489
1508
|
headers: headers2,
|
|
1490
1509
|
idempotencyKey,
|
|
1491
1510
|
botToken,
|
|
1492
|
-
body: body2
|
|
1511
|
+
body: body2,
|
|
1512
|
+
// An answer past the deadline, after the view has said the live avatar couldn't start: a session it made is
|
|
1513
|
+
// ended at once with its own secret, and never joined. The reason is the visitor's own where they gave the
|
|
1514
|
+
// start up first, else `client_error`. It reads `run` and never writes it, so the deadline's `failed` below is
|
|
1515
|
+
// shown whichever of the two is handled first.
|
|
1516
|
+
onLate: (late) => settle(late, run.cancelled ?? "client_error", context)
|
|
1493
1517
|
});
|
|
1494
1518
|
if (startRef.current === run) startRef.current = null;
|
|
1495
|
-
settle(result, run,
|
|
1496
|
-
module: loaded,
|
|
1497
|
-
offer,
|
|
1498
|
-
messageId,
|
|
1499
|
-
base: base2,
|
|
1500
|
-
headers: headers2
|
|
1501
|
-
});
|
|
1519
|
+
settle(result, run.cancelled, context);
|
|
1502
1520
|
})();
|
|
1503
1521
|
},
|
|
1504
1522
|
[exchangeNow, go, reoffer, settle]
|
|
@@ -2097,7 +2115,7 @@ function AvatarLiveView({
|
|
|
2097
2115
|
className: "w-full max-w-sm rounded-lg border border-border p-4 text-start",
|
|
2098
2116
|
children: [
|
|
2099
2117
|
/* @__PURE__ */ jsxRuntime.jsx("h2", { id: consentTitleId, className: "text-base font-semibold", children: copy.title }),
|
|
2100
|
-
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "mt-2 text-sm", children: productName === null || copy.introProduct === null ? copy.intro :
|
|
2118
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "mt-2 text-sm", children: productName === null || copy.introProduct === null ? copy.intro : chunkN7E6Z2GF_js.fill(copy.introProduct, { product: productName }) }),
|
|
2101
2119
|
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "mt-2 text-sm text-muted-foreground", children: copy.processing }),
|
|
2102
2120
|
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "mt-2 text-sm text-muted-foreground", children: copy.storage }),
|
|
2103
2121
|
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
@@ -2277,14 +2295,21 @@ function AvatarLiveView({
|
|
|
2277
2295
|
children: lastQuestion.content
|
|
2278
2296
|
}
|
|
2279
2297
|
),
|
|
2280
|
-
lastAnswer === void 0 ? unanswered === "waiting" ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-muted-foreground", children: activity ?? S.gettingAnswer }) : unanswered === "failed" ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-muted-foreground", children: S.answerFailed }) : null : lastAnswer.status === "PENDING" || lastAnswer.status === "RUNNING" ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-muted-foreground", children: activity ?? S.gettingAnswer }) : lastAnswer.status === "FAILED" ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-muted-foreground", children: S.answerFailed }) :
|
|
2281
|
-
|
|
2282
|
-
|
|
2283
|
-
|
|
2284
|
-
|
|
2285
|
-
|
|
2286
|
-
|
|
2287
|
-
|
|
2298
|
+
lastAnswer === void 0 ? unanswered === "waiting" ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-muted-foreground", children: activity ?? S.gettingAnswer }) : unanswered === "failed" ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-muted-foreground", children: S.answerFailed }) : null : lastAnswer.status === "PENDING" || lastAnswer.status === "RUNNING" ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-muted-foreground", children: activity ?? S.gettingAnswer }) : lastAnswer.status === "FAILED" ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-muted-foreground", children: S.answerFailed }) : (
|
|
2299
|
+
// The answer's words, not its markdown: `content` is written for the chat's renderer, and shown as it is
|
|
2300
|
+
// here a link reads `[label](https://…)`. In its spoken form, as the chat's read-aloud says it: a link is its
|
|
2301
|
+
// label (the address is in Chat, one tap away), a table its rows, and the markers of emphasis, headings,
|
|
2302
|
+
// quotes and list items go (`answerDisplayText`). The words are the ones the chat shows, citation markers
|
|
2303
|
+
// included, which the sources in Chat answer to.
|
|
2304
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2305
|
+
"p",
|
|
2306
|
+
{
|
|
2307
|
+
"data-boff-explore": "avatar-live-text-answer",
|
|
2308
|
+
dir: "auto",
|
|
2309
|
+
className: "line-clamp-6 w-full max-w-sm whitespace-pre-wrap break-words text-start text-sm",
|
|
2310
|
+
children: chunkN7E6Z2GF_js.answerDisplayText(lastAnswer.content)
|
|
2311
|
+
}
|
|
2312
|
+
)
|
|
2288
2313
|
)
|
|
2289
2314
|
] });
|
|
2290
2315
|
const ended = phase.name === "ended";
|