@burdenoff/website-sdk 2026.922.2 → 2026.922.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.
@@ -263,11 +263,21 @@ var EXPLORE_MESSAGE_FIELDS = (
263
263
  completedAt
264
264
  `
265
265
  );
266
- var EXPLORE_CATALOG_QUERY = (
266
+ var EXPLORE_OWN_MESSAGE_FIELDS = (
267
+ /* GraphQL */
268
+ `
269
+ ${EXPLORE_MESSAGE_FIELDS}
270
+ feedback {
271
+ rating
272
+ reason
273
+ comment
274
+ createdAt
275
+ }
276
+ `
277
+ );
278
+ var EXPLORE_CATALOG_ESTABLISHED_FIELDS = (
267
279
  /* GraphQL */
268
280
  `
269
- query ExploreCatalog($productSlug: String) {
270
- exploreCatalog(productSlug: $productSlug) {
271
281
  enabled
272
282
  products {
273
283
  slug
@@ -285,17 +295,41 @@ var EXPLORE_CATALOG_QUERY = (
285
295
  historyTurns
286
296
  }
287
297
  captchaRequired
288
- recaptchaSiteKey
298
+ recaptchaSiteKey`
299
+ );
300
+ var EXPLORE_CATALOG_HIGHLIGHT_FIELD = (
301
+ /* GraphQL */
302
+ `
303
+ conceptHighlights {
304
+ product
305
+ productName
306
+ title
307
+ url
308
+ imageUrl
309
+ alt
310
+ }`
311
+ );
312
+ function exploreCatalogDocument(extraFields) {
313
+ return (
314
+ /* GraphQL */
315
+ `
316
+ query ExploreCatalog($productSlug: String) {
317
+ exploreCatalog(productSlug: $productSlug) {${EXPLORE_CATALOG_ESTABLISHED_FIELDS}${extraFields}
289
318
  }
290
319
  }
291
320
  `
321
+ );
322
+ }
323
+ var EXPLORE_CATALOG_QUERY = exploreCatalogDocument(
324
+ EXPLORE_CATALOG_HIGHLIGHT_FIELD
292
325
  );
326
+ var EXPLORE_CATALOG_QUERY_WITHOUT_HIGHLIGHTS = exploreCatalogDocument("");
293
327
  var EXPLORE_MESSAGE_QUERY = (
294
328
  /* GraphQL */
295
329
  `
296
330
  query ExploreMessage($conversationToken: String!, $id: ID!) {
297
331
  exploreMessage(conversationToken: $conversationToken, id: $id) {
298
- ${EXPLORE_MESSAGE_FIELDS}
332
+ ${EXPLORE_OWN_MESSAGE_FIELDS}
299
333
  }
300
334
  }
301
335
  `
@@ -313,10 +347,10 @@ var SEND_EXPLORE_MESSAGE_MUTATION = (
313
347
  createdAt
314
348
  }
315
349
  userMessage {
316
- ${EXPLORE_MESSAGE_FIELDS}
350
+ ${EXPLORE_OWN_MESSAGE_FIELDS}
317
351
  }
318
352
  assistantMessage {
319
- ${EXPLORE_MESSAGE_FIELDS}
353
+ ${EXPLORE_OWN_MESSAGE_FIELDS}
320
354
  }
321
355
  remainingToday
322
356
  }
@@ -333,6 +367,22 @@ var RECORD_EXPLORE_CLICK_MUTATION = (
333
367
  }
334
368
  `
335
369
  );
370
+ var SUBMIT_EXPLORE_FEEDBACK_MUTATION = (
371
+ /* GraphQL */
372
+ `
373
+ mutation SubmitExploreFeedback($input: SubmitExploreFeedbackInput!) {
374
+ submitExploreFeedback(input: $input) {
375
+ recorded
376
+ feedback {
377
+ rating
378
+ reason
379
+ comment
380
+ createdAt
381
+ }
382
+ }
383
+ }
384
+ `
385
+ );
336
386
  var CREATE_EXPLORE_SHARE_LINK_MUTATION = (
337
387
  /* GraphQL */
338
388
  `
@@ -637,7 +687,12 @@ function buildFallbackCatalog(examplePrompts, welcome) {
637
687
  welcomeBody: welcome?.body ?? FALLBACK_WELCOME_BODY,
638
688
  limits: FALLBACK_EXPLORE_LIMITS,
639
689
  captchaRequired: false,
640
- recaptchaSiteKey: null
690
+ recaptchaSiteKey: null,
691
+ // Empty, and deliberately not synthesised from `ECOSYSTEM_PRODUCTS`: a concept highlight
692
+ // needs a real published illustration URL, and this SDK has no registry of them. An
693
+ // invented path would render 38 broken frames on the one screen every prerender captures.
694
+ // The strip renders nothing at all when the list is empty, which is the honest fallback.
695
+ conceptHighlights: []
641
696
  };
642
697
  }
643
698
  function normalizeCatalog(raw, fallback) {
@@ -654,9 +709,27 @@ function normalizeCatalog(raw, fallback) {
654
709
  historyTurns: raw.limits?.historyTurns || fallback.limits.historyTurns
655
710
  },
656
711
  captchaRequired: raw.captchaRequired === true,
657
- recaptchaSiteKey: raw.recaptchaSiteKey ?? null
712
+ recaptchaSiteKey: raw.recaptchaSiteKey ?? null,
713
+ // `[ExploreConceptHighlight!]!` on the wire, so a gateway that KNOWS the field always
714
+ // sends an array. The one response that arrives without it is the retry against an older
715
+ // supergraph (`EXPLORE_CATALOG_QUERY_WITHOUT_HIGHLIGHTS`) — that gateway does not answer
716
+ // the full document at all, it refuses it. Either way
717
+ // `catalog.conceptHighlights.filter(...)` on `undefined` would throw inside render,
718
+ // blanking the welcome screen over a decorative strip.
719
+ conceptHighlights: raw.conceptHighlights?.length ? raw.conceptHighlights : fallback.conceptHighlights
658
720
  };
659
721
  }
722
+ var CATALOG_DOCUMENT_REJECTED_CODES = /* @__PURE__ */ new Set([
723
+ "GRAPHQL_VALIDATION_FAILED",
724
+ "HTTP_400"
725
+ ]);
726
+ function catalogRejectedTheHighlightField(res) {
727
+ if (res.data?.exploreCatalog) return false;
728
+ return (res.errors ?? []).some((error) => {
729
+ const code = error.extensions?.code;
730
+ return typeof code === "string" && CATALOG_DOCUMENT_REJECTED_CODES.has(code) || error.message.includes("conceptHighlights");
731
+ });
732
+ }
660
733
  var RATE_LIMIT_CODES = /* @__PURE__ */ new Set([
661
734
  "RATE_LIMITED",
662
735
  "HTTP_429",
@@ -996,11 +1069,19 @@ function useExploreChat(options = {}) {
996
1069
  useEffect(() => {
997
1070
  let cancelled = false;
998
1071
  const load = async () => {
999
- const res = await client.query(
1072
+ const variables = { productSlug: productSlug ?? null };
1073
+ let res = await client.query(
1000
1074
  EXPLORE_CATALOG_QUERY,
1001
- { productSlug: productSlug ?? null }
1075
+ variables
1002
1076
  );
1003
1077
  if (cancelled || !mountedRef.current) return;
1078
+ if (catalogRejectedTheHighlightField(res)) {
1079
+ res = await client.query(
1080
+ EXPLORE_CATALOG_QUERY_WITHOUT_HIGHLIGHTS,
1081
+ variables
1082
+ );
1083
+ if (cancelled || !mountedRef.current) return;
1084
+ }
1004
1085
  const raw = res.data?.exploreCatalog;
1005
1086
  if (res.errors?.length || !raw) {
1006
1087
  console.warn(
@@ -1381,6 +1462,42 @@ function useExploreChat(options = {}) {
1381
1462
  },
1382
1463
  [client]
1383
1464
  );
1465
+ const submitFeedback = useCallback(
1466
+ async (messageId, rating, detail) => {
1467
+ const token = conversationTokenRef.current;
1468
+ if (!token) return false;
1469
+ const comment = detail?.comment?.trim();
1470
+ const input = {
1471
+ conversationToken: token,
1472
+ messageId,
1473
+ rating,
1474
+ // Only meaningful with NOT_HELPFUL. The server stores null for HELPFUL either
1475
+ // way; sending it would just be noise the backend has to defend against.
1476
+ reason: rating === "NOT_HELPFUL" ? detail?.reason ?? null : null,
1477
+ comment: comment ? comment : null
1478
+ };
1479
+ try {
1480
+ const res = await client.mutate(
1481
+ SUBMIT_EXPLORE_FEEDBACK_MUTATION,
1482
+ { input }
1483
+ );
1484
+ const result = res?.data?.submitExploreFeedback;
1485
+ if (!result?.recorded) return false;
1486
+ const recorded = result.feedback;
1487
+ if (recorded && mountedRef.current) {
1488
+ setMessages(
1489
+ (current) => current.map(
1490
+ (message) => message.id === messageId ? { ...message, feedback: recorded } : message
1491
+ )
1492
+ );
1493
+ }
1494
+ return true;
1495
+ } catch {
1496
+ return false;
1497
+ }
1498
+ },
1499
+ [client]
1500
+ );
1384
1501
  return {
1385
1502
  phase,
1386
1503
  catalog,
@@ -1400,6 +1517,7 @@ function useExploreChat(options = {}) {
1400
1517
  deleteConversation,
1401
1518
  clearHistory,
1402
1519
  recordClick,
1520
+ submitFeedback,
1403
1521
  createShareLink,
1404
1522
  isSharedView
1405
1523
  };