@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.
@@ -1,5 +1,5 @@
1
1
  import { turnstileSiteKeyOf, isAvatarLiveLocaleReviewed, isAvatarSite, isAvatarVersion } from '../chunk-7MSB3EUI.mjs';
2
- import { fill } from '../chunk-TT3MHN42.mjs';
2
+ import { answerDisplayText, fill } from '../chunk-JZS6FQT6.mjs';
3
3
  import { cn } from '../chunk-R7G6TWIS.mjs';
4
4
  import '../chunk-VNS5WDWO.mjs';
5
5
  import { useId, useState, useRef, useCallback, useEffect } from 'react';
@@ -180,7 +180,7 @@ async function requestAvailability(target) {
180
180
  timer.done();
181
181
  }
182
182
  }
183
- async function requestCreate(target) {
183
+ function requestCreate(target) {
184
184
  const { body } = target;
185
185
  const payload = JSON.stringify({
186
186
  site: body.site,
@@ -190,27 +190,45 @@ async function requestCreate(target) {
190
190
  consentVersion: body.consentVersion,
191
191
  manifestVersion: body.manifestVersion
192
192
  });
193
- const timer = deadline(CREATE_TIMEOUT_MS);
194
- try {
195
- const response = await fetch(`${target.base}/sessions`, {
196
- method: "POST",
197
- credentials: "omit",
198
- cache: "no-store",
199
- headers: {
200
- ...target.headers,
201
- "Content-Type": "application/json",
202
- "Idempotency-Key": target.idempotencyKey,
203
- ...target.botToken === void 0 ? {} : { "x-web-avatar-bot-token": target.botToken }
204
- },
205
- body: payload,
206
- signal: timer.signal
193
+ const controller = new AbortController();
194
+ let answered = false;
195
+ const answer = (async () => {
196
+ try {
197
+ const response = await fetch(`${target.base}/sessions`, {
198
+ method: "POST",
199
+ credentials: "omit",
200
+ cache: "no-store",
201
+ headers: {
202
+ ...target.headers,
203
+ "Content-Type": "application/json",
204
+ "Idempotency-Key": target.idempotencyKey,
205
+ ...target.botToken === void 0 ? {} : { "x-web-avatar-bot-token": target.botToken }
206
+ },
207
+ body: payload,
208
+ signal: controller.signal
209
+ });
210
+ answered = true;
211
+ return readCreate(response.status, await readJson(response));
212
+ } catch {
213
+ return FAILED;
214
+ }
215
+ })();
216
+ return new Promise((resolve) => {
217
+ let late = false;
218
+ const timer = setTimeout(() => {
219
+ late = true;
220
+ if (!answered) controller.abort();
221
+ resolve(FAILED);
222
+ }, CREATE_TIMEOUT_MS);
223
+ void answer.then((result) => {
224
+ if (late) {
225
+ target.onLate?.(result);
226
+ return;
227
+ }
228
+ clearTimeout(timer);
229
+ resolve(result);
207
230
  });
208
- return readCreate(response.status, await readJson(response));
209
- } catch {
210
- return INERT;
211
- } finally {
212
- timer.done();
213
- }
231
+ });
214
232
  }
215
233
  function sendEnd(target) {
216
234
  try {
@@ -1359,21 +1377,21 @@ function AvatarLiveView({
1359
1377
  [go]
1360
1378
  );
1361
1379
  const settle = useCallback(
1362
- (result, run, context) => {
1380
+ (result, givenUp, context) => {
1363
1381
  const created = result.kind === "created" ? {
1364
1382
  sessionId: result.session.sessionId,
1365
1383
  secret: result.session.endSecret
1366
1384
  } : result.kind === "unusable" ? { sessionId: result.sessionId, secret: result.endSecret } : null;
1367
1385
  const claimed = created !== null || result.kind === "refused" && result.reason === "answer_claimed";
1368
1386
  if (claimed) claimedRef.current.add(context.messageId);
1369
- if (run.cancelled !== null) {
1387
+ if (givenUp !== null) {
1370
1388
  if (created !== null) {
1371
1389
  sendEnd({
1372
1390
  base: context.base,
1373
1391
  headers: context.headers,
1374
1392
  sessionId: created.sessionId,
1375
1393
  secret: created.secret,
1376
- reason: run.cancelled
1394
+ reason: givenUp
1377
1395
  });
1378
1396
  }
1379
1397
  const shown2 = phaseRef.current;
@@ -1482,21 +1500,21 @@ function AvatarLiveView({
1482
1500
  return;
1483
1501
  }
1484
1502
  if (turnstile !== null) go({ name: "creating" });
1503
+ const context = { module: loaded, offer, messageId, base: base2, headers: headers2 };
1485
1504
  const result = await requestCreate({
1486
1505
  base: base2,
1487
1506
  headers: headers2,
1488
1507
  idempotencyKey,
1489
1508
  botToken,
1490
- body: body2
1509
+ body: body2,
1510
+ // An answer past the deadline, after the view has said the live avatar couldn't start: a session it made is
1511
+ // ended at once with its own secret, and never joined. The reason is the visitor's own where they gave the
1512
+ // start up first, else `client_error`. It reads `run` and never writes it, so the deadline's `failed` below is
1513
+ // shown whichever of the two is handled first.
1514
+ onLate: (late) => settle(late, run.cancelled ?? "client_error", context)
1491
1515
  });
1492
1516
  if (startRef.current === run) startRef.current = null;
1493
- settle(result, run, {
1494
- module: loaded,
1495
- offer,
1496
- messageId,
1497
- base: base2,
1498
- headers: headers2
1499
- });
1517
+ settle(result, run.cancelled, context);
1500
1518
  })();
1501
1519
  },
1502
1520
  [exchangeNow, go, reoffer, settle]
@@ -2275,14 +2293,21 @@ function AvatarLiveView({
2275
2293
  children: lastQuestion.content
2276
2294
  }
2277
2295
  ),
2278
- lastAnswer === void 0 ? unanswered === "waiting" ? /* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground", children: activity ?? S.gettingAnswer }) : unanswered === "failed" ? /* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground", children: S.answerFailed }) : null : lastAnswer.status === "PENDING" || lastAnswer.status === "RUNNING" ? /* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground", children: activity ?? S.gettingAnswer }) : lastAnswer.status === "FAILED" ? /* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground", children: S.answerFailed }) : /* @__PURE__ */ jsx(
2279
- "p",
2280
- {
2281
- "data-boff-explore": "avatar-live-text-answer",
2282
- dir: "auto",
2283
- className: "line-clamp-6 w-full max-w-sm whitespace-pre-wrap break-words text-start text-sm",
2284
- children: lastAnswer.content
2285
- }
2296
+ lastAnswer === void 0 ? unanswered === "waiting" ? /* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground", children: activity ?? S.gettingAnswer }) : unanswered === "failed" ? /* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground", children: S.answerFailed }) : null : lastAnswer.status === "PENDING" || lastAnswer.status === "RUNNING" ? /* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground", children: activity ?? S.gettingAnswer }) : lastAnswer.status === "FAILED" ? /* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground", children: S.answerFailed }) : (
2297
+ // The answer's words, not its markdown: `content` is written for the chat's renderer, and shown as it is
2298
+ // here a link reads `[label](https://…)`. In its spoken form, as the chat's read-aloud says it: a link is its
2299
+ // label (the address is in Chat, one tap away), a table its rows, and the markers of emphasis, headings,
2300
+ // quotes and list items go (`answerDisplayText`). The words are the ones the chat shows, citation markers
2301
+ // included, which the sources in Chat answer to.
2302
+ /* @__PURE__ */ jsx(
2303
+ "p",
2304
+ {
2305
+ "data-boff-explore": "avatar-live-text-answer",
2306
+ dir: "auto",
2307
+ className: "line-clamp-6 w-full max-w-sm whitespace-pre-wrap break-words text-start text-sm",
2308
+ children: answerDisplayText(lastAnswer.content)
2309
+ }
2310
+ )
2286
2311
  )
2287
2312
  ] });
2288
2313
  const ended = phase.name === "ended";