@burdenoff/website-sdk 2026.829.5 → 2026.829.7

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
@@ -1,7 +1,7 @@
1
1
  import * as React from 'react';
2
2
  import { createContext, useMemo, useContext, useState, useCallback, useLayoutEffect, useRef, useEffect } from 'react';
3
3
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
4
- import { Instagram, Youtube, Facebook, Github, Linkedin, Twitter, Mail, Phone, MapPin, Clock, Send, CheckCircle, Upload, Globe, ChevronDown, Search, Rocket, ArrowRight, Download, Sparkles, RotateCcw, Link2, History, Trash2, Mic, Square, ArrowUp, BookOpenText, Layers, TriangleAlert, ChevronLeft, ChevronRight, FileText, ExternalLink } from 'lucide-react';
4
+ import { Instagram, Youtube, Facebook, Github, Linkedin, Twitter, Mail, Phone, MapPin, Clock, Send, CheckCircle, Upload, Globe, ChevronDown, Search, Rocket, ArrowRight, Download, Sparkles, RotateCcw, Link2, History, Trash2, Paperclip, X, Mic, Square, ArrowUp, BookOpenText, Layers, TriangleAlert, ChevronLeft, ChevronRight, FileText, ExternalLink } from 'lucide-react';
5
5
  import ReCAPTCHA4 from 'react-google-recaptcha';
6
6
  import { toast } from 'sonner';
7
7
  import { Helmet } from 'react-helmet-async';
