@kite-copilot/chat-panel 0.2.39 → 0.2.42

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.
@@ -882,10 +882,62 @@ function DataRenderer({ type, data }) {
882
882
  }
883
883
 
884
884
  // src/ChatPanel.tsx
885
- import * as React4 from "react";
885
+ import * as React5 from "react";
886
886
  import { createClient } from "@supabase/supabase-js";
887
887
  import { ArrowLeft, ArrowUp, Command, CornerDownLeft, CheckCircle2 as CheckCircle23, SquarePen, Paperclip, X, FileSpreadsheet, Loader2 as Loader22, ChevronLeft, ChevronRight, Sparkles, Minus } from "lucide-react";
888
888
 
889
+ // src/hooks/useUserAuth.ts
890
+ import * as React4 from "react";
891
+ function useUserAuth({
892
+ productBackendUrl,
893
+ sessionId,
894
+ enabled = true
895
+ }) {
896
+ const [authState, setAuthState] = React4.useState({ status: "idle" });
897
+ const lastSessionIdRef = React4.useRef(null);
898
+ const fetchUser = React4.useCallback(async () => {
899
+ if (!productBackendUrl || !enabled) {
900
+ setAuthState({ status: "idle" });
901
+ return;
902
+ }
903
+ setAuthState({ status: "loading" });
904
+ try {
905
+ const response = await fetch(`${productBackendUrl}/users/me`, {
906
+ method: "GET",
907
+ credentials: "include",
908
+ // Include cookies for authentication
909
+ headers: {
910
+ "Accept": "application/json"
911
+ }
912
+ });
913
+ if (!response.ok) {
914
+ if (response.status === 401) {
915
+ throw new Error("Please log in to use the chat assistant.");
916
+ }
917
+ if (response.status === 403) {
918
+ throw new Error("You do not have permission to access this feature.");
919
+ }
920
+ throw new Error(`Authentication failed (${response.status})`);
921
+ }
922
+ const user = await response.json();
923
+ setAuthState({ status: "authenticated", user });
924
+ } catch (error) {
925
+ const message = error instanceof Error ? error.message : "Unable to verify your identity. Please try again.";
926
+ setAuthState({ status: "error", error: message });
927
+ }
928
+ }, [productBackendUrl, enabled]);
929
+ React4.useEffect(() => {
930
+ if (sessionId !== lastSessionIdRef.current) {
931
+ lastSessionIdRef.current = sessionId;
932
+ fetchUser();
933
+ }
934
+ }, [sessionId, fetchUser]);
935
+ const retry = React4.useCallback(() => {
936
+ fetchUser();
937
+ }, [fetchUser]);
938
+ return { authState, retry };
939
+ }
940
+
889
941
  // src/components/TypingIndicator.tsx
890
942
  import { jsx as jsx9, jsxs as jsxs5 } from "react/jsx-runtime";
