@nuskin/react-search-sdk 1.0.0-comx-2233.1 → 1.0.0-comx-2233.2

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/dist/index.mjs CHANGED
@@ -12,7 +12,7 @@ var DEBOUNCE_MS = 220;
12
12
  var MAX_VISIBLE_SUGGESTIONS = 6;
13
13
  var SEARCH_PLACEHOLDER = "Search by product name, ingredient, benefits, or SKU";
14
14
  var TRIGGER_PLACEHOLDER = "Product Search";
15
- var DEFAULT_AI_CHAT_BASE_URL = "https://admin.tst.nuskin.ai/api/analytics/v1/chat";
15
+ var DEFAULT_AI_CHAT_BASE_URL = "https://admin.tst.nuskin.ai/api/analytics/v1/embed";
16
16
  var DEFAULT_AI_CHAT_CONVERSATIONS_URL = `${DEFAULT_AI_CHAT_BASE_URL}/conversations`;
17
17
  var DEFAULT_AI_CHAT_MESSAGES_URL = `${DEFAULT_AI_CHAT_BASE_URL}/messages`;
18
18
 
@@ -763,6 +763,19 @@ function findClosingFence(content, fromIndex) {
763
763
  }
764
764
  return -1;
765
765
  }
766
+ function isRecord(value) {
767
+ return value !== null && typeof value === "object";
768
+ }
769
+ function getRenderProductListItems(event) {
770
+ if (event["type"] !== "render" || event["pattern"] !== "product_list") {
771
+ return [];
772
+ }
773
+ const data = event["data"];
774
+ if (!isRecord(data) || !Array.isArray(data["items"])) {
775
+ return [];
776
+ }
777
+ return data["items"].filter(isRecord);
778
+ }
766
779
  function extractProductsFromMarkdown(content) {
767
780
  const products = [];
768
781
  const summaryParts = [];
@@ -791,7 +804,8 @@ function extractProductsFromMarkdown(content) {
791
804
  if (Array.isArray(parsed)) {
792
805
  products.push(...parsed);
793
806
  }
794
- } catch {
807
+ } catch (e) {
808
+ console.error("Failed to parse products block:", e);
795
809
  }
796
810
  summaryParts.push(content.slice(summaryCursor, start));
797
811
  summaryCursor = end + MARKDOWN_CLOSING_FENCE.length;
@@ -804,8 +818,10 @@ function createChatService(options) {
804
818
  const {
805
819
  conversationsUrl = DEFAULT_AI_CHAT_CONVERSATIONS_URL,
806
820
  messagesUrl = DEFAULT_AI_CHAT_MESSAGES_URL,
807
- tenantId,
808
- getAuthToken,
821
+ salesAiAppKey,
822
+ salesAiParentOrigin,
823
+ market,
824
+ language,
809
825
  fetchImpl: fetchImplOption
810
826
  } = options;
811
827
  let fetchImpl;
@@ -818,22 +834,30 @@ function createChatService(options) {
818
834
  throw new Error("ChatService: no fetch implementation available");
819
835
  };
820
836
  }
821
- function buildHeaders(extra) {
837
+ function buildHeaders(extra, includeJsonContentType = true) {
822
838
  const headers = {
823
- "Content-Type": "application/json",
824
839
  ...extra
825
840
  };
826
- if (tenantId) headers["X-Tenant-Id"] = tenantId;
827
- const token = getAuthToken?.();
828
- if (token) headers["Authorization"] = `Bearer ${token}`;
841
+ if (includeJsonContentType) {
842
+ headers["Content-Type"] = "application/json";
843
+ }
844
+ const accessToken = typeof window !== "undefined" ? window.localStorage?.getItem("accessToken") : null;
845
+ if (accessToken) {
846
+ headers["Authorization"] = `Bearer ${accessToken}`;
847
+ }
848
+ if (salesAiAppKey) {
849
+ headers["X-Sales-AI-App-Key"] = salesAiAppKey;
850
+ }
851
+ if (salesAiParentOrigin) {
852
+ headers["X-Sales-AI-Parent-Origin"] = salesAiParentOrigin;
853
+ }
829
854
  return headers;
830
855
  }
831
856
  return {
832
- async createConversation(title = "Search Session") {
857
+ async createConversation() {
833
858
  const res = await fetchImpl(conversationsUrl, {
834
859
  method: "POST",
835
- headers: buildHeaders(),
836
- body: JSON.stringify({ title })
860
+ headers: buildHeaders(void 0, false)
837
861
  });
838
862
  if (!res.ok) {
839
863
  throw new Error(
@@ -850,14 +874,26 @@ function createChatService(options) {
850
874
  return id;
851
875
  },
852
876
  async sendMessage(conversationId, content, onChunk) {
877
+ const requestBody = {
878
+ conversation_id: conversationId,
879
+ content
880
+ };
881
+ if (market || language) {
882
+ requestBody.scope_context = {
883
+ market: market ?? "US",
884
+ language: language ?? "en"
885
+ };
886
+ }
887
+ requestBody.client_capabilities = {
888
+ patterns: {
889
+ product_list: [1],
890
+ follow_up: [1]
891
+ }
892
+ };
853
893
  const res = await fetchImpl(messagesUrl, {
854
894
  method: "POST",
855
- headers: buildHeaders({ Accept: "application/json" }),
856
- body: JSON.stringify({
857
- conversation_id: conversationId,
858
- content,
859
- compact: false
860
- })
895
+ headers: buildHeaders({ Accept: "text/event-stream" }),
896
+ body: JSON.stringify(requestBody)
861
897
  });
862
898
  if (!res.ok) {
863
899
  throw new Error(
@@ -865,6 +901,7 @@ function createChatService(options) {
865
901
  );
866
902
  }
867
903
  let accumulated = "";
904
+ const renderedProducts = [];
868
905
  const parser = createParser({
869
906
  onEvent(event) {
870
907
  const data = event.data;
@@ -873,6 +910,9 @@ function createChatService(options) {
873
910
  const parsed = JSON.parse(data);
874
911
  const parsedType = parsed["type"];
875
912
  const type = typeof parsedType === "string" ? parsedType : "";
913
+ renderedProducts.push(
914
+ ...getRenderProductListItems(parsed)
915
+ );
876
916
  if (type === "content" && typeof parsed["text"] === "string") {
877
917
  const text = parsed["text"];
878
918
  accumulated += text;
@@ -900,7 +940,12 @@ function createChatService(options) {
900
940
  parser.feed(rawBody);
901
941
  }
902
942
  const { summary, products } = extractProductsFromMarkdown(accumulated);
903
- return { summary, products, rawContent: accumulated };
943
+ const finalProducts = renderedProducts.length > 0 ? renderedProducts : products;
944
+ return {
945
+ summary,
946
+ products: finalProducts,
947
+ rawContent: accumulated
948
+ };
904
949
  }
905
950
  };
906
951
  }
@@ -1647,6 +1692,7 @@ function getSpeechRecognition() {
1647
1692
  }
1648
1693
  function useVoiceSearch({
1649
1694
  lang,
1695
+ onInterimResult,
1650
1696
  onResult,
1651
1697
  onError
1652
1698
  }) {
@@ -1664,11 +1710,24 @@ function useVoiceSearch({
1664
1710
  stop();
1665
1711
  const rec = new SR();
1666
1712
  rec.lang = lang ?? navigator.language ?? "en-US";
1667
- rec.interimResults = false;
1713
+ rec.interimResults = true;
1668
1714
  rec.maxAlternatives = 1;
1669
1715
  rec.onresult = (event) => {
1670
- const transcript = event.results[0]?.[0]?.transcript ?? "";
1671
- if (transcript) onResult(transcript);
1716
+ let finalTranscript = "";
1717
+ let interimTranscript = "";
1718
+ const startIndex = event.resultIndex ?? 0;
1719
+ for (let index = startIndex; index < event.results.length; index += 1) {
1720
+ const result = event.results[index];
1721
+ const transcript = result?.[0]?.transcript ?? "";
1722
+ if (!transcript) continue;
1723
+ if (result?.isFinal) {
1724
+ finalTranscript += transcript;
1725
+ } else {
1726
+ interimTranscript += transcript;
1727
+ }
1728
+ }
1729
+ if (interimTranscript) onInterimResult?.(interimTranscript);
1730
+ if (finalTranscript) onResult(finalTranscript);
1672
1731
  };
1673
1732
  rec.onerror = (event) => {
1674
1733
  onError?.(event);
@@ -1678,7 +1737,7 @@ function useVoiceSearch({
1678
1737
  recognitionRef.current = rec;
1679
1738
  rec.start();
1680
1739
  setListening(true);
1681
- }, [lang, onResult, onError, stop]);
1740
+ }, [lang, onInterimResult, onResult, onError, stop]);
1682
1741
  return { listening, supported, start, stop };
1683
1742
  }
1684
1743