@@ -4768,6 +4768,12 @@ var EN = {
4768
4768
  disclaimerShort: "Grounded in our docs \u2014 check anything important.",
4769
4769
  dictate: "Dictate your question",
4770
4770
  stopDictating: "Stop dictating",
4771
+ attach: "Attach files",
4772
+ attachHint: "Up to {{max}} files, {{size}} MB each",
4773
+ removeAttachment: "Remove {{name}}",
4774
+ attachmentNameOnly: "name and type only",
4775
+ attachmentTooLarge: "{{name}} is larger than {{size}} MB and was not attached.",
4776
+ attachmentTooMany: "Only {{max}} files can be attached, so {{name}} was skipped.",
4771
4777
  noAnswer: "I couldn't find this in our documentation, so the answer below is not grounded in a source. Try rephrasing, or",
4772
4778
  askHuman: "ask a human",
4773
4779
  prevSuggestion: "Previous suggestion",
@@ -4810,6 +4816,12 @@ var ZH = {
4810
4816
  disclaimerShort: "\u5185\u5BB9\u57FA\u4E8E\u6211\u4EEC\u7684\u6587\u6863\uFF0C\u91CD\u8981\u4FE1\u606F\u8BF7\u81EA\u884C\u6838\u5BF9\u3002",
4811
4817
  dictate: "\u8BED\u97F3\u8F93\u5165",
4812
4818
  stopDictating: "\u505C\u6B62\u8BED\u97F3\u8F93\u5165",
4819
+ attach: "\u6DFB\u52A0\u6587\u4EF6",
4820
+ attachHint: "\u6700\u591A {{max}} \u4E2A\u6587\u4EF6\uFF0C\u6BCF\u4E2A\u4E0D\u8D85\u8FC7 {{size}} MB",
4821
+ removeAttachment: "\u79FB\u9664 {{name}}",
4822
+ attachmentNameOnly: "\u4EC5\u6587\u4EF6\u540D\u548C\u7C7B\u578B",
4823
+ attachmentTooLarge: "{{name}} \u8D85\u8FC7 {{size}} MB\uFF0C\u672A\u80FD\u6DFB\u52A0\u3002",
4824
+ attachmentTooMany: "\u6700\u591A\u53EA\u80FD\u6DFB\u52A0 {{max}} \u4E2A\u6587\u4EF6\uFF0C\u5DF2\u8DF3\u8FC7 {{name}}\u3002",
4813
4825
  noAnswer: "\u6211\u5728\u6587\u6863\u4E2D\u6CA1\u6709\u627E\u5230\u76F8\u5173\u5185\u5BB9\uFF0C\u4E0B\u9762\u7684\u56DE\u7B54\u6CA1\u6709\u6765\u6E90\u652F\u6301\u3002\u8BF7\u6362\u4E2A\u8BF4\u6CD5\uFF0C\u6216",
4814
4826
  askHuman: "\u8054\u7CFB\u6211\u4EEC",
4815
4827
  prevSuggestion: "\u4E0A\u4E00\u4E2A\u5EFA\u8BAE",
@@ -4848,6 +4860,12 @@ var HI = {
4848
4860
  disclaimerShort: "\u092F\u0939 \u0939\u092E\u093E\u0930\u0947 \u0926\u0938\u094D\u0924\u093E\u0935\u0947\u091C\u093C\u094B\u0902 \u092A\u0930 \u0906\u0927\u093E\u0930\u093F\u0924 \u0939\u0948 \u2014 \u092E\u0939\u0924\u094D\u0935\u092A\u0942\u0930\u094D\u0923 \u092C\u093E\u0924\u0947\u0902 \u091C\u093C\u0930\u0942\u0930 \u091C\u093E\u0901\u091A \u0932\u0947\u0902\u0964",
4849
4861
  dictate: "\u092C\u094B\u0932\u0915\u0930 \u092A\u0942\u091B\u0947\u0902",
4850
4862
  stopDictating: "\u092C\u094B\u0932\u0928\u093E \u092C\u0902\u0926 \u0915\u0930\u0947\u0902",
4863
+ attach: "\u092B\u093C\u093E\u0907\u0932\u0947\u0902 \u091C\u094B\u0921\u093C\u0947\u0902",
4864
+ attachHint: "\u0905\u0927\u093F\u0915\u0924\u092E {{max}} \u092B\u093C\u093E\u0907\u0932\u0947\u0902, \u092A\u094D\u0930\u0924\u094D\u092F\u0947\u0915 {{size}} MB \u0924\u0915",
4865
+ removeAttachment: "{{name}} \u0939\u091F\u093E\u090F\u0901",
4866
+ attachmentNameOnly: "\u0915\u0947\u0935\u0932 \u0928\u093E\u092E \u0914\u0930 \u092A\u094D\u0930\u0915\u093E\u0930",
4867
+ attachmentTooLarge: "{{name}} {{size}} MB \u0938\u0947 \u092C\u0921\u093C\u0940 \u0939\u0948, \u0907\u0938\u0932\u093F\u090F \u091C\u094B\u0921\u093C\u0940 \u0928\u0939\u0940\u0902 \u0917\u0908\u0964",
4868
+ attachmentTooMany: "\u0915\u0947\u0935\u0932 {{max}} \u092B\u093C\u093E\u0907\u0932\u0947\u0902 \u091C\u094B\u0921\u093C\u0940 \u091C\u093E \u0938\u0915\u0924\u0940 \u0939\u0948\u0902, \u0907\u0938\u0932\u093F\u090F {{name}} \u091B\u094B\u0921\u093C \u0926\u0940 \u0917\u0908\u0964",
4851
4869
  noAnswer: "\u092F\u0939 \u092E\u0941\u091D\u0947 \u0939\u092E\u093E\u0930\u0947 \u0926\u0938\u094D\u0924\u093E\u0935\u0947\u091C\u093C\u094B\u0902 \u092E\u0947\u0902 \u0928\u0939\u0940\u0902 \u092E\u093F\u0932\u093E, \u0907\u0938\u0932\u093F\u090F \u0928\u0940\u091A\u0947 \u0926\u093F\u092F\u093E \u0909\u0924\u094D\u0924\u0930 \u0915\u093F\u0938\u0940 \u0938\u094D\u0930\u094B\u0924 \u092A\u0930 \u0906\u0927\u093E\u0930\u093F\u0924 \u0928\u0939\u0940\u0902 \u0939\u0948\u0964 \u0926\u0942\u0938\u0930\u0947 \u0936\u092C\u094D\u0926\u094B\u0902 \u092E\u0947\u0902 \u092A\u0942\u091B\u0947\u0902, \u092F\u093E",
4852
4870
  askHuman: "\u0939\u092E\u0938\u0947 \u0938\u0902\u092A\u0930\u094D\u0915 \u0915\u0930\u0947\u0902",
4853
4871
  prevSuggestion: "\u092A\u093F\u091B\u0932\u093E \u0938\u0941\u091D\u093E\u0935",
@@ -4890,6 +4908,12 @@ var ES = {
4890
4908
  disclaimerShort: "Basado en nuestra documentaci\xF3n: comprueba cualquier dato importante.",
4891
4909
  dictate: "Dictar tu pregunta",
4892
4910
  stopDictating: "Dejar de dictar",
4911
+ attach: "Adjuntar archivos",
4912
+ attachHint: "Hasta {{max}} archivos, {{size}} MB cada uno",
4913
+ removeAttachment: "Quitar {{name}}",
4914
+ attachmentNameOnly: "solo nombre y tipo",
4915
+ attachmentTooLarge: "{{name}} supera los {{size}} MB y no se adjunt\xF3.",
4916
+ attachmentTooMany: "Solo se pueden adjuntar {{max}} archivos, as\xED que se omiti\xF3 {{name}}.",
4893
4917
  noAnswer: "No he encontrado esto en nuestra documentaci\xF3n, as\xED que la respuesta de abajo no se apoya en ninguna fuente. Prueba a reformularla, o",
4894
4918
  askHuman: "habla con una persona",
4895
4919
  prevSuggestion: "Sugerencia anterior",
@@ -4932,6 +4956,12 @@ var AR = {
4932
4956
  disclaimerShort: "\u0645\u0628\u0646\u064A \u0639\u0644\u0649 \u0648\u062B\u0627\u0626\u0642\u0646\u0627 \u2014 \u062A\u062D\u0642\u0651\u0642 \u0645\u0646 \u0623\u064A \u0645\u0639\u0644\u0648\u0645\u0629 \u0645\u0647\u0645\u0629.",
4933
4957
  dictate: "\u0623\u0645\u0644\u0650 \u0633\u0624\u0627\u0644\u0643",
4934
4958
  stopDictating: "\u0625\u064A\u0642\u0627\u0641 \u0627\u0644\u0625\u0645\u0644\u0627\u0621",
4959
+ attach: "\u0625\u0631\u0641\u0627\u0642 \u0645\u0644\u0641\u0627\u062A",
4960
+ attachHint: "\u062D\u062A\u0649 {{max}} \u0645\u0644\u0641\u0627\u062A\u060C \u0628\u062D\u062F \u0623\u0642\u0635\u0649 {{size}} \u0645\u064A\u063A\u0627\u0628\u0627\u064A\u062A \u0644\u0643\u0644 \u0645\u0644\u0641",
4961
+ removeAttachment: "\u0625\u0632\u0627\u0644\u0629 {{name}}",
4962
+ attachmentNameOnly: "\u0627\u0644\u0627\u0633\u0645 \u0648\u0627\u0644\u0646\u0648\u0639 \u0641\u0642\u0637",
4963
+ attachmentTooLarge: "{{name}} \u0623\u0643\u0628\u0631 \u0645\u0646 {{size}} \u0645\u064A\u063A\u0627\u0628\u0627\u064A\u062A \u0648\u0644\u0645 \u064A\u062A\u0645 \u0625\u0631\u0641\u0627\u0642\u0647.",
4964
+ attachmentTooMany: "\u064A\u0645\u0643\u0646 \u0625\u0631\u0641\u0627\u0642 {{max}} \u0645\u0644\u0641\u0627\u062A \u0641\u0642\u0637\u060C \u0644\u0630\u0627 \u062A\u0645 \u062A\u062E\u0637\u064A {{name}}.",
4935
4965
  noAnswer: "\u0644\u0645 \u0623\u062C\u062F \u0647\u0630\u0627 \u0641\u064A \u0648\u062B\u0627\u0626\u0642\u0646\u0627\u060C \u0644\u0630\u0627 \u0641\u0627\u0644\u0625\u062C\u0627\u0628\u0629 \u0623\u062F\u0646\u0627\u0647 \u063A\u064A\u0631 \u0645\u0633\u062A\u0646\u062F\u0629 \u0625\u0644\u0649 \u0645\u0635\u062F\u0631. \u062D\u0627\u0648\u0644 \u0625\u0639\u0627\u062F\u0629 \u0627\u0644\u0635\u064A\u0627\u063A\u0629\u060C \u0623\u0648",
4936
4966
  askHuman: "\u062A\u062D\u062F\u0651\u062B \u0625\u0644\u0649 \u0634\u062E\u0635",
4937
4967
  prevSuggestion: "\u0627\u0644\u0627\u0642\u062A\u0631\u0627\u062D \u0627\u0644\u0633\u0627\u0628\u0642",
@@ -4974,6 +5004,12 @@ var TA = {
4974
5004
  disclaimerShort: "\u0B8E\u0B99\u0BCD\u0B95\u0BB3\u0BCD \u0B86\u0BB5\u0BA3\u0B99\u0BCD\u0B95\u0BB3\u0BC8 \u0B85\u0B9F\u0BBF\u0BAA\u0BCD\u0BAA\u0B9F\u0BC8\u0BAF\u0BBE\u0B95\u0B95\u0BCD \u0B95\u0BCA\u0BA3\u0BCD\u0B9F\u0BA4\u0BC1 \u2014 \u0BAE\u0BC1\u0B95\u0BCD\u0B95\u0BBF\u0BAF\u0BAE\u0BBE\u0BA9\u0BA4\u0BC8\u0B9A\u0BCD \u0B9A\u0BB0\u0BBF\u0BAA\u0BBE\u0BB0\u0BCD\u0B95\u0BCD\u0B95\u0BB5\u0BC1\u0BAE\u0BCD.",
4975
5005
  dictate: "\u0B89\u0B99\u0BCD\u0B95\u0BB3\u0BCD \u0B95\u0BC7\u0BB3\u0BCD\u0BB5\u0BBF\u0BAF\u0BC8\u0BAA\u0BCD \u0BAA\u0BC7\u0B9A\u0BC1\u0B99\u0BCD\u0B95\u0BB3\u0BCD",
4976
5006
  stopDictating: "\u0BAA\u0BC7\u0B9A\u0BC1\u0BB5\u0BA4\u0BC8 \u0BA8\u0BBF\u0BB1\u0BC1\u0BA4\u0BCD\u0BA4\u0BC1",
5007
+ attach: "\u0B95\u0BCB\u0BAA\u0BCD\u0BAA\u0BC1\u0B95\u0BB3\u0BC8 \u0B87\u0BA3\u0BC8\u0B95\u0BCD\u0B95",
5008
+ attachHint: "\u0B85\u0BA4\u0BBF\u0B95\u0BAA\u0B9F\u0BCD\u0B9A\u0BAE\u0BCD {{max}} \u0B95\u0BCB\u0BAA\u0BCD\u0BAA\u0BC1\u0B95\u0BB3\u0BCD, \u0B92\u0BB5\u0BCD\u0BB5\u0BCA\u0BA9\u0BCD\u0BB1\u0BC1\u0BAE\u0BCD {{size}} MB \u0BB5\u0BB0\u0BC8",
5009
+ removeAttachment: "{{name}} \u0B85\u0B95\u0BB1\u0BCD\u0BB1\u0BC1",
5010
+ attachmentNameOnly: "\u0BAA\u0BC6\u0BAF\u0BB0\u0BC1\u0BAE\u0BCD \u0BB5\u0B95\u0BC8\u0BAF\u0BC1\u0BAE\u0BCD \u0BAE\u0B9F\u0BCD\u0B9F\u0BC1\u0BAE\u0BCD",
5011
+ attachmentTooLarge: "{{name}} {{size}} MB-\u0B90 \u0BB5\u0BBF\u0B9F \u0BAA\u0BC6\u0BB0\u0BBF\u0BAF\u0BA4\u0BC1, \u0B8E\u0BA9\u0BB5\u0BC7 \u0B87\u0BA3\u0BC8\u0B95\u0BCD\u0B95\u0BAA\u0BCD\u0BAA\u0B9F\u0BB5\u0BBF\u0BB2\u0BCD\u0BB2\u0BC8.",
5012
+ attachmentTooMany: "{{max}} \u0B95\u0BCB\u0BAA\u0BCD\u0BAA\u0BC1\u0B95\u0BB3\u0BCD \u0BAE\u0B9F\u0BCD\u0B9F\u0BC1\u0BAE\u0BC7 \u0B87\u0BA3\u0BC8\u0B95\u0BCD\u0B95 \u0BAE\u0BC1\u0B9F\u0BBF\u0BAF\u0BC1\u0BAE\u0BCD, \u0B8E\u0BA9\u0BB5\u0BC7 {{name}} \u0BA4\u0BB5\u0BBF\u0BB0\u0BCD\u0B95\u0BCD\u0B95\u0BAA\u0BCD\u0BAA\u0B9F\u0BCD\u0B9F\u0BA4\u0BC1.",
4977
5013
  noAnswer: "\u0B87\u0BA4\u0BC1 \u0B8E\u0B99\u0BCD\u0B95\u0BB3\u0BCD \u0B86\u0BB5\u0BA3\u0B99\u0BCD\u0B95\u0BB3\u0BBF\u0BB2\u0BCD \u0B95\u0BBF\u0B9F\u0BC8\u0B95\u0BCD\u0B95\u0BB5\u0BBF\u0BB2\u0BCD\u0BB2\u0BC8, \u0B8E\u0BA9\u0BB5\u0BC7 \u0B95\u0BC0\u0BB4\u0BC7 \u0B89\u0BB3\u0BCD\u0BB3 \u0BAA\u0BA4\u0BBF\u0BB2\u0BC1\u0B95\u0BCD\u0B95\u0BC1 \u0BAE\u0BC2\u0BB2\u0BAE\u0BCD \u0B87\u0BB2\u0BCD\u0BB2\u0BC8. \u0BB5\u0BC7\u0BB1\u0BC1 \u0BB5\u0B95\u0BC8\u0BAF\u0BBF\u0BB2\u0BCD \u0B95\u0BC7\u0BB3\u0BC1\u0B99\u0BCD\u0B95\u0BB3\u0BCD, \u0B85\u0BB2\u0BCD\u0BB2\u0BA4\u0BC1",
4978
5014
  askHuman: "\u0B8E\u0B99\u0BCD\u0B95\u0BB3\u0BC8\u0BA4\u0BCD \u0BA4\u0BCA\u0B9F\u0BB0\u0BCD\u0BAA\u0BC1 \u0B95\u0BCA\u0BB3\u0BCD\u0BB3\u0BC1\u0B99\u0BCD\u0B95\u0BB3\u0BCD",
4979
5015
  prevSuggestion: "\u0BAE\u0BC1\u0BA8\u0BCD\u0BA4\u0BC8\u0BAF \u0BAA\u0BB0\u0BBF\u0BA8\u0BCD\u0BA4\u0BC1\u0BB0\u0BC8",
@@ -5222,6 +5258,12 @@ var EXPLORE_MESSAGE_FIELDS = (
5222
5258
  }
5223
5259
  followUps
5224
5260
  answered
5261
+ attachments {
5262
+ name
5263
+ mimeType
5264
+ size
5265
+ textExtracted
5266
+ }
5225
5267
  errorCode
5226
5268
  createdAt
5227
5269
  completedAt
@@ -5307,6 +5349,16 @@ var CREATE_EXPLORE_SHARE_LINK_MUTATION = (
5307
5349
  }
5308
5350
  `
5309
5351
  );
5352
+ var EXPLORE_SHARED_CONVERSATION_QUERY = (
5353
+ /* GraphQL */
5354
+ `
5355
+ query ExploreSharedConversation($shareToken: String!) {
5356
+ exploreSharedConversation(shareToken: $shareToken) {
5357
+ ${EXPLORE_MESSAGE_FIELDS}
5358
+ }
5359
+ }
5360
+ `
5361
+ );
5310
5362
 
5311
5363
  // src/data/products.ts
5312
5364
  var ECOSYSTEM_PRODUCTS = [
@@ -5757,6 +5809,14 @@ function readPersisted(key) {
5757
5809
  return null;
5758
5810
  }
5759
5811
  }
5812
+ function readShareToken() {
5813
+ if (typeof window === "undefined") return null;
5814
+ try {
5815
+ return new URL(window.location.href).searchParams.get("c");
5816
+ } catch {
5817
+ return null;
5818
+ }
5819
+ }
5760
5820
  function visibleText(message) {
5761
5821
  return message.content || message.partialContent || "";
5762
5822
  }
@@ -5795,10 +5855,18 @@ function useExploreChat(options = {}) {
5795
5855
  const pollGenerationRef = useRef(0);
5796
5856
  const pollTimerRef = useRef(null);
5797
5857
  const conversationTokenRef = useRef(null);
5858
+ const shareTokenRef = useRef(void 0);
5859
+ if (shareTokenRef.current === void 0) {
5860
+ shareTokenRef.current = readShareToken();
5861
+ }
5862
+ const isSharedView = shareTokenRef.current !== null;
5798
5863
  const catalogRef = useRef(fallbackCatalog);
5799
5864
  const turnCountRef = useRef(0);
5800
5865
  const focusProductRef = useRef(null);
5801
5866
  const lastSentTextRef = useRef(null);
5867
+ const lastSentAttachmentsRef = useRef(
5868
+ []
5869
+ );
5802
5870
  const inFlightRef = useRef(false);
5803
5871
  catalogRef.current = catalog;
5804
5872
  const clearPollTimer = useCallback(() => {
@@ -5823,6 +5891,43 @@ function useExploreChat(options = {}) {
5823
5891
  };
5824
5892
  }, []);
5825
5893
  useEffect(() => {
5894
+ const shareToken = shareTokenRef.current;
5895
+ if (!shareToken) return;
5896
+ let cancelled = false;
5897
+ setHydrated(true);
5898
+ void client.query(
5899
+ EXPLORE_SHARED_CONVERSATION_QUERY,
5900
+ { shareToken },
5901
+ { cache: false }
5902
+ ).then((res) => {
5903
+ if (cancelled || !mountedRef.current) return;
5904
+ const shared = res?.data?.exploreSharedConversation;
5905
+ if (shared && shared.length > 0) {
5906
+ setMessages(shared);
5907
+ return;
5908
+ }
5909
+ setError({
5910
+ kind: "unknown",
5911
+ code: "SHARE_NOT_FOUND",
5912
+ message: "That shared conversation could not be found. The link may have expired.",
5913
+ // Nothing to retry: a bad token will stay bad.
5914
+ retryable: false
5915
+ });
5916
+ }).catch(() => {
5917
+ if (cancelled || !mountedRef.current) return;
5918
+ setError({
5919
+ kind: "unknown",
5920
+ code: "SHARE_NOT_FOUND",
5921
+ message: "That shared conversation could not be loaded.",
5922
+ retryable: true
5923
+ });
5924
+ });
5925
+ return () => {
5926
+ cancelled = true;
5927
+ };
5928
+ }, [client]);
5929
+ useEffect(() => {
5930
+ if (shareTokenRef.current !== null) return;
5826
5931
  if (!persist) {
5827
5932
  setHydrated(true);
5828
5933
  return;
@@ -5990,7 +6095,7 @@ function useExploreChat(options = {}) {
5990
6095
  [client, pollIntervalMs, pollTimeoutMs]
5991
6096
  );
5992
6097
  const submit = useCallback(
5993
- async (text, optimisticId, captchaAttempt) => {
6098
+ async (text, optimisticId, captchaAttempt, attachments) => {
5994
6099
  const activeCatalog = catalogRef.current;
5995
6100
  let recaptchaToken;
5996
6101
  if (activeCatalog.captchaRequired && activeCatalog.recaptchaSiteKey) {
@@ -6008,7 +6113,8 @@ function useExploreChat(options = {}) {
6008
6113
  ...focusProductRef.current || productSlug ? { productSlug: focusProductRef.current ?? productSlug } : {},
6009
6114
  ...recaptchaToken ? { recaptchaToken } : {},
6010
6115
  ...locale ? { locale } : {},
6011
- ...pageUrl ? { pageUrl } : {}
6116
+ ...pageUrl ? { pageUrl } : {},
6117
+ ...attachments.length > 0 ? { attachments: [...attachments] } : {}
6012
6118
  };
6013
6119
  const res = await client.mutate(
6014
6120
  SEND_EXPLORE_MESSAGE_MUTATION,
@@ -6022,7 +6128,7 @@ function useExploreChat(options = {}) {
6022
6128
  const code = typeof first?.extensions?.code === "string" ? first.extensions.code : void 0;
6023
6129
  const classified = classifyExploreError(code, first?.message);
6024
6130
  if (classified.kind === "captcha" && captchaAttempt === 0) {
6025
- await submit(text, optimisticId, 1);
6131
+ await submit(text, optimisticId, 1, attachments);
6026
6132
  return;
6027
6133
  }
6028
6134
  inFlightRef.current = false;
@@ -6059,7 +6165,7 @@ function useExploreChat(options = {}) {
6059
6165
  [client, locale, pageUrl, productSlug, startPolling]
6060
6166
  );
6061
6167
  const send = useCallback(
6062
- async (message) => {
6168
+ async (message, attachments = []) => {
6063
6169
  const text = message.trim();
6064
6170
  if (!text) return;
6065
6171
  if (inFlightRef.current) return;
@@ -6089,6 +6195,7 @@ function useExploreChat(options = {}) {
6089
6195
  }
6090
6196
  inFlightRef.current = true;
6091
6197
  lastSentTextRef.current = text;
6198
+ lastSentAttachmentsRef.current = attachments;
6092
6199
  setError(null);
6093
6200
  setPhase("sending");
6094
6201
  cancelPolling();
@@ -6111,7 +6218,7 @@ function useExploreChat(options = {}) {
6111
6218
  setTurnCount(turnCountRef.current);
6112
6219
  onSend?.(text);
6113
6220
  try {
6114
- await submit(text, optimistic.id, 0);
6221
+ await submit(text, optimistic.id, 0, attachments);
6115
6222
  } catch (err) {
6116
6223
  if (!mountedRef.current) return;
6117
6224
  console.error("[WebSDK] Explore send failed", err);
@@ -6160,7 +6267,7 @@ function useExploreChat(options = {}) {
6160
6267
  });
6161
6268
  turnCountRef.current = Math.max(0, turnCountRef.current - 1);
6162
6269
  setTurnCount(turnCountRef.current);
6163
- void send(text);
6270
+ void send(text, lastSentAttachmentsRef.current);
6164
6271
  }, [cancelPolling, send]);
6165
6272
  const reset = useCallback(() => {
6166
6273
  setArchive(
@@ -6174,6 +6281,7 @@ function useExploreChat(options = {}) {
6174
6281
  inFlightRef.current = false;
6175
6282
  conversationTokenRef.current = null;
6176
6283
  lastSentTextRef.current = null;
6284
+ lastSentAttachmentsRef.current = [];
6177
6285
  turnCountRef.current = 0;
6178
6286
  setTurnCount(0);
6179
6287
  setMessages([]);
@@ -6282,7 +6390,8 @@ function useExploreChat(options = {}) {
6282
6390
  deleteConversation,
6283
6391
  clearHistory,
6284
6392
  recordClick,
6285
- createShareLink
6393
+ createShareLink,
6394
+ isSharedView
6286
6395
  };
6287
6396
  }
6288
6397
  var optimisticCounter = 0;
@@ -6541,6 +6650,145 @@ function useSwipe({
6541
6650
  }, []);
6542
6651
  return { onPointerDown, onPointerUp, onPointerCancel };
6543
6652
  }
6653
+
6654
+ // src/utils/explore-attachments.ts
6655
+ var MAX_ATTACHMENTS = 5;
6656
+ var MAX_ATTACHMENT_BYTES = 10 * 1024 * 1024;
6657
+ var MAX_TEXT_PER_ATTACHMENT = 2e4;
6658
+ var TEXT_EXTENSIONS = /* @__PURE__ */ new Set([
6659
+ "txt",
6660
+ "md",
6661
+ "markdown",
6662
+ "csv",
6663
+ "tsv",
6664
+ "json",
6665
+ "jsonl",
6666
+ "yaml",
6667
+ "yml",
6668
+ "toml",
6669
+ "ini",
6670
+ "cfg",
6671
+ "conf",
6672
+ "env",
6673
+ "log",
6674
+ "sql",
6675
+ "graphql",
6676
+ "gql",
6677
+ "html",
6678
+ "htm",
6679
+ "xml",
6680
+ "svg",
6681
+ "css",
6682
+ "scss",
6683
+ "js",
6684
+ "jsx",
6685
+ "mjs",
6686
+ "cjs",
6687
+ "ts",
6688
+ "tsx",
6689
+ "py",
6690
+ "rb",
6691
+ "go",
6692
+ "rs",
6693
+ "java",
6694
+ "kt",
6695
+ "c",
6696
+ "h",
6697
+ "cpp",
6698
+ "cs",
6699
+ "php",
6700
+ "sh",
6701
+ "bash",
6702
+ "zsh",
6703
+ "ps1",
6704
+ "dockerfile",
6705
+ "tf",
6706
+ "tfvars"
6707
+ ]);
6708
+ function isTextualMimeType(mimeType) {
6709
+ if (mimeType.startsWith("text/")) return true;
6710
+ return mimeType === "application/json" || mimeType === "application/xml" || mimeType === "application/yaml" || mimeType === "application/x-yaml" || mimeType === "application/javascript" || mimeType === "application/graphql" || mimeType.endsWith("+json") || mimeType.endsWith("+xml");
6711
+ }
6712
+ function extensionOf(name) {
6713
+ const dot = name.lastIndexOf(".");
6714
+ if (dot <= 0 || dot === name.length - 1) return "";
6715
+ return name.slice(dot + 1).toLowerCase();
6716
+ }
6717
+ function looksTextual(name, mimeType) {
6718
+ if (isTextualMimeType(mimeType)) return true;
6719
+ return TEXT_EXTENSIONS.has(extensionOf(name));
6720
+ }
6721
+ function isDecodedTextUsable(decoded) {
6722
+ if (decoded.length === 0) return false;
6723
+ if (decoded.includes("\0")) return false;
6724
+ let replacements = 0;
6725
+ for (const char of decoded) if (char === "\uFFFD") replacements += 1;
6726
+ return replacements / decoded.length < 0.1;
6727
+ }
6728
+ function formatBytes(bytes) {
6729
+ if (bytes < 1024) return `${bytes} B`;
6730
+ if (bytes < 1024 * 1024) return `${Math.round(bytes / 1024)} KB`;
6731
+ return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
6732
+ }
6733
+ var counter = 0;
6734
+ function nextId() {
6735
+ counter += 1;
6736
+ return `att-${counter}`;
6737
+ }
6738
+ async function readArrayBuffer(blob) {
6739
+ if (typeof blob.arrayBuffer === "function") return blob.arrayBuffer();
6740
+ return new Promise((resolve, reject) => {
6741
+ const reader = new FileReader();
6742
+ reader.onload = () => resolve(reader.result);
6743
+ reader.onerror = () => reject(reader.error ?? new Error("file read failed"));
6744
+ reader.readAsArrayBuffer(blob);
6745
+ });
6746
+ }
6747
+ async function readTextPrefix(file) {
6748
+ try {
6749
+ const slice = file.slice(0, MAX_TEXT_PER_ATTACHMENT);
6750
+ const buffer = await readArrayBuffer(slice);
6751
+ const decoded = new TextDecoder("utf-8").decode(buffer);
6752
+ return isDecodedTextUsable(decoded) ? decoded : null;
6753
+ } catch {
6754
+ return null;
6755
+ }
6756
+ }
6757
+ async function stageFiles(files, alreadyStaged) {
6758
+ const accepted = [];
6759
+ const rejected = [];
6760
+ let slots = MAX_ATTACHMENTS - alreadyStaged.length;
6761
+ for (const file of files) {
6762
+ if (slots <= 0) {
6763
+ rejected.push({ name: file.name, reason: "too-many" });
6764
+ continue;
6765
+ }
6766
+ if (file.size > MAX_ATTACHMENT_BYTES) {
6767
+ rejected.push({ name: file.name, reason: "too-large" });
6768
+ continue;
6769
+ }
6770
+ const mimeType = file.type || "application/octet-stream";
6771
+ const textContent = looksTextual(file.name, mimeType) ? await readTextPrefix(file) : null;
6772
+ accepted.push({
6773
+ id: nextId(),
6774
+ name: file.name,
6775
+ mimeType,
6776
+ size: file.size,
6777
+ textContent,
6778
+ textExtracted: textContent !== null
6779
+ });
6780
+ slots -= 1;
6781
+ }
6782
+ return { accepted, rejected };
6783
+ }
6784
+ function toPayload(staged) {
6785
+ return staged.map(({ name, mimeType, size, textContent }) => ({
6786
+ name,
6787
+ mimeType,
6788
+ size,
6789
+ textContent
6790
+ }));
6791
+ }
6544
6792
  var EXPLORE_CSS = `
6545
6793
  @keyframes boff-explore-pulse {
6546
6794
  0%, 80%, 100% { opacity: 0.25; transform: translateY(0); }
@@ -6889,15 +7137,45 @@ function ThinkingIndicator({ activity }) {
6889
7137
  }
6890
7138
  );
6891
7139
  }
6892
- function UserBubble({ message }) {
6893
- return /* @__PURE__ */ jsx("div", { className: "flex justify-end", children: /* @__PURE__ */ jsx(
6894
- "div",
6895
- {
6896
- "data-boff-explore": "user",
6897
- className: "max-w-[85%] whitespace-pre-wrap break-words rounded-2xl rounded-br-md bg-primary px-4 py-2.5 text-sm leading-relaxed text-primary-foreground shadow-sm",
6898
- children: message.content
6899
- }
6900
- ) });
7140
+ function UserBubble({
7141
+ strings: T,
7142
+ message
7143
+ }) {
7144
+ const attachments = message.attachments ?? [];
7145
+ return /* @__PURE__ */ jsxs("div", { className: "flex flex-col items-end gap-1.5", children: [
7146
+ /* @__PURE__ */ jsx(
7147
+ "div",
7148
+ {
7149
+ "data-boff-explore": "user",
7150
+ className: "max-w-[85%] whitespace-pre-wrap break-words rounded-2xl rounded-br-md bg-primary px-4 py-2.5 text-sm leading-relaxed text-primary-foreground shadow-sm",
7151
+ children: message.content
7152
+ }
7153
+ ),
7154
+ attachments.length > 0 ? /* @__PURE__ */ jsx(
7155
+ "ul",
7156
+ {
7157
+ "data-boff-explore": "user-attachments",
7158
+ className: "flex max-w-[85%] flex-wrap justify-end gap-1.5",
7159
+ children: attachments.map((attachment) => /* @__PURE__ */ jsxs(
7160
+ "li",
7161
+ {
7162
+ "data-boff-explore": "user-attachment",
7163
+ "data-text-extracted": attachment.textExtracted ? "true" : "false",
7164
+ className: "flex max-w-full items-center gap-1.5 rounded-full border border-border bg-muted/60 px-2.5 py-1 text-xs text-muted-foreground",
7165
+ children: [
7166
+ /* @__PURE__ */ jsx(Paperclip, { className: "h-3 w-3 shrink-0" }),
7167
+ /* @__PURE__ */ jsx("span", { className: "truncate", title: attachment.name, children: attachment.name }),
7168
+ attachment.textExtracted ? null : /* @__PURE__ */ jsxs("span", { className: "shrink-0", children: [
7169
+ "\xB7 ",
7170
+ T.attachmentNameOnly
7171
+ ] })
7172
+ ]
7173
+ },
7174
+ `${attachment.name}-${attachment.size}`
7175
+ ))
7176
+ }
7177
+ ) : null
7178
+ ] });
6901
7179
  }
6902
7180
  function AssistantBubble({
6903
7181
  strings: T,
@@ -7396,7 +7674,8 @@ function ExplorePage({
7396
7674
  deleteConversation,
7397
7675
  clearHistory,
7398
7676
  recordClick,
7399
- createShareLink
7677
+ createShareLink,
7678
+ isSharedView
7400
7679
  } = useExploreChat({ productSlug, pageUrl, onSend, examplePrompts });
7401
7680
  const [draft, setDraft] = useState("");
7402
7681
  const textareaRef = useRef(null);
@@ -7422,6 +7701,12 @@ function ExplorePage({
7422
7701
  const T = useMemo(() => exploreStrings(activeLocale), [activeLocale]);
7423
7702
  const rtl = isRtlLocale(activeLocale);
7424
7703
  const [disclaimerOpen, setDisclaimerOpen] = useState(false);
7704
+ const [staged, setStaged] = useState([]);
7705
+ const [attachmentNotice, setAttachmentNotice] = useState(null);
7706
+ const fileInputRef = useRef(null);
7707
+ const stagedRef = useRef([]);
7708
+ stagedRef.current = staged;
7709
+ const pickQueueRef = useRef(Promise.resolve());
7425
7710
  const [shareLabel, setShareLabel] = useState("Share");
7426
7711
  const [shareUrl, setShareUrl] = useState(null);
7427
7712
  const scrollRef = useRef(null);
@@ -7498,13 +7783,44 @@ function ExplorePage({
7498
7783
  setShareLabel("Share");
7499
7784
  }
7500
7785
  }, [createShareLink, pageUrl]);
7786
+ const handleFilesPicked = useCallback(
7787
+ (picked) => {
7788
+ if (!picked || picked.length === 0) return pickQueueRef.current;
7789
+ const files = Array.from(picked);
7790
+ pickQueueRef.current = pickQueueRef.current.then(async () => {
7791
+ const { accepted, rejected } = await stageFiles(
7792
+ files,
7793
+ stagedRef.current
7794
+ );
7795
+ setStaged((prev) => [...prev, ...accepted]);
7796
+ const first = rejected[0];
7797
+ setAttachmentNotice(
7798
+ first ? first.reason === "too-large" ? fill(T.attachmentTooLarge, {
7799
+ name: first.name,
7800
+ size: String(MAX_ATTACHMENT_BYTES / (1024 * 1024))
7801
+ }) : fill(T.attachmentTooMany, {
7802
+ name: first.name,
7803
+ max: String(MAX_ATTACHMENTS)
7804
+ }) : null
7805
+ );
7806
+ });
7807
+ return pickQueueRef.current;
7808
+ },
7809
+ [T]
7810
+ );
7811
+ const removeAttachment = useCallback((id) => {
7812
+ setStaged((prev) => prev.filter((entry) => entry.id !== id));
7813
+ setAttachmentNotice(null);
7814
+ }, []);
7501
7815
  const submitDraft = useCallback(() => {
7502
7816
  const text = draft.trim();
7503
7817
  if (!text || overLimit || busy || !canSend) return;
7504
7818
  stopDictation();
7505
7819
  setDraft("");
7506
7820
  stickToBottomRef.current = true;
7507
- void send(text);
7821
+ void send(text, toPayload(stagedRef.current));
7822
+ setStaged([]);
7823
+ setAttachmentNotice(null);
7508
7824
  textareaRef.current?.focus();
7509
7825
  }, [busy, canSend, draft, overLimit, send, stopDictation]);
7510
7826
  const sendPrompt = useCallback(
@@ -7512,7 +7828,9 @@ function ExplorePage({
7512
7828
  if (!canSend || busy) return;
7513
7829
  setDraft("");
7514
7830
  stickToBottomRef.current = true;
7515
- void send(prompt);
7831
+ void send(prompt, toPayload(stagedRef.current));
7832
+ setStaged([]);
7833
+ setAttachmentNotice(null);
7516
7834
  },
7517
7835
  [busy, canSend, send]
7518
7836
  );
@@ -7525,7 +7843,9 @@ function ExplorePage({
7525
7843
  },
7526
7844
  [submitDraft]
7527
7845
  );
7528
- const composerDisabled = phase === "limited" || phase === "disabled" || !catalog.enabled;
7846
+ const composerDisabled = phase === "limited" || phase === "disabled" || !catalog.enabled || // A share token grants read access only — the server would reject a send anyway, so
7847
+ // disable it here rather than letting the visitor type into a dead composer.
7848
+ isSharedView;
7529
7849
  const captchaOn = Boolean(
7530
7850
  catalog.captchaRequired && catalog.recaptchaSiteKey
7531
7851
  );
@@ -7719,7 +8039,7 @@ function ExplorePage({
7719
8039
  disabled: !canSend || busy
7720
8040
  }
7721
8041
  ) : /* @__PURE__ */ jsx("div", { className: "mx-auto w-full min-w-0 max-w-3xl space-y-6 px-4 py-6", children: messages.map(
7722
- (message) => message.role === "USER" ? /* @__PURE__ */ jsx(UserBubble, { message }, message.id) : /* @__PURE__ */ jsx(
8042
+ (message) => message.role === "USER" ? /* @__PURE__ */ jsx(UserBubble, { strings: T, message }, message.id) : /* @__PURE__ */ jsx(
7723
8043
  AssistantBubble,
7724
8044
  {
7725
8045
  strings: T,
@@ -7743,6 +8063,33 @@ function ExplorePage({
7743
8063
  captchaOn
7744
8064
  }
7745
8065
  ),
8066
+ isSharedView ? /* @__PURE__ */ jsxs(
8067
+ "div",
8068
+ {
8069
+ "data-boff-explore": "shared-banner",
8070
+ className: "mx-auto flex w-full max-w-3xl items-center gap-2 px-4 pb-2 text-xs text-muted-foreground",
8071
+ children: [
8072
+ /* @__PURE__ */ jsx(Link2, { className: "h-3.5 w-3.5 shrink-0" }),
8073
+ /* @__PURE__ */ jsx("span", { className: "min-w-0 flex-1", children: "You are viewing a shared conversation. Start your own to ask a question." }),
8074
+ /* @__PURE__ */ jsx(
8075
+ "button",
8076
+ {
8077
+ type: "button",
8078
+ "data-boff-explore": "shared-start-own",
8079
+ onClick: () => {
8080
+ if (typeof window !== "undefined") {
8081
+ const url = new URL(window.location.href);
8082
+ url.searchParams.delete("c");
8083
+ window.location.href = url.toString();
8084
+ }
8085
+ },
8086
+ className: "shrink-0 underline underline-offset-2 hover:text-foreground",
8087
+ children: "New chat"
8088
+ }
8089
+ )
8090
+ ]
8091
+ }
8092
+ ) : null,
7746
8093
  /* @__PURE__ */ jsx("div", { className: "border-t border-border bg-background/85 px-4 pb-[max(1rem,env(safe-area-inset-bottom))] pt-3 backdrop-blur-md", children: /* @__PURE__ */ jsxs(
7747
8094
  "form",
7748
8095
  {
@@ -7754,6 +8101,51 @@ function ExplorePage({
7754
8101
  },
7755
8102
  children: [
7756
8103
  error ? /* @__PURE__ */ jsx(ErrorBanner, { error, onRetry: retry, onReset: reset }) : null,
8104
+ staged.length > 0 ? /* @__PURE__ */ jsx(
8105
+ "ul",
8106
+ {
8107
+ "data-boff-explore": "attachments",
8108
+ className: "mb-2 flex flex-wrap gap-1.5",
8109
+ "aria-label": T.attach,
8110
+ children: staged.map((entry) => /* @__PURE__ */ jsxs(
8111
+ "li",
8112
+ {
8113
+ "data-boff-explore": "attachment",
8114
+ "data-text-extracted": entry.textExtracted ? "true" : "false",
8115
+ className: "flex max-w-full items-center gap-1.5 rounded-full border border-border bg-muted/60 py-1 pl-2.5 pr-1 text-xs",
8116
+ children: [
8117
+ /* @__PURE__ */ jsx(Paperclip, { className: "h-3 w-3 shrink-0 text-muted-foreground" }),
8118
+ /* @__PURE__ */ jsx("span", { className: "truncate font-medium", title: entry.name, children: entry.name }),
8119
+ /* @__PURE__ */ jsxs("span", { className: "shrink-0 text-muted-foreground", children: [
8120
+ formatBytes(entry.size),
8121
+ entry.textExtracted ? "" : ` \xB7 ${T.attachmentNameOnly}`
8122
+ ] }),
8123
+ /* @__PURE__ */ jsx(
8124
+ "button",
8125
+ {
8126
+ type: "button",
8127
+ "data-boff-explore": "attachment-remove",
8128
+ onClick: () => removeAttachment(entry.id),
8129
+ "aria-label": fill(T.removeAttachment, { name: entry.name }),
8130
+ className: "ml-0.5 flex h-5 w-5 shrink-0 items-center justify-center rounded-full text-muted-foreground transition-colors hover:bg-background hover:text-foreground",
8131
+ children: /* @__PURE__ */ jsx(X, { className: "h-3 w-3" })
8132
+ }
8133
+ )
8134
+ ]
8135
+ },
8136
+ entry.id
8137
+ ))
8138
+ }
8139
+ ) : null,
8140
+ attachmentNotice !== null ? /* @__PURE__ */ jsx(
8141
+ "p",
8142
+ {
8143
+ "data-boff-explore": "attachment-notice",
8144
+ role: "status",
8145
+ className: "mb-2 text-xs text-destructive",
8146
+ children: attachmentNotice
8147
+ }
8148
+ ) : null,
7757
8149
  /* @__PURE__ */ jsxs(
7758
8150
  "div",
7759
8151
  {
@@ -7782,7 +8174,37 @@ function ExplorePage({
7782
8174
  placeholder: composerDisabled ? phase === "limited" ? "Message limit reached \u2014 please try again later" : "Explore is unavailable right now" : focusedProductName ? fill(T.placeholderProduct, {
7783
8175
  product: focusedProductName
7784
8176
  }) : T.placeholder,
7785
- className: "max-h-[200px] min-h-[44px] w-full min-w-0 flex-1 resize-none border-0 bg-transparent px-2 py-2.5 text-sm shadow-none focus-visible:ring-0 md:text-sm"
8177
+ className: "max-h-[200px] min-h-[44px] w-full min-w-0 flex-1 resize-none border-0 bg-transparent px-2 py-2.5 text-base shadow-none focus-visible:ring-0 sm:text-sm"
8178
+ }
8179
+ ),
8180
+ /* @__PURE__ */ jsx(
8181
+ "input",
8182
+ {
8183
+ ref: fileInputRef,
8184
+ type: "file",
8185
+ multiple: true,
8186
+ className: "hidden",
8187
+ onChange: (event) => {
8188
+ void handleFilesPicked(event.target.files);
8189
+ event.target.value = "";
8190
+ }
8191
+ }
8192
+ ),
8193
+ /* @__PURE__ */ jsx(
8194
+ Button,
8195
+ {
8196
+ "data-boff-explore": "attach",
8197
+ type: "button",
8198
+ size: "icon",
8199
+ variant: "ghost",
8200
+ disabled: composerDisabled || staged.length >= MAX_ATTACHMENTS,
8201
+ "aria-label": T.attach,
8202
+ title: `${T.attach} \u2014 ${fill(T.attachHint, {
8203
+ max: String(MAX_ATTACHMENTS),
8204
+ size: String(MAX_ATTACHMENT_BYTES / (1024 * 1024))
8205
+ })}`,
8206
+ onClick: () => fileInputRef.current?.click(),
8207
+ children: /* @__PURE__ */ jsx(Paperclip, { className: "h-4 w-4" })
7786
8208
  }
7787
8209
  ),
7788
8210
  speech.supported ? /* @__PURE__ */ jsx(
@@ -9767,7 +10189,7 @@ function ChangelogPage(props) {
9767
10189
  }
9768
10190
 
9769
10191
  // src/content/utils.ts
9770
- function formatBytes(bytes) {
10192
+ function formatBytes2(bytes) {
9771
10193
  if (bytes == null) return "";
9772
10194
  if (bytes < 1024) return `${bytes} B`;
9773
10195
  if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(0)} KB`;
@@ -9888,7 +10310,7 @@ function PressKitLightbox({
9888
10310
  }, [asset, onClose]);
9889
10311
  if (!asset) return null;
9890
10312
  const ext = (asset.mimeType || "file").split("/").pop()?.toUpperCase() || "FILE";
9891
- const size = formatBytes(asset.fileSize);
10313
+ const size = formatBytes2(asset.fileSize);
9892
10314
  return /* @__PURE__ */ jsx(
9893
10315
  "div",
9894
10316
  {
@@ -9997,7 +10419,7 @@ function AssetCard({
9997
10419
  day: "numeric"
9998
10420
  }) : "";
9999
10421
  const ext = (asset.mimeType || "file").split("/").pop()?.toUpperCase() || "FILE";
10000
- const size = formatBytes(asset.fileSize);
10422
+ const size = formatBytes2(asset.fileSize);
10001
10423
  const [imgError, setImgError] = useState(false);
10002
10424
  const thumb = asset.thumbnailUrl && !imgError ? /* @__PURE__ */ jsx("div", { className: "aspect-[16/9] overflow-hidden bg-muted/30", children: /* @__PURE__ */ jsx(
10003
10425
  "img",
@@ -10501,7 +10923,7 @@ function ContractsPage(props) {
10501
10923
  ] }) }),
10502
10924
  /* @__PURE__ */ jsx("section", { className: "max-w-5xl mx-auto px-4 sm:px-6 lg:px-8 py-12", children: loading ? /* @__PURE__ */ jsx("div", { className: "flex justify-center py-20", children: /* @__PURE__ */ jsx("div", { className: "h-8 w-8 animate-spin rounded-full border-2 border-primary border-t-transparent" }) }) : error ? /* @__PURE__ */ jsx("div", { className: "text-center py-16", children: /* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground", children: error }) }) : contracts.length === 0 ? /* @__PURE__ */ jsx("div", { className: "text-center py-16", children: /* @__PURE__ */ jsx("p", { className: "text-base text-muted-foreground", children: "No contracts are available yet." }) }) : /* @__PURE__ */ jsx("ul", { className: "divide-y divide-border rounded-xl border border-border overflow-hidden bg-card", children: contracts.map((c) => {
10503
10925
  const ext = fileExt(c);
10504
- const size = formatBytes(c.fileSize);
10926
+ const size = formatBytes2(c.fileSize);
10505
10927
  return /* @__PURE__ */ jsxs(
10506
10928
  "li",
10507
10929
  {