891
943
  function TypingIndicator({ className = "" }) {
@@ -916,7 +968,7 @@ function TypingIndicator({ className = "" }) {
916
968
 
917
969
  // src/ChatPanel.tsx
918
970
  import { Fragment as Fragment2, jsx as jsx10, jsxs as jsxs6 } from "react/jsx-runtime";
919
- var CHAT_PANEL_VERSION = true ? "0.2.39" : "dev";
971
+ var CHAT_PANEL_VERSION = true ? "0.2.42" : "dev";
920
972
  var DEFAULT_AGENT_URL = "http://localhost:5002";
921
973
  var PANEL_WIDTH = 340;
922
974
  function unescapeJsonString(str) {
@@ -1334,6 +1386,32 @@ var guides = {
1334
1386
  }
1335
1387
  };
1336
1388
  var initialMessages = [];
1389
+ function AuthLoadingState() {
1390
+ return /* @__PURE__ */ jsxs6("div", { className: "flex flex-col items-center justify-center h-full p-6", children: [
1391
+ /* @__PURE__ */ jsx10(Loader22, { className: "h-8 w-8 animate-spin text-gray-400 mb-3" }),
1392
+ /* @__PURE__ */ jsx10("p", { className: "text-xs text-gray-500", children: "Verifying your identity..." })
1393
+ ] });
1394
+ }
1395
+ function AuthErrorState({
1396
+ error,
1397
+ onRetry
1398
+ }) {
1399
+ return /* @__PURE__ */ jsxs6("div", { className: "flex flex-col items-center justify-center h-full p-6 text-center", children: [
1400
+ /* @__PURE__ */ jsx10("div", { className: "w-12 h-12 rounded-full bg-red-100 flex items-center justify-center mb-4", children: /* @__PURE__ */ jsx10(X, { className: "h-6 w-6 text-red-600" }) }),
1401
+ /* @__PURE__ */ jsx10("h3", { className: "text-sm font-semibold text-gray-900 mb-2", children: "Unable to Start Chat" }),
1402
+ /* @__PURE__ */ jsx10("p", { className: "text-xs text-gray-500 mb-4 max-w-[240px]", children: error }),
1403
+ /* @__PURE__ */ jsx10(
1404
+ Button,
1405
+ {
1406
+ variant: "secondary",
1407
+ size: "sm",
1408
+ onClick: onRetry,
1409
+ className: "h-8 px-4 text-xs",
1410
+ children: "Try Again"
1411
+ }
1412
+ )
1413
+ ] });
1414
+ }
1337
1415
  function ChatPanel({
1338
1416
  isOpen = true,
1339
1417
  onClose,
@@ -1351,21 +1429,46 @@ function ChatPanel({
1351
1429
  userEmail,
1352
1430
  userOrganization,
1353
1431
  supabaseUrl,
1354
- supabaseAnonKey
1432
+ supabaseAnonKey,
1433
+ productBackendUrl
1355
1434
  } = {}) {
1356
- const [messages, setMessages] = React4.useState(initialMessages);
1357
- const [input, setInput] = React4.useState("");
1358
- const [sessionId, setSessionId] = React4.useState(() => crypto.randomUUID());
1359
- const [isEscalated, setIsEscalated] = React4.useState(false);
1360
- const escalationWsRef = React4.useRef(null);
1361
- const [agentIsTyping, setAgentIsTyping] = React4.useState(false);
1362
- const supabaseRef = React4.useRef(null);
1363
- const typingChannelRef = React4.useRef(null);
1364
- const typingTimeoutRef = React4.useRef(null);
1365
- React4.useEffect(() => {
1435
+ const [messages, setMessages] = React5.useState(initialMessages);
1436
+ const [input, setInput] = React5.useState("");
1437
+ const [sessionId, setSessionId] = React5.useState(() => crypto.randomUUID());
1438
+ const { authState, retry: retryAuth } = useUserAuth({
1439
+ productBackendUrl,
1440
+ sessionId,
1441
+ enabled: !!productBackendUrl
1442
+ // Only enable if URL is provided
1443
+ });
1444
+ const effectiveUser = React5.useMemo(() => {
1445
+ if (authState.status === "authenticated") {
1446
+ return {
1447
+ userId: authState.user.id,
1448
+ userName: authState.user.name,
1449
+ userEmail: authState.user.email,
1450
+ userRole: authState.user.role,
1451
+ isInternal: authState.user.isInternal
1452
+ };
1453
+ }
1454
+ return {
1455
+ userId: userId || "anonymous",
1456
+ userName: userName || "Anonymous User",
1457
+ userEmail: userEmail || "Not provided",
1458
+ userRole: void 0,
1459
+ isInternal: false
1460
+ };
1461
+ }, [authState, userId, userName, userEmail]);
1462
+ const [isEscalated, setIsEscalated] = React5.useState(false);
1463
+ const escalationWsRef = React5.useRef(null);
1464
+ const [agentIsTyping, setAgentIsTyping] = React5.useState(false);
1465
+ const supabaseRef = React5.useRef(null);
1466
+ const typingChannelRef = React5.useRef(null);
1467
+ const typingTimeoutRef = React5.useRef(null);
1468
+ React5.useEffect(() => {
1366
1469
  console.log(`[KiteChat] Chat Panel v${CHAT_PANEL_VERSION} loaded`);
1367
1470
  }, []);
1368
- const resetSession = React4.useCallback(() => {
1471
+ const resetSession = React5.useCallback(() => {
1369
1472
  console.log("[KiteChat] resetSession called", { isEscalated, hasSupabase: !!supabaseRef.current, sessionId });
1370
1473
  if (isEscalated && supabaseRef.current && sessionId) {
1371
1474
  console.log("[KiteChat] Updating customer_status to disconnected for session:", sessionId);
@@ -1395,12 +1498,12 @@ function ChatPanel({
1395
1498
  typingChannelRef.current = null;
1396
1499
  }
1397
1500
  }, [isEscalated, sessionId]);
1398
- React4.useEffect(() => {
1501
+ React5.useEffect(() => {
1399
1502
  if (supabaseUrl && supabaseAnonKey && !supabaseRef.current) {
1400
1503
  supabaseRef.current = createClient(supabaseUrl, supabaseAnonKey);
1401
1504
  }
1402
1505
  }, [supabaseUrl, supabaseAnonKey]);
1403
- React4.useEffect(() => {
1506
+ React5.useEffect(() => {
1404
1507
  if (!isEscalated || !sessionId || !supabaseRef.current) {
1405
1508
  return;
1406
1509
  }
@@ -1437,8 +1540,8 @@ function ChatPanel({
1437
1540
  }
1438
1541
  };
1439
1542
  }, [isEscalated, sessionId]);
1440
- const heartbeatIntervalRef = React4.useRef(null);
1441
- const updateCustomerStatus = React4.useCallback(async (status) => {
1543
+ const heartbeatIntervalRef = React5.useRef(null);
1544
+ const updateCustomerStatus = React5.useCallback(async (status) => {
1442
1545
  if (!supabaseRef.current || !sessionId) return;
1443
1546
  try {
1444
1547
  await supabaseRef.current.from("escalations").update({
@@ -1449,7 +1552,7 @@ function ChatPanel({
1449
1552
  console.error("[KiteChat] Failed to update customer status:", err);
1450
1553
  }
1451
1554
  }, [sessionId]);
1452
- React4.useEffect(() => {
1555
+ React5.useEffect(() => {
1453
1556
  if (!isEscalated || !sessionId || !supabaseRef.current) {
1454
1557
  return;
1455
1558
  }
@@ -1497,7 +1600,7 @@ function ChatPanel({
1497
1600
  }
1498
1601
  };
1499
1602
  }, [isEscalated, sessionId, updateCustomerStatus]);
1500
- const sendTypingIndicator = React4.useCallback((isTyping) => {
1603
+ const sendTypingIndicator = React5.useCallback((isTyping) => {
1501
1604
  if (!typingChannelRef.current) {
1502
1605
  console.log("[KiteChat] Cannot send typing - channel not ready");
1503
1606
  return;
@@ -1513,8 +1616,8 @@ function ChatPanel({
1513
1616
  payload: { sender: "user", isTyping }
1514
1617
  });
1515
1618
  }, [isEscalated]);
1516
- const userTypingTimeoutRef = React4.useRef(null);
1517
- const handleTypingStart = React4.useCallback(() => {
1619
+ const userTypingTimeoutRef = React5.useRef(null);
1620
+ const handleTypingStart = React5.useCallback(() => {
1518
1621
  if (!isEscalated || !supabaseRef.current) return;
1519
1622
  sendTypingIndicator(true);
1520
1623
  updateCustomerStatus("active");
@@ -1525,19 +1628,19 @@ function ChatPanel({
1525
1628
  sendTypingIndicator(false);
1526
1629
  }, 1500);
1527
1630
  }, [isEscalated, sendTypingIndicator, updateCustomerStatus]);
1528
- const streamIntervals = React4.useRef({});
1631
+ const streamIntervals = React5.useRef({});
1529
1632
  const isEmpty = messages.length === 0;
1530
- const [phase, setPhase] = React4.useState("idle");
1531
- const [progressSteps, setProgressSteps] = React4.useState([]);
1532
- const phaseTimers = React4.useRef([]);
1633
+ const [phase, setPhase] = React5.useState("idle");
1634
+ const [progressSteps, setProgressSteps] = React5.useState([]);
1635
+ const phaseTimers = React5.useRef([]);
1533
1636
  const lastRole = messages.length ? messages[messages.length - 1].role : void 0;
1534
- const [panelView, setPanelView] = React4.useState(
1637
+ const [panelView, setPanelView] = React5.useState(
1535
1638
  "landing"
1536
1639
  );
1537
- const [currentFolderId, setCurrentFolderId] = React4.useState(void 0);
1538
- const [startingQuestions, setStartingQuestions] = React4.useState(startingQuestionsProp || defaultStartingQuestions);
1539
- const [loadingQuestions, setLoadingQuestions] = React4.useState(false);
1540
- React4.useEffect(() => {
1640
+ const [currentFolderId, setCurrentFolderId] = React5.useState(void 0);
1641
+ const [startingQuestions, setStartingQuestions] = React5.useState(startingQuestionsProp || defaultStartingQuestions);
1642
+ const [loadingQuestions, setLoadingQuestions] = React5.useState(false);
1643
+ React5.useEffect(() => {
1541
1644
  if (startingQuestionsEndpoint && !startingQuestionsProp) {
1542
1645
  setLoadingQuestions(true);
1543
1646
  fetch(startingQuestionsEndpoint).then((res) => res.json()).then((data) => {
@@ -1549,16 +1652,16 @@ function ChatPanel({
1549
1652
  }).finally(() => setLoadingQuestions(false));
1550
1653
  }
1551
1654
  }, [startingQuestionsEndpoint, startingQuestionsProp]);
1552
- React4.useEffect(() => {
1655
+ React5.useEffect(() => {
1553
1656
  if (startingQuestionsProp) {
1554
1657
  setStartingQuestions(startingQuestionsProp);
1555
1658
  }
1556
1659
  }, [startingQuestionsProp]);
1557
- const [activeGuide, setActiveGuide] = React4.useState(void 0);
1558
- const activeGuideRef = React4.useRef(void 0);
1559
- const latestBulkSummaryNavigationRef = React4.useRef(null);
1560
- const [guideComplete, setGuideComplete] = React4.useState(false);
1561
- React4.useEffect(() => {
1660
+ const [activeGuide, setActiveGuide] = React5.useState(void 0);
1661
+ const activeGuideRef = React5.useRef(void 0);
1662
+ const latestBulkSummaryNavigationRef = React5.useRef(null);
1663
+ const [guideComplete, setGuideComplete] = React5.useState(false);
1664
+ React5.useEffect(() => {
1562
1665
  window.resetIntegrationNotification = () => {
1563
1666
  localStorage.removeItem("gmailNotificationSeen");
1564
1667
  console.log(
@@ -1592,7 +1695,7 @@ function ChatPanel({
1592
1695
  );
1593
1696
  };
1594
1697
  }, []);
1595
- React4.useEffect(() => {
1698
+ React5.useEffect(() => {
1596
1699
  if (activeGuide) {
1597
1700
  if (!activeGuideRef.current || activeGuideRef.current.id !== activeGuide.id || activeGuideRef.current.stepIndex !== activeGuide.stepIndex) {
1598
1701
  activeGuideRef.current = activeGuide;
@@ -1601,21 +1704,21 @@ function ChatPanel({
1601
1704
  activeGuideRef.current = void 0;
1602
1705
  }
1603
1706
  }, [activeGuide]);
1604
- const [pendingNavigation, setPendingNavigation] = React4.useState(null);
1605
- const [pendingAction, setPendingAction] = React4.useState(null);
1606
- const [actionFormData, setActionFormData] = React4.useState({});
1607
- const messagesEndRef = React4.useRef(null);
1608
- const messagesContainerRef = React4.useRef(null);
1609
- const currentStepRef = React4.useRef(null);
1707
+ const [pendingNavigation, setPendingNavigation] = React5.useState(null);
1708
+ const [pendingAction, setPendingAction] = React5.useState(null);
1709
+ const [actionFormData, setActionFormData] = React5.useState({});
1710
+ const messagesEndRef = React5.useRef(null);
1711
+ const messagesContainerRef = React5.useRef(null);
1712
+ const currentStepRef = React5.useRef(null);
1610
1713
  const { cursorState, moveTo, hide } = useGuideCursor();
1611
- const [pendingFile, setPendingFile] = React4.useState(null);
1612
- const [pendingBulkSession, setPendingBulkSession] = React4.useState(null);
1613
- const pendingBulkSessionRef = React4.useRef(null);
1614
- const fileInputRef = React4.useRef(null);
1615
- const [searchExpanded, setSearchExpanded] = React4.useState(false);
1616
- const [searchInput, setSearchInput] = React4.useState("");
1617
- const searchInputRef = React4.useRef(null);
1618
- React4.useEffect(() => {
1714
+ const [pendingFile, setPendingFile] = React5.useState(null);
1715
+ const [pendingBulkSession, setPendingBulkSession] = React5.useState(null);
1716
+ const pendingBulkSessionRef = React5.useRef(null);
1717
+ const fileInputRef = React5.useRef(null);
1718
+ const [searchExpanded, setSearchExpanded] = React5.useState(false);
1719
+ const [searchInput, setSearchInput] = React5.useState("");
1720
+ const searchInputRef = React5.useRef(null);
1721
+ React5.useEffect(() => {
1619
1722
  if (!activeGuide || activeGuide.id !== "add-api-key" || activeGuide.stepIndex !== 2) {
1620
1723
  return;
1621
1724
  }
@@ -1641,7 +1744,7 @@ function ChatPanel({
1641
1744
  const interval = setInterval(checkForDialogOpen, 300);
1642
1745
  return () => clearInterval(interval);
1643
1746
  }, [activeGuide, hide]);
1644
- React4.useEffect(() => {
1747
+ React5.useEffect(() => {
1645
1748
  return () => {
1646
1749
  Object.values(streamIntervals.current).forEach(
1647
1750
  (id) => window.clearInterval(id)
@@ -1651,7 +1754,7 @@ function ChatPanel({
1651
1754
  phaseTimers.current = [];
1652
1755
  };
1653
1756
  }, []);
1654
- React4.useEffect(() => {
1757
+ React5.useEffect(() => {
1655
1758
  if (activeGuide && messages.length > 0) {
1656
1759
  const lastMessage = messages[messages.length - 1];
1657
1760
  if (lastMessage.kind === "guideStep" || lastMessage.kind === "guideComplete") {
@@ -1668,7 +1771,7 @@ function ChatPanel({
1668
1771
  messagesEndRef.current?.scrollIntoView({ behavior: "smooth" });
1669
1772
  }
1670
1773
  }, [messages, phase, activeGuide]);
1671
- const latestBulkSummaryNavigation = React4.useMemo(() => {
1774
+ const latestBulkSummaryNavigation = React5.useMemo(() => {
1672
1775
  for (let i = messages.length - 1; i >= 0; i--) {
1673
1776
  const msg = messages[i];
1674
1777
  if (msg.kind === "bulkSummary" && msg.bulkSummary?.navigationPage && msg.bulkSummary.successes > 0) {
@@ -1677,13 +1780,13 @@ function ChatPanel({
1677
1780
  }
1678
1781
  return null;
1679
1782
  }, [messages]);
1680
- React4.useEffect(() => {
1783
+ React5.useEffect(() => {
1681
1784
  latestBulkSummaryNavigationRef.current = latestBulkSummaryNavigation;
1682
1785
  }, [latestBulkSummaryNavigation]);
1683
- React4.useEffect(() => {
1786
+ React5.useEffect(() => {
1684
1787
  pendingBulkSessionRef.current = pendingBulkSession;
1685
1788
  }, [pendingBulkSession]);
1686
- React4.useEffect(() => {
1789
+ React5.useEffect(() => {
1687
1790
  const handleKeyDown = (e) => {
1688
1791
  if ((e.metaKey || e.ctrlKey) && e.key === "Enter") {
1689
1792
  const currentBulkSession = pendingBulkSessionRef.current;
@@ -1746,7 +1849,7 @@ function ChatPanel({
1746
1849
  guideComplete,
1747
1850
  onNavigate
1748
1851
  ]);
1749
- const connectToEscalationWs = React4.useCallback((currentSessionId) => {
1852
+ const connectToEscalationWs = React5.useCallback((currentSessionId) => {
1750
1853
  if (!agentUrl) return;
1751
1854
  if (escalationWsRef.current) {
1752
1855
  escalationWsRef.current.close();
@@ -1789,7 +1892,7 @@ function ChatPanel({
1789
1892
  };
1790
1893
  escalationWsRef.current = ws;
1791
1894
  }, [agentUrl]);
1792
- const sendEscalatedMessage = React4.useCallback(async (content) => {
1895
+ const sendEscalatedMessage = React5.useCallback(async (content) => {
1793
1896
  if (!escalationWsRef.current || escalationWsRef.current.readyState !== WebSocket.OPEN) {
1794
1897
  console.error("[KiteChat] Escalation WebSocket not connected");
1795
1898
  return false;
@@ -1806,14 +1909,14 @@ function ChatPanel({
1806
1909
  return false;
1807
1910
  }
1808
1911
  }, [updateCustomerStatus]);
1809
- React4.useEffect(() => {
1912
+ React5.useEffect(() => {
1810
1913
  return () => {
1811
1914
  if (escalationWsRef.current) {
1812
1915
  escalationWsRef.current.close();
1813
1916
  }
1814
1917
  };
1815
1918
  }, []);
1816
- React4.useEffect(() => {
1919
+ React5.useEffect(() => {
1817
1920
  if (isEscalated && sessionId) {
1818
1921
  connectToEscalationWs(sessionId);
1819
1922
  }
@@ -2088,9 +2191,9 @@ function ChatPanel({
2088
2191
  session_id: sessionId,
2089
2192
  message: userText,
2090
2193
  current_page: currentPage || "dashboard",
2091
- user_id: userId,
2092
- user_name: userName,
2093
- user_email: userEmail,
2194
+ user_id: effectiveUser.userId,
2195
+ user_name: effectiveUser.userName,
2196
+ user_email: effectiveUser.userEmail,
2094
2197
  user_organization: userOrganization,
2095
2198
  org_id: orgId
2096
2199
  }),
@@ -3033,6 +3136,64 @@ ${userText}`
3033
3136
  ] })
3034
3137
  ] }) }) });
3035
3138
  }
3139
+ if (productBackendUrl) {
3140
+ if (authState.status === "loading") {
3141
+ return /* @__PURE__ */ jsxs6(
3142
+ "section",
3143
+ {
3144
+ className: `fixed top-0 right-0 z-40 flex flex-col bg-white border-l border-gray-200 h-full overflow-hidden transition-transform duration-300 ${isOpen ? "translate-x-0" : "translate-x-full"}`,
3145
+ style: { width: `${PANEL_WIDTH}px` },
3146
+ children: [
3147
+ /* @__PURE__ */ jsxs6("div", { className: "flex items-center justify-between px-4 py-3 border-b border-gray-100 bg-gradient-to-r from-gray-50 to-white shrink-0", children: [
3148
+ /* @__PURE__ */ jsxs6("div", { className: "flex items-center gap-2.5", children: [
3149
+ /* @__PURE__ */ jsx10(Sparkles, { className: "h-3.5 w-3.5 text-black", fill: "currentColor" }),
3150
+ /* @__PURE__ */ jsx10("h3", { className: "text-sm font-semibold text-gray-800", children: "Copilot" })
3151
+ ] }),
3152
+ /* @__PURE__ */ jsx10(
3153
+ Button,
3154
+ {
3155
+ variant: "ghost",
3156
+ size: "sm",
3157
+ className: "h-7 w-7 p-0 text-gray-400 hover:text-gray-600 hover:bg-gray-100 rounded-full",
3158
+ onClick: () => onClose?.(),
3159
+ children: /* @__PURE__ */ jsx10(Minus, { className: "h-3.5 w-3.5" })
3160
+ }
3161
+ )
3162
+ ] }),
3163
+ /* @__PURE__ */ jsx10(AuthLoadingState, {})
3164
+ ]
3165
+ }
3166
+ );
3167
+ }
3168
+ if (authState.status === "error") {
3169
+ return /* @__PURE__ */ jsxs6(
3170
+ "section",
3171
+ {
3172
+ className: `fixed top-0 right-0 z-40 flex flex-col bg-white border-l border-gray-200 h-full overflow-hidden transition-transform duration-300 ${isOpen ? "translate-x-0" : "translate-x-full"}`,
3173
+ style: { width: `${PANEL_WIDTH}px` },
3174
+ children: [
3175
+ /* @__PURE__ */ jsxs6("div", { className: "flex items-center justify-between px-4 py-3 border-b border-gray-100 bg-gradient-to-r from-gray-50 to-white shrink-0", children: [
3176
+ /* @__PURE__ */ jsxs6("div", { className: "flex items-center gap-2.5", children: [
3177
+ /* @__PURE__ */ jsx10(Sparkles, { className: "h-3.5 w-3.5 text-black", fill: "currentColor" }),
3178
+ /* @__PURE__ */ jsx10("h3", { className: "text-sm font-semibold text-gray-800", children: "Copilot" })
3179
+ ] }),
3180
+ /* @__PURE__ */ jsx10(
3181
+ Button,
3182
+ {
3183
+ variant: "ghost",
3184
+ size: "sm",
3185
+ className: "h-7 w-7 p-0 text-gray-400 hover:text-gray-600 hover:bg-gray-100 rounded-full",
3186
+ onClick: () => onClose?.(),
3187
+ children: /* @__PURE__ */ jsx10(Minus, { className: "h-3.5 w-3.5" })
3188
+ }
3189
+ )
3190
+ ] }),
3191
+ /* @__PURE__ */ jsx10(AuthErrorState, { error: authState.error, onRetry: retryAuth })
3192
+ ]
3193
+ }
3194
+ );
3195
+ }
3196
+ }
3036
3197
  return /* @__PURE__ */ jsxs6(
3037
3198
  "section",
3038
3199
  {
@@ -4150,7 +4311,7 @@ ${userText}`
4150
4311
  message.id
4151
4312
  );
4152
4313
  }
4153
- return /* @__PURE__ */ jsx10(React4.Fragment, { children: /* @__PURE__ */ jsxs6(
4314
+ return /* @__PURE__ */ jsx10(React5.Fragment, { children: /* @__PURE__ */ jsxs6(
4154
4315
  "div",
4155
4316
  {
4156
4317
  ref: isCurrentGuideStep ? currentStepRef : null,
@@ -4404,9 +4565,10 @@ function ChatPanelWithToggle({
4404
4565
  userEmail,
4405
4566
  userOrganization,
4406
4567
  supabaseUrl,
4407
- supabaseAnonKey
4568
+ supabaseAnonKey,
4569
+ productBackendUrl
4408
4570
  }) {
4409
- const [internalIsOpen, setInternalIsOpen] = React4.useState(defaultOpen);
4571
+ const [internalIsOpen, setInternalIsOpen] = React5.useState(defaultOpen);
4410
4572
  const isOpen = controlledIsOpen !== void 0 ? controlledIsOpen : internalIsOpen;
4411
4573
  const setIsOpen = (open) => {
4412
4574
  if (controlledIsOpen === void 0) {
@@ -4414,7 +4576,7 @@ function ChatPanelWithToggle({
4414
4576
  }
4415
4577
  onOpenChange?.(open);
4416
4578
  };
4417
- React4.useEffect(() => {
4579
+ React5.useEffect(() => {
4418
4580
  const originalPadding = document.body.style.paddingRight;
4419
4581
  const originalTransition = document.body.style.transition;
4420
4582
  document.body.style.transition = "padding-right 0.3s ease";
@@ -4442,7 +4604,8 @@ function ChatPanelWithToggle({
4442
4604
  userEmail,
4443
4605
  userOrganization,
4444
4606
  supabaseUrl,
4445
- supabaseAnonKey
4607
+ supabaseAnonKey,
4608
+ productBackendUrl
4446
4609
  }
4447
4610
  );
4448
4611
  }
@@ -4460,7 +4623,7 @@ function HelpButton({ onClick, className = "" }) {
4460
4623
  }
4461
4624
 
4462
4625
  // src/createKiteChat.tsx
4463
- import React5 from "react";
4626
+ import React6 from "react";
4464
4627
  import { createRoot } from "react-dom/client";
4465
4628
  import { jsx as jsx11 } from "react/jsx-runtime";
4466
4629
  function KiteChatWrapper({
@@ -4468,14 +4631,14 @@ function KiteChatWrapper({
4468
4631
  onConfigUpdate,
4469
4632
  onStateUpdate
4470
4633
  }) {
4471
- const [config, setConfig] = React5.useState(initialConfig);
4472
- const [currentPage, setCurrentPage] = React5.useState(initialConfig.currentPage || "dashboard");
4473
- const [isOpen, setIsOpen] = React5.useState(false);
4474
- const isOpenRef = React5.useRef(false);
4475
- React5.useEffect(() => {
4634
+ const [config, setConfig] = React6.useState(initialConfig);
4635
+ const [currentPage, setCurrentPage] = React6.useState(initialConfig.currentPage || "dashboard");
4636
+ const [isOpen, setIsOpen] = React6.useState(false);
4637
+ const isOpenRef = React6.useRef(false);
4638
+ React6.useEffect(() => {
4476
4639
  isOpenRef.current = isOpen;
4477
4640
  }, [isOpen]);
4478
- React5.useEffect(() => {
4641
+ React6.useEffect(() => {
4479
4642
  onConfigUpdate((newConfig) => {
4480
4643
  if (newConfig.currentPage !== void 0) {
4481
4644
  setCurrentPage(newConfig.currentPage);
@@ -4487,7 +4650,7 @@ function KiteChatWrapper({
4487
4650
  getIsOpen: () => isOpenRef.current
4488
4651
  });
4489
4652
  }, [onConfigUpdate, onStateUpdate]);
4490
- React5.useEffect(() => {
4653
+ React6.useEffect(() => {
4491
4654
  const container = document.getElementById("kite-chat-root");
4492
4655
  if (!container) return;
4493
4656
  if (config.theme === "dark") {
@@ -4516,7 +4679,8 @@ function KiteChatWrapper({
4516
4679
  userEmail: config.userEmail,
4517
4680
  userOrganization: config.userOrganization,
4518
4681
  supabaseUrl: config.supabaseUrl,
4519
- supabaseAnonKey: config.supabaseAnonKey
4682
+ supabaseAnonKey: config.supabaseAnonKey,
4683
+ productBackendUrl: config.productBackendUrl
4520
4684
  }
4521
4685
  );
4522
4686
  }
@@ -112,8 +112,10 @@ interface ChatPanelProps {
112
112
  supabaseUrl?: string;
113
113
  /** Supabase anonymous key for realtime features */
114
114
  supabaseAnonKey?: string;
115
+ /** Product backend URL for user authentication (e.g., https://dev.api.rocketalumnisolutions.com) */
116
+ productBackendUrl?: string;
115
117
  }
116
- declare function ChatPanel({ isOpen, onClose, onOpen, onBack, onNavigate, onActionComplete, currentPage, agentUrl, startingQuestions: startingQuestionsProp, startingQuestionsEndpoint, userId, orgId, userName, userEmail, userOrganization, supabaseUrl, supabaseAnonKey, }?: ChatPanelProps): react_jsx_runtime.JSX.Element;
118
+ declare function ChatPanel({ isOpen, onClose, onOpen, onBack, onNavigate, onActionComplete, currentPage, agentUrl, startingQuestions: startingQuestionsProp, startingQuestionsEndpoint, userId, orgId, userName, userEmail, userOrganization, supabaseUrl, supabaseAnonKey, productBackendUrl, }?: ChatPanelProps): react_jsx_runtime.JSX.Element;
117
119
  /**
118
120
  * PanelToggle - An arrow button on the right edge that toggles the side panel
119
121
  * Shows left arrow when closed (click to open), right arrow when open (click to close)
@@ -172,8 +174,10 @@ interface ChatPanelWithToggleProps {
172
174
  supabaseUrl?: string;
173
175
  /** Supabase anonymous key for realtime features */
174
176
  supabaseAnonKey?: string;
177
+ /** Product backend URL for user authentication (e.g., https://dev.api.rocketalumnisolutions.com) */
178
+ productBackendUrl?: string;
175
179
  }
176
- declare function ChatPanelWithToggle({ onNavigate, onActionComplete, currentPage, agentUrl, startingQuestions, startingQuestionsEndpoint, defaultOpen, isOpen: controlledIsOpen, onOpenChange, userId, orgId, userName, userEmail, userOrganization, supabaseUrl, supabaseAnonKey, }: ChatPanelWithToggleProps): react_jsx_runtime.JSX.Element;
180
+ declare function ChatPanelWithToggle({ onNavigate, onActionComplete, currentPage, agentUrl, startingQuestions, startingQuestionsEndpoint, defaultOpen, isOpen: controlledIsOpen, onOpenChange, userId, orgId, userName, userEmail, userOrganization, supabaseUrl, supabaseAnonKey, productBackendUrl, }: ChatPanelWithToggleProps): react_jsx_runtime.JSX.Element;
177
181
  /**
178
182
  * @deprecated Use ChatPanelWithToggle instead for the new side panel UX
179
183
  */
@@ -244,6 +248,8 @@ interface KiteChatConfig {
244
248
  supabaseUrl?: string;
245
249
  /** Supabase anonymous key for realtime features */
246
250
  supabaseAnonKey?: string;
251
+ /** Product backend URL for user authentication (e.g., https://dev.api.rocketalumnisolutions.com) */
252
+ productBackendUrl?: string;
247
253
  }
248
254
  /**
249
255
  * Instance returned by createKiteChat with lifecycle control methods.
@@ -112,8 +112,10 @@ interface ChatPanelProps {
112
112
  supabaseUrl?: string;
113
113
  /** Supabase anonymous key for realtime features */
114
114
  supabaseAnonKey?: string;
115
+ /** Product backend URL for user authentication (e.g., https://dev.api.rocketalumnisolutions.com) */
116
+ productBackendUrl?: string;
115
117
  }
116
- declare function ChatPanel({ isOpen, onClose, onOpen, onBack, onNavigate, onActionComplete, currentPage, agentUrl, startingQuestions: startingQuestionsProp, startingQuestionsEndpoint, userId, orgId, userName, userEmail, userOrganization, supabaseUrl, supabaseAnonKey, }?: ChatPanelProps): react_jsx_runtime.JSX.Element;
118
+ declare function ChatPanel({ isOpen, onClose, onOpen, onBack, onNavigate, onActionComplete, currentPage, agentUrl, startingQuestions: startingQuestionsProp, startingQuestionsEndpoint, userId, orgId, userName, userEmail, userOrganization, supabaseUrl, supabaseAnonKey, productBackendUrl, }?: ChatPanelProps): react_jsx_runtime.JSX.Element;
117
119
  /**
118
120
  * PanelToggle - An arrow button on the right edge that toggles the side panel
119
121
  * Shows left arrow when closed (click to open), right arrow when open (click to close)
@@ -172,8 +174,10 @@ interface ChatPanelWithToggleProps {
172
174
  supabaseUrl?: string;
173
175
  /** Supabase anonymous key for realtime features */
174
176
  supabaseAnonKey?: string;
177
+ /** Product backend URL for user authentication (e.g., https://dev.api.rocketalumnisolutions.com) */
178
+ productBackendUrl?: string;
175
179
  }
176
- declare function ChatPanelWithToggle({ onNavigate, onActionComplete, currentPage, agentUrl, startingQuestions, startingQuestionsEndpoint, defaultOpen, isOpen: controlledIsOpen, onOpenChange, userId, orgId, userName, userEmail, userOrganization, supabaseUrl, supabaseAnonKey, }: ChatPanelWithToggleProps): react_jsx_runtime.JSX.Element;
180
+ declare function ChatPanelWithToggle({ onNavigate, onActionComplete, currentPage, agentUrl, startingQuestions, startingQuestionsEndpoint, defaultOpen, isOpen: controlledIsOpen, onOpenChange, userId, orgId, userName, userEmail, userOrganization, supabaseUrl, supabaseAnonKey, productBackendUrl, }: ChatPanelWithToggleProps): react_jsx_runtime.JSX.Element;
177
181
  /**
178
182
  * @deprecated Use ChatPanelWithToggle instead for the new side panel UX
179
183
  */
@@ -244,6 +248,8 @@ interface KiteChatConfig {
244
248
  supabaseUrl?: string;
245
249
  /** Supabase anonymous key for realtime features */
246
250
  supabaseAnonKey?: string;
251
+ /** Product backend URL for user authentication (e.g., https://dev.api.rocketalumnisolutions.com) */
252
+ productBackendUrl?: string;
247
253
  }
248
254
  /**
249
255
  * Instance returned by createKiteChat with lifecycle control methods.