@usepanacea/react 0.1.2 → 0.1.3
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.cjs +161 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +39 -1
- package/dist/index.d.ts +39 -1
- package/dist/index.js +161 -2
- package/dist/index.js.map +1 -1
- package/dist/styles.css +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -82,6 +82,42 @@ function PanaceaProvider({
|
|
|
82
82
|
const [liveEscalationId, setLiveEscalationId] = react.useState(null);
|
|
83
83
|
const [liveMessages, setLiveMessages] = react.useState([]);
|
|
84
84
|
const [isOpen, setIsOpen] = react.useState(false);
|
|
85
|
+
react.useEffect(() => {
|
|
86
|
+
if (!customerToken) return;
|
|
87
|
+
let cancelled = false;
|
|
88
|
+
async function tryResume() {
|
|
89
|
+
try {
|
|
90
|
+
const token = await tokenMgr.getToken();
|
|
91
|
+
const url = new URL(`${apiBase}/api/v1/sessions/resume`);
|
|
92
|
+
url.searchParams.set("customerToken", customerToken);
|
|
93
|
+
const res = await fetch(url.toString(), {
|
|
94
|
+
headers: { Authorization: `Bearer ${token}` }
|
|
95
|
+
});
|
|
96
|
+
if (!res.ok || cancelled) return;
|
|
97
|
+
const data = await res.json();
|
|
98
|
+
const resumedId = data?.session?.sessionId ?? null;
|
|
99
|
+
if (!resumedId || cancelled) return;
|
|
100
|
+
sessionId.current = resumedId;
|
|
101
|
+
const turnsRes = await fetch(`${apiBase}/api/v1/sessions/${resumedId}/turns`, {
|
|
102
|
+
headers: { Authorization: `Bearer ${token}` }
|
|
103
|
+
});
|
|
104
|
+
if (!turnsRes.ok || cancelled) return;
|
|
105
|
+
const turnsData = await turnsRes.json();
|
|
106
|
+
const rawTurns = turnsData?.data?.turns ?? turnsData?.turns ?? [];
|
|
107
|
+
if (cancelled) return;
|
|
108
|
+
const hydrated = rawTurns.flatMap((t) => [
|
|
109
|
+
{ role: "user", content: t.query },
|
|
110
|
+
{ role: "assistant", content: t.response }
|
|
111
|
+
]);
|
|
112
|
+
if (hydrated.length > 0) setTurns(hydrated);
|
|
113
|
+
} catch {
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
void tryResume();
|
|
117
|
+
return () => {
|
|
118
|
+
cancelled = true;
|
|
119
|
+
};
|
|
120
|
+
}, [customerToken, apiBase]);
|
|
85
121
|
const value = react.useMemo(
|
|
86
122
|
() => ({
|
|
87
123
|
config,
|
|
@@ -357,6 +393,55 @@ function useWidget() {
|
|
|
357
393
|
const toggle = react.useCallback(() => setIsOpen((v) => !v), [setIsOpen]);
|
|
358
394
|
return { isOpen, open, close, toggle };
|
|
359
395
|
}
|
|
396
|
+
function useSessionHistory() {
|
|
397
|
+
const { apiBase, getToken, config, setTurns, sessionId: activeSessionIdRef } = usePanaceaContext();
|
|
398
|
+
const [sessions, setSessions] = react.useState([]);
|
|
399
|
+
const [loading, setLoading] = react.useState(false);
|
|
400
|
+
const fetchSessions = react.useCallback(async () => {
|
|
401
|
+
if (!config.customerToken) return;
|
|
402
|
+
setLoading(true);
|
|
403
|
+
try {
|
|
404
|
+
const token = await getToken();
|
|
405
|
+
const url = new URL(`${apiBase}/api/v1/sessions`);
|
|
406
|
+
url.searchParams.set("customerToken", config.customerToken);
|
|
407
|
+
const res = await fetch(url.toString(), {
|
|
408
|
+
headers: { Authorization: `Bearer ${token}` }
|
|
409
|
+
});
|
|
410
|
+
if (!res.ok) return;
|
|
411
|
+
const data = await res.json();
|
|
412
|
+
const list = Array.isArray(data) ? data : data?.data ?? data?.sessions ?? [];
|
|
413
|
+
setSessions(list);
|
|
414
|
+
} catch {
|
|
415
|
+
} finally {
|
|
416
|
+
setLoading(false);
|
|
417
|
+
}
|
|
418
|
+
}, [apiBase, getToken, config.customerToken]);
|
|
419
|
+
react.useEffect(() => {
|
|
420
|
+
void fetchSessions();
|
|
421
|
+
}, [fetchSessions]);
|
|
422
|
+
const loadSession = react.useCallback(
|
|
423
|
+
async (sessionId) => {
|
|
424
|
+
try {
|
|
425
|
+
const token = await getToken();
|
|
426
|
+
const res = await fetch(`${apiBase}/api/v1/sessions/${sessionId}/turns`, {
|
|
427
|
+
headers: { Authorization: `Bearer ${token}` }
|
|
428
|
+
});
|
|
429
|
+
if (!res.ok) return;
|
|
430
|
+
const data = await res.json();
|
|
431
|
+
const raw = data?.data?.turns ?? data?.turns ?? [];
|
|
432
|
+
const turns = raw.flatMap((t) => [
|
|
433
|
+
{ role: "user", content: t.query },
|
|
434
|
+
{ role: "assistant", content: t.response }
|
|
435
|
+
]);
|
|
436
|
+
activeSessionIdRef.current = sessionId;
|
|
437
|
+
setTurns(turns);
|
|
438
|
+
} catch {
|
|
439
|
+
}
|
|
440
|
+
},
|
|
441
|
+
[apiBase, getToken, setTurns, activeSessionIdRef]
|
|
442
|
+
);
|
|
443
|
+
return { sessions, loading, loadSession, refresh: fetchSessions };
|
|
444
|
+
}
|
|
360
445
|
function cn(...inputs) {
|
|
361
446
|
return tailwindMerge.twMerge(clsx.clsx(inputs));
|
|
362
447
|
}
|
|
@@ -538,14 +623,90 @@ function PanaceaChat({
|
|
|
538
623
|
)
|
|
539
624
|
] });
|
|
540
625
|
}
|
|
626
|
+
function formatDate(iso) {
|
|
627
|
+
try {
|
|
628
|
+
return new Intl.DateTimeFormat(void 0, {
|
|
629
|
+
month: "short",
|
|
630
|
+
day: "numeric",
|
|
631
|
+
hour: "2-digit",
|
|
632
|
+
minute: "2-digit"
|
|
633
|
+
}).format(new Date(iso));
|
|
634
|
+
} catch {
|
|
635
|
+
return iso;
|
|
636
|
+
}
|
|
637
|
+
}
|
|
638
|
+
function PanaceaHistory({ onSessionLoaded, className }) {
|
|
639
|
+
const { config } = usePanaceaContext();
|
|
640
|
+
const { sessions, loading, loadSession } = useSessionHistory();
|
|
641
|
+
const [active, setActive] = react.useState(null);
|
|
642
|
+
const [loadingId, setLoadingId] = react.useState(null);
|
|
643
|
+
if (!config.customerToken) {
|
|
644
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn("flex flex-col items-center justify-center gap-2 py-8 text-center text-sm text-muted-foreground", className), children: /* @__PURE__ */ jsxRuntime.jsx("span", { children: "Sign in to see your conversation history." }) });
|
|
645
|
+
}
|
|
646
|
+
if (loading) {
|
|
647
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn("flex flex-col gap-2 p-3", className), children: [1, 2, 3].map((i) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
648
|
+
"div",
|
|
649
|
+
{
|
|
650
|
+
className: "h-14 animate-pulse rounded-lg bg-muted"
|
|
651
|
+
},
|
|
652
|
+
i
|
|
653
|
+
)) });
|
|
654
|
+
}
|
|
655
|
+
if (sessions.length === 0) {
|
|
656
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn("flex flex-col items-center justify-center gap-2 py-8 text-center text-sm text-muted-foreground", className), children: /* @__PURE__ */ jsxRuntime.jsx("span", { children: "No previous conversations found." }) });
|
|
657
|
+
}
|
|
658
|
+
async function handleLoad(session) {
|
|
659
|
+
setLoadingId(session.sessionId);
|
|
660
|
+
await loadSession(session.sessionId);
|
|
661
|
+
setActive(session.sessionId);
|
|
662
|
+
setLoadingId(null);
|
|
663
|
+
onSessionLoaded?.(session.sessionId);
|
|
664
|
+
}
|
|
665
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn("flex flex-col gap-1 overflow-y-auto p-2", className), children: sessions.map((session) => {
|
|
666
|
+
const isActive = active === session.sessionId;
|
|
667
|
+
const isLoading = loadingId === session.sessionId;
|
|
668
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
669
|
+
"button",
|
|
670
|
+
{
|
|
671
|
+
onClick: () => void handleLoad(session),
|
|
672
|
+
disabled: isLoading,
|
|
673
|
+
className: cn(
|
|
674
|
+
"flex w-full flex-col gap-0.5 rounded-lg px-3 py-2.5 text-left text-sm transition-colors hover:bg-accent disabled:cursor-wait",
|
|
675
|
+
isActive && "bg-accent"
|
|
676
|
+
),
|
|
677
|
+
children: [
|
|
678
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate font-medium leading-snug text-foreground", children: session.preview ?? "Conversation" }),
|
|
679
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 text-xs text-muted-foreground", children: [
|
|
680
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { children: formatDate(session.createdAt) }),
|
|
681
|
+
session.turnCount !== void 0 && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
682
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { "aria-hidden": true, children: "\xB7" }),
|
|
683
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
|
|
684
|
+
session.turnCount,
|
|
685
|
+
" ",
|
|
686
|
+
session.turnCount === 1 ? "message" : "messages"
|
|
687
|
+
] })
|
|
688
|
+
] }),
|
|
689
|
+
isLoading && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
690
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { "aria-hidden": true, children: "\xB7" }),
|
|
691
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { children: "Loading\u2026" })
|
|
692
|
+
] })
|
|
693
|
+
] })
|
|
694
|
+
]
|
|
695
|
+
},
|
|
696
|
+
session.sessionId
|
|
697
|
+
);
|
|
698
|
+
}) });
|
|
699
|
+
}
|
|
541
700
|
|
|
542
701
|
exports.PanaceaChat = PanaceaChat;
|
|
543
702
|
exports.PanaceaFAB = PanaceaFAB;
|
|
703
|
+
exports.PanaceaHistory = PanaceaHistory;
|
|
544
704
|
exports.PanaceaInput = PanaceaInput;
|
|
545
705
|
exports.PanaceaMessages = PanaceaMessages;
|
|
546
706
|
exports.PanaceaProvider = PanaceaProvider;
|
|
547
707
|
exports.useChat = useChat;
|
|
548
708
|
exports.useLiveSession = useLiveSession;
|
|
709
|
+
exports.useSessionHistory = useSessionHistory;
|
|
549
710
|
exports.useWidget = useWidget;
|
|
550
711
|
//# sourceMappingURL=index.cjs.map
|
|
551
712
|
//# sourceMappingURL=index.cjs.map
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/token.ts","../src/provider.tsx","../src/hooks/useChat.ts","../src/hooks/useLiveSession.ts","../src/hooks/useWidget.ts","../src/lib/utils.ts","../src/components/index.tsx"],"names":["createContext","useContext","useMemo","useState","useRef","jsx","useCallback","react","useEffect","twMerge","clsx","cva","jsxs","Fragment"],"mappings":"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","file":"index.cjs","sourcesContent":["import type { PanaceaConfig } from \"./types\";\n\ninterface TokenState {\n token: string;\n /** unix ms */\n expiresAt: number;\n}\n\n/**\n * Manages the short-lived widget JWT (15 min TTL).\n * Auto-refreshes 60s before expiry. Concurrent callers share one refresh promise.\n */\nexport class TokenManager {\n private state: TokenState | null = null;\n private refreshPromise: Promise<string> | null = null;\n\n constructor(\n private readonly config: PanaceaConfig,\n private readonly apiBase: string,\n ) {}\n\n async getToken(): Promise<string> {\n if (!this.state || Date.now() >= this.state.expiresAt - 60_000) {\n if (!this.refreshPromise) {\n this.refreshPromise = this.refresh().finally(() => {\n this.refreshPromise = null;\n });\n }\n return this.refreshPromise;\n }\n return this.state.token;\n }\n\n private async refresh(): Promise<string> {\n const res = await fetch(`${this.apiBase}/api/v1/auth/widget-token`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ tenantId: this.config.tenantId }),\n });\n\n if (!res.ok) {\n throw new Error(`Panacea: token refresh failed (${res.status})`);\n }\n\n const data = (await res.json()) as { token: string; expiresAt: string };\n this.state = {\n token: data.token,\n expiresAt: new Date(data.expiresAt).getTime(),\n };\n return this.state.token;\n }\n}\n","\"use client\";\n\nimport React, { createContext, useContext, useMemo, useRef, useState } from \"react\";\nimport type { LiveMessage, PanaceaConfig, PanaceaContextValue, Turn } from \"./types\";\nimport { TokenManager } from \"./token\";\n\n// ---------------------------------------------------------------------------\n// Context\n// ---------------------------------------------------------------------------\n\nconst PanaceaContext = createContext<PanaceaContextValue | null>(null);\n\nexport function usePanaceaContext(): PanaceaContextValue {\n const ctx = useContext(PanaceaContext);\n if (!ctx) {\n throw new Error(\n \"usePanaceaContext must be used inside <PanaceaProvider>. \" +\n 'Wrap your component tree with <PanaceaProvider tenantId=\"...\">.',\n );\n }\n return ctx;\n}\n\n// ---------------------------------------------------------------------------\n// Provider\n// ---------------------------------------------------------------------------\n\ninterface PanaceaProviderProps {\n children: React.ReactNode;\n tenantId: string;\n apiBase?: string;\n customerToken?: string;\n escalationKeywords?: string[];\n persona?: PanaceaConfig[\"persona\"];\n}\n\nexport function PanaceaProvider({\n children,\n tenantId,\n apiBase: apiBaseProp,\n customerToken,\n escalationKeywords,\n persona,\n}: PanaceaProviderProps) {\n const apiBase = apiBaseProp ?? (typeof window !== \"undefined\" ? window.location.origin : \"\");\n\n const config: PanaceaConfig = useMemo(\n () => ({ tenantId, apiBase, customerToken, escalationKeywords, persona }),\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [tenantId, apiBase, customerToken],\n );\n\n // Stable token manager instance across re-renders\n const tokenMgr = useMemo(\n () => new TokenManager(config, apiBase),\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [tenantId, apiBase],\n );\n\n // AI conversation\n const [turns, setTurns] = useState<Turn[]>([]);\n const [loading, setLoading] = useState(false);\n const [streaming, setStreaming] = useState(\"\");\n const sessionId = useRef<string | null>(null);\n\n // Live handover\n const [liveEscalationId, setLiveEscalationId] = useState<string | null>(null);\n const [liveMessages, setLiveMessages] = useState<LiveMessage[]>([]);\n\n // Panel\n const [isOpen, setIsOpen] = useState(false);\n\n const value: PanaceaContextValue = useMemo(\n () => ({\n config,\n apiBase,\n getToken: () => tokenMgr.getToken(),\n turns,\n setTurns,\n loading,\n setLoading,\n streaming,\n setStreaming,\n sessionId,\n liveEscalationId,\n setLiveEscalationId,\n liveMessages,\n setLiveMessages,\n isOpen,\n setIsOpen,\n }),\n [config, apiBase, tokenMgr, turns, loading, streaming, liveEscalationId, liveMessages, isOpen],\n );\n\n return <PanaceaContext.Provider value={value}>{children}</PanaceaContext.Provider>;\n}\n","\"use client\";\n\nimport { useCallback } from \"react\";\nimport { usePanaceaContext } from \"../provider\";\nimport type { Source, Turn } from \"../types\";\n\ninterface QueryResponse {\n answer: string;\n sources: Source[];\n confidence: number;\n flaggedForReview: boolean;\n sessionId: string;\n escalated?: boolean;\n}\n\ninterface UseChatReturn {\n /** All conversation turns so far */\n turns: Turn[];\n /** True while an AI response is in flight */\n loading: boolean;\n /** Partial token stream content during SSE streaming */\n streaming: string;\n /** Current session ID (null until first message) */\n sessionId: string | null;\n /** True once the session has been escalated to a human */\n isEscalated: boolean;\n /** Send a message. Routes to live agent if session is escalated. */\n send: (message: string) => Promise<void>;\n /** Manually trigger escalation to a human agent */\n escalate: (reason?: string) => Promise<void>;\n /** Post a thumbs-up/down reaction for a turn by index */\n react: (turnIndex: number, reaction: \"helpful\" | \"unhelpful\") => Promise<void>;\n /** Push page context to the active session (URL, title, content summary, etc.) */\n setPageContext: (ctx: Record<string, unknown>) => Promise<void>;\n /** Clear all turns and start fresh */\n reset: () => void;\n}\n\nexport function useChat(): UseChatReturn {\n const {\n apiBase,\n getToken,\n turns,\n setTurns,\n loading,\n setLoading,\n streaming,\n setStreaming,\n sessionId,\n liveEscalationId,\n setLiveEscalationId,\n } = usePanaceaContext();\n\n const send = useCallback(\n async (message: string) => {\n // While escalated, route to the live customer-message endpoint\n if (liveEscalationId) {\n setTurns((prev) => [...prev, { role: \"user\", content: message }]);\n try {\n const token = await getToken();\n await fetch(`${apiBase}/api/v1/inbox/${liveEscalationId}/customer-message`, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n Authorization: `Bearer ${token}`,\n },\n body: JSON.stringify({ content: message }),\n });\n } catch {\n // Message shown optimistically — non-critical\n }\n return;\n }\n\n setLoading(true);\n setStreaming(\"\");\n setTurns((prev) => [...prev, { role: \"user\", content: message }]);\n\n try {\n const token = await getToken();\n const res = await fetch(`${apiBase}/api/v1/query`, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n Authorization: `Bearer ${token}`,\n Accept: \"text/event-stream\",\n },\n body: JSON.stringify({\n question: message,\n sessionId: sessionId.current,\n }),\n });\n\n if (!res.ok || !res.body) {\n throw new Error(`Query failed: ${res.status}`);\n }\n\n // SSE streaming\n const reader = res.body.getReader();\n const decoder = new TextDecoder();\n let buffer = \"\";\n let finalResponse: QueryResponse | null = null;\n\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n buffer += decoder.decode(value, { stream: true });\n const lines = buffer.split(\"\\n\");\n buffer = lines.pop() ?? \"\";\n\n for (const line of lines) {\n if (!line.startsWith(\"data: \")) continue;\n const raw = line.slice(6).trim();\n if (!raw || raw === \"[DONE]\") continue;\n try {\n const frame = JSON.parse(raw) as {\n type: \"token\" | \"done\" | \"error\";\n delta?: string;\n answer?: string;\n sources?: Source[];\n confidence?: number;\n sessionId?: string;\n flaggedForReview?: boolean;\n escalated?: boolean;\n message?: string;\n };\n if (frame.type === \"token\" && frame.delta) {\n setStreaming((s) => s + frame.delta);\n } else if (frame.type === \"done\") {\n finalResponse = {\n answer: frame.answer ?? \"\",\n sources: frame.sources ?? [],\n confidence: frame.confidence ?? 0,\n flaggedForReview: frame.flaggedForReview ?? false,\n sessionId: frame.sessionId ?? \"\",\n escalated: frame.escalated,\n };\n } else if (frame.type === \"error\") {\n throw new Error(frame.message ?? \"Stream error\");\n }\n } catch {\n // Ignore malformed frames\n }\n }\n }\n\n if (!finalResponse) throw new Error(\"Stream ended without done frame\");\n\n sessionId.current = finalResponse.sessionId;\n\n setTurns((prev) => [\n ...prev,\n {\n role: \"assistant\",\n content: finalResponse!.answer,\n confidence: finalResponse!.confidence,\n sources: finalResponse!.sources,\n flaggedForReview: finalResponse!.flaggedForReview,\n reaction: null,\n escalated: finalResponse!.escalated,\n },\n ]);\n } catch (err) {\n setTurns((prev) => [\n ...prev,\n {\n role: \"assistant\",\n content:\n err instanceof Error\n ? `Something went wrong: ${err.message}`\n : \"Something went wrong. Please try again.\",\n },\n ]);\n } finally {\n setLoading(false);\n setStreaming(\"\");\n }\n },\n [apiBase, getToken, liveEscalationId, sessionId, setLoading, setStreaming, setTurns],\n );\n\n const escalate = useCallback(\n async (reason = \"Customer requested human support\") => {\n if (!sessionId.current) return;\n try {\n const token = await getToken();\n const res = await fetch(`${apiBase}/api/v1/sessions/${sessionId.current}/escalate`, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n Authorization: `Bearer ${token}`,\n },\n body: JSON.stringify({ reason }),\n });\n if (res.ok) {\n const data = (await res.json()) as {\n data?: { escalationId?: string };\n escalationId?: string;\n };\n const id = data?.data?.escalationId ?? data?.escalationId;\n if (id) setLiveEscalationId(id);\n }\n } catch {\n // Non-critical\n }\n },\n [apiBase, getToken, sessionId, setLiveEscalationId],\n );\n\n const react = useCallback(\n async (turnIndex: number, reaction: \"helpful\" | \"unhelpful\") => {\n if (!sessionId.current) return;\n setTurns((prev) => prev.map((t, i) => (i === turnIndex ? { ...t, reaction } : t)));\n try {\n const token = await getToken();\n await fetch(`${apiBase}/api/v1/sessions/${sessionId.current}/reaction`, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n Authorization: `Bearer ${token}`,\n },\n body: JSON.stringify({ reaction, turnIndex }),\n });\n } catch {\n // Non-critical\n }\n },\n [apiBase, getToken, sessionId, setTurns],\n );\n\n const reset = useCallback(() => {\n setTurns([]);\n setStreaming(\"\");\n sessionId.current = null;\n }, [sessionId, setStreaming, setTurns]);\n\n const setPageContext = useCallback(\n async (ctx: Record<string, unknown>) => {\n if (!sessionId.current) return;\n try {\n const token = await getToken();\n await fetch(`${apiBase}/api/v1/sessions/${sessionId.current}`, {\n method: \"PATCH\",\n headers: {\n \"Content-Type\": \"application/json\",\n Authorization: `Bearer ${token}`,\n },\n body: JSON.stringify({ pageContext: ctx }),\n });\n } catch {\n // Non-critical\n }\n },\n [apiBase, getToken, sessionId],\n );\n\n return {\n turns,\n loading,\n streaming,\n sessionId: sessionId.current,\n isEscalated: !!liveEscalationId,\n send,\n escalate,\n react,\n setPageContext,\n reset,\n };\n}\n","\"use client\";\n\nimport { useCallback, useEffect, useRef } from \"react\";\nimport { usePanaceaContext } from \"../provider\";\nimport type { LiveMessage } from \"../types\";\n\ninterface UseLiveSessionReturn {\n /** True once the session has been escalated */\n isLive: boolean;\n /** The active escalation ID, or null */\n escalationId: string | null;\n /** All messages exchanged since escalation (agent + customer) */\n liveMessages: LiveMessage[];\n /** Agent-only messages (for display in widget — customer messages shown optimistically) */\n agentMessages: LiveMessage[];\n /** Send a customer message to the live agent */\n sendMessage: (content: string) => Promise<void>;\n}\n\nexport function useLiveSession(): UseLiveSessionReturn {\n const { apiBase, getToken, liveEscalationId, liveMessages, setLiveMessages } =\n usePanaceaContext();\n\n const seenIds = useRef<Set<string>>(new Set());\n\n // Poll for new messages every 3s while escalated\n useEffect(() => {\n if (!liveEscalationId) return;\n\n const poll = async () => {\n try {\n const token = await getToken();\n const res = await fetch(`${apiBase}/api/v1/inbox/${liveEscalationId}/messages`, {\n headers: { Authorization: `Bearer ${token}` },\n });\n if (!res.ok) return;\n\n const data = (await res.json()) as {\n data?: { messages?: LiveMessage[] };\n messages?: LiveMessage[];\n };\n const all: LiveMessage[] = data?.data?.messages ?? data?.messages ?? [];\n\n // Only add messages we haven't seen yet\n const newMsgs = all.filter((m) => !seenIds.current.has(m.id));\n if (newMsgs.length > 0) {\n newMsgs.forEach((m) => seenIds.current.add(m.id));\n setLiveMessages((prev) => [...prev, ...newMsgs]);\n }\n } catch {\n // Non-critical\n }\n };\n\n poll();\n const id = setInterval(poll, 3_000);\n return () => clearInterval(id);\n }, [liveEscalationId, apiBase, getToken, setLiveMessages]);\n\n const sendMessage = useCallback(\n async (content: string) => {\n if (!liveEscalationId) return;\n try {\n const token = await getToken();\n await fetch(`${apiBase}/api/v1/inbox/${liveEscalationId}/customer-message`, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n Authorization: `Bearer ${token}`,\n },\n body: JSON.stringify({ content }),\n });\n } catch {\n // Non-critical — message shown optimistically by the caller\n }\n },\n [liveEscalationId, apiBase, getToken],\n );\n\n return {\n isLive: !!liveEscalationId,\n escalationId: liveEscalationId,\n liveMessages,\n agentMessages: liveMessages.filter((m) => m.senderRole === \"agent\"),\n sendMessage,\n };\n}\n","\"use client\";\n\nimport { useCallback } from \"react\";\nimport { usePanaceaContext } from \"../provider\";\n\ninterface UseWidgetReturn {\n isOpen: boolean;\n open: () => void;\n close: () => void;\n toggle: () => void;\n}\n\nexport function useWidget(): UseWidgetReturn {\n const { isOpen, setIsOpen } = usePanaceaContext();\n\n const open = useCallback(() => setIsOpen(true), [setIsOpen]);\n const close = useCallback(() => setIsOpen(false), [setIsOpen]);\n const toggle = useCallback(() => setIsOpen((v) => !v), [setIsOpen]);\n\n return { isOpen, open, close, toggle };\n}\n","import { clsx, type ClassValue } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\nexport function cn(...inputs: ClassValue[]) {\n return twMerge(clsx(inputs));\n}\n","\"use client\";\n\nimport React, { useEffect, useRef } from \"react\";\nimport { cva, type VariantProps } from \"class-variance-authority\";\nimport { cn } from \"../lib/utils\";\nimport { useChat } from \"../hooks/useChat\";\nimport { useLiveSession } from \"../hooks/useLiveSession\";\nimport { useWidget } from \"../hooks/useWidget\";\nimport { usePanaceaContext } from \"../provider\";\nimport type { Turn } from \"../types\";\n\n// ---------------------------------------------------------------------------\n// Button (shadcn pattern)\n// ---------------------------------------------------------------------------\n\nconst buttonVariants = cva(\n \"inline-flex items-center justify-center gap-1.5 rounded-lg text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 disabled:pointer-events-none disabled:opacity-50\",\n {\n variants: {\n variant: {\n default: \"bg-primary text-primary-foreground hover:bg-primary/90\",\n outline: \"border border-input bg-background hover:bg-accent hover:text-accent-foreground\",\n ghost: \"hover:bg-accent hover:text-accent-foreground\",\n },\n size: {\n default: \"h-9 px-4 py-2\",\n sm: \"h-8 px-3 text-xs\",\n icon: \"size-9\",\n },\n },\n defaultVariants: { variant: \"default\", size: \"default\" },\n },\n);\n\ninterface ButtonProps\n extends React.ButtonHTMLAttributes<HTMLButtonElement>, VariantProps<typeof buttonVariants> {}\n\nfunction Button({ className, variant, size, ...props }: ButtonProps) {\n return <button className={cn(buttonVariants({ variant, size }), className)} {...props} />;\n}\n\n// ---------------------------------------------------------------------------\n// FAB\n// ---------------------------------------------------------------------------\n\nexport function PanaceaFAB({ className }: { className?: string }) {\n const { toggle } = useWidget();\n return (\n <button\n aria-label=\"Open support chat\"\n onClick={toggle}\n className={cn(\n \"fixed bottom-6 right-6 z-[2147483647] flex size-14 items-center justify-center rounded-full bg-primary text-2xl text-primary-foreground shadow-lg transition-transform hover:scale-105\",\n className,\n )}\n >\n 💬\n </button>\n );\n}\n\n// ---------------------------------------------------------------------------\n// Message bubble\n// ---------------------------------------------------------------------------\n\n/**\n * Parse [[Label|wiki/path]] or [[wiki/path]] citations from agent answers\n * and render them as styled inline spans (or links when sourceUrl is known).\n * Falls back to plain text for malformed tokens.\n */\nfunction renderContent(text: string): React.ReactNode[] {\n const parts = text.split(/(\\[\\[[^\\]]+\\]\\])/g);\n return parts.map((part, i) => {\n const m = part.match(/^\\[\\[(?:([^|\\]]+)\\|)?([^\\]]+)\\]\\]$/);\n if (m) {\n const label = (m[1] ?? m[2] ?? part).trim();\n return (\n <span\n key={i}\n className=\"inline-flex items-center gap-0.5 rounded bg-blue-50 px-1 py-0.5 text-xs font-medium text-blue-700\"\n >\n <svg className=\"inline size-3 shrink-0\" viewBox=\"0 0 16 16\" fill=\"currentColor\">\n <path d=\"M2 2h5v2H4v8h8v-3h2v5H2V2zm7 0h5v5h-2V4.414L6.707 9.707 5.293 8.293 10.586 3H9V2z\" />\n </svg>\n {label}\n </span>\n );\n }\n if (!part) return null;\n return <span key={i}>{part}</span>;\n }).filter(Boolean) as React.ReactNode[];\n}\n\nfunction Bubble({ turn }: { turn: Turn }) {\n const isUser = turn.role === \"user\";\n const isAgent = turn.isLiveAgent;\n return (\n <div className={cn(\"mb-3 flex flex-col\", isUser ? \"items-end\" : \"items-start\")}>\n {isAgent && (\n <span className=\"mb-1 text-[10px] font-bold uppercase tracking-wide text-blue-600\">\n Agent\n </span>\n )}\n <div\n className={cn(\n \"max-w-[82%] rounded-2xl px-3.5 py-2.5 text-sm leading-relaxed\",\n isUser\n ? \"rounded-tr-sm bg-primary text-primary-foreground\"\n : isAgent\n ? \"rounded-tl-sm bg-blue-100 text-blue-900\"\n : \"rounded-tl-sm bg-muted text-foreground\",\n )}\n >\n {isUser ? turn.content : renderContent(turn.content)}\n </div>\n </div>\n );\n}\n\nfunction TypingDots() {\n return (\n <div className=\"mb-3 flex items-start\">\n <div className=\"flex gap-1 rounded-2xl rounded-tl-sm bg-muted px-3.5 py-3\">\n {[0, 1, 2].map((i) => (\n <span\n key={i}\n className=\"size-1.5 animate-bounce rounded-full bg-muted-foreground/50\"\n style={{ animationDelay: `${i * 0.15}s` }}\n />\n ))}\n </div>\n </div>\n );\n}\n\n// ---------------------------------------------------------------------------\n// PanaceaMessages\n// ---------------------------------------------------------------------------\n\nexport function PanaceaMessages({ className }: { className?: string }) {\n const { turns, loading, streaming } = useChat();\n const { agentMessages } = useLiveSession();\n const bottomRef = useRef<HTMLDivElement>(null);\n\n const agentTurns: Turn[] = agentMessages.map((m) => ({\n role: \"assistant\",\n content: m.content,\n isLiveAgent: true,\n }));\n const allTurns = [...turns, ...agentTurns];\n\n useEffect(() => {\n bottomRef.current?.scrollIntoView({ behavior: \"smooth\" });\n }, [allTurns.length]);\n\n return (\n <div className={cn(\"flex flex-1 flex-col overflow-y-auto p-4\", className)}>\n {allTurns.map((turn, i) => (\n <Bubble key={i} turn={turn} />\n ))}\n {loading && !streaming && <TypingDots />}\n {streaming && <Bubble turn={{ role: \"assistant\", content: streaming }} />}\n <div ref={bottomRef} />\n </div>\n );\n}\n\n// ---------------------------------------------------------------------------\n// PanaceaInput\n// ---------------------------------------------------------------------------\n\nexport function PanaceaInput({\n placeholder,\n className,\n}: {\n placeholder?: string;\n className?: string;\n}) {\n const { send, loading, isEscalated } = useChat();\n const inputRef = useRef<HTMLInputElement>(null);\n\n const handleSend = () => {\n const val = inputRef.current?.value.trim();\n if (!val || loading) return;\n void send(val);\n if (inputRef.current) inputRef.current.value = \"\";\n };\n\n return (\n <div className={cn(\"flex gap-2 border-t border-border bg-background p-3\", className)}>\n <input\n ref={inputRef}\n placeholder={isEscalated ? \"Reply to agent…\" : (placeholder ?? \"Ask a question…\")}\n disabled={loading}\n onKeyDown={(e) => e.key === \"Enter\" && handleSend()}\n className=\"flex-1 rounded-full border border-input bg-muted/40 px-4 py-2 text-sm outline-none placeholder:text-muted-foreground focus:border-primary focus:bg-background disabled:opacity-50\"\n />\n <Button\n onClick={handleSend}\n disabled={loading}\n size=\"sm\"\n className=\"shrink-0 rounded-full px-4\"\n >\n Send\n </Button>\n </div>\n );\n}\n\n// ---------------------------------------------------------------------------\n// PanaceaChat — full pre-built floating panel\n// ---------------------------------------------------------------------------\n\nexport function PanaceaChat({\n title,\n placeholder,\n className,\n}: {\n title?: string;\n placeholder?: string;\n className?: string;\n}) {\n const { config } = usePanaceaContext();\n const { isOpen, close } = useWidget();\n const panelTitle = title ?? config.persona?.name ?? \"Support\";\n\n return (\n <>\n <PanaceaFAB />\n <div\n className={cn(\n \"fixed bottom-24 right-6 z-[2147483646] flex w-[360px] flex-col overflow-hidden rounded-2xl border border-border bg-background shadow-2xl transition-all duration-200\",\n isOpen\n ? \"pointer-events-auto h-[520px] opacity-100\"\n : \"pointer-events-none h-0 opacity-0\",\n className,\n )}\n >\n {/* Header */}\n <div className=\"flex shrink-0 items-center justify-between bg-primary px-4 py-3.5\">\n <span className=\"text-sm font-semibold text-primary-foreground\">{panelTitle}</span>\n <button\n onClick={close}\n aria-label=\"Close\"\n className=\"text-primary-foreground/70 transition-colors hover:text-primary-foreground\"\n >\n ✕\n </button>\n </div>\n\n <PanaceaMessages />\n <PanaceaInput placeholder={placeholder} />\n </div>\n </>\n );\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/token.ts","../src/provider.tsx","../src/hooks/useChat.ts","../src/hooks/useLiveSession.ts","../src/hooks/useWidget.ts","../src/hooks/useSessionHistory.ts","../src/lib/utils.ts","../src/components/index.tsx","../src/components/PanaceaHistory.tsx"],"names":["createContext","useContext","useMemo","useState","useRef","useEffect","jsx","useCallback","react","twMerge","clsx","cva","jsxs","Fragment"],"mappings":"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","file":"index.cjs","sourcesContent":["import type { PanaceaConfig } from \"./types\";\n\ninterface TokenState {\n token: string;\n /** unix ms */\n expiresAt: number;\n}\n\n/**\n * Manages the short-lived widget JWT (15 min TTL).\n * Auto-refreshes 60s before expiry. Concurrent callers share one refresh promise.\n */\nexport class TokenManager {\n private state: TokenState | null = null;\n private refreshPromise: Promise<string> | null = null;\n\n constructor(\n private readonly config: PanaceaConfig,\n private readonly apiBase: string,\n ) {}\n\n async getToken(): Promise<string> {\n if (!this.state || Date.now() >= this.state.expiresAt - 60_000) {\n if (!this.refreshPromise) {\n this.refreshPromise = this.refresh().finally(() => {\n this.refreshPromise = null;\n });\n }\n return this.refreshPromise;\n }\n return this.state.token;\n }\n\n private async refresh(): Promise<string> {\n const res = await fetch(`${this.apiBase}/api/v1/auth/widget-token`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ tenantId: this.config.tenantId }),\n });\n\n if (!res.ok) {\n throw new Error(`Panacea: token refresh failed (${res.status})`);\n }\n\n const data = (await res.json()) as { token: string; expiresAt: string };\n this.state = {\n token: data.token,\n expiresAt: new Date(data.expiresAt).getTime(),\n };\n return this.state.token;\n }\n}\n","\"use client\";\n\nimport React, { createContext, useContext, useEffect, useMemo, useRef, useState } from \"react\";\nimport type { LiveMessage, PanaceaConfig, PanaceaContextValue, Turn } from \"./types\";\nimport { TokenManager } from \"./token\";\n\n// ---------------------------------------------------------------------------\n// Context\n// ---------------------------------------------------------------------------\n\nconst PanaceaContext = createContext<PanaceaContextValue | null>(null);\n\nexport function usePanaceaContext(): PanaceaContextValue {\n const ctx = useContext(PanaceaContext);\n if (!ctx) {\n throw new Error(\n \"usePanaceaContext must be used inside <PanaceaProvider>. \" +\n 'Wrap your component tree with <PanaceaProvider tenantId=\"...\">.',\n );\n }\n return ctx;\n}\n\n// ---------------------------------------------------------------------------\n// Provider\n// ---------------------------------------------------------------------------\n\ninterface PanaceaProviderProps {\n children: React.ReactNode;\n tenantId: string;\n apiBase?: string;\n customerToken?: string;\n escalationKeywords?: string[];\n persona?: PanaceaConfig[\"persona\"];\n}\n\nexport function PanaceaProvider({\n children,\n tenantId,\n apiBase: apiBaseProp,\n customerToken,\n escalationKeywords,\n persona,\n}: PanaceaProviderProps) {\n const apiBase = apiBaseProp ?? (typeof window !== \"undefined\" ? window.location.origin : \"\");\n\n const config: PanaceaConfig = useMemo(\n () => ({ tenantId, apiBase, customerToken, escalationKeywords, persona }),\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [tenantId, apiBase, customerToken],\n );\n\n // Stable token manager instance across re-renders\n const tokenMgr = useMemo(\n () => new TokenManager(config, apiBase),\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [tenantId, apiBase],\n );\n\n // AI conversation\n const [turns, setTurns] = useState<Turn[]>([]);\n const [loading, setLoading] = useState(false);\n const [streaming, setStreaming] = useState(\"\");\n const sessionId = useRef<string | null>(null);\n\n // Live handover\n const [liveEscalationId, setLiveEscalationId] = useState<string | null>(null);\n const [liveMessages, setLiveMessages] = useState<LiveMessage[]>([]);\n\n // Panel\n const [isOpen, setIsOpen] = useState(false);\n\n // Session resume: on mount (or when customerToken changes), attempt to\n // restore the most recent resumable session for this identified customer.\n useEffect(() => {\n if (!customerToken) return;\n let cancelled = false;\n\n async function tryResume() {\n try {\n const token = await tokenMgr.getToken();\n const url = new URL(`${apiBase}/api/v1/sessions/resume`);\n url.searchParams.set(\"customerToken\", customerToken!);\n const res = await fetch(url.toString(), {\n headers: { Authorization: `Bearer ${token}` },\n });\n if (!res.ok || cancelled) return;\n const data = (await res.json()) as { session: { sessionId: string } | null };\n const resumedId = data?.session?.sessionId ?? null;\n if (!resumedId || cancelled) return;\n\n sessionId.current = resumedId;\n\n // Hydrate turns from history\n const turnsRes = await fetch(`${apiBase}/api/v1/sessions/${resumedId}/turns`, {\n headers: { Authorization: `Bearer ${token}` },\n });\n if (!turnsRes.ok || cancelled) return;\n const turnsData = (await turnsRes.json()) as {\n data?: { turns?: Array<{ query: string; response: string }> };\n turns?: Array<{ query: string; response: string }>;\n };\n const rawTurns = turnsData?.data?.turns ?? turnsData?.turns ?? [];\n if (cancelled) return;\n const hydrated: Turn[] = rawTurns.flatMap((t) => [\n { role: \"user\" as const, content: t.query },\n { role: \"assistant\" as const, content: t.response },\n ]);\n if (hydrated.length > 0) setTurns(hydrated);\n } catch {\n // Resume is best-effort — silent fail\n }\n }\n\n void tryResume();\n return () => {\n cancelled = true;\n };\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [customerToken, apiBase]);\n\n const value: PanaceaContextValue = useMemo(\n () => ({\n config,\n apiBase,\n getToken: () => tokenMgr.getToken(),\n turns,\n setTurns,\n loading,\n setLoading,\n streaming,\n setStreaming,\n sessionId,\n liveEscalationId,\n setLiveEscalationId,\n liveMessages,\n setLiveMessages,\n isOpen,\n setIsOpen,\n }),\n [config, apiBase, tokenMgr, turns, loading, streaming, liveEscalationId, liveMessages, isOpen],\n );\n\n return <PanaceaContext.Provider value={value}>{children}</PanaceaContext.Provider>;\n}\n","\"use client\";\n\nimport { useCallback } from \"react\";\nimport { usePanaceaContext } from \"../provider\";\nimport type { Source, Turn } from \"../types\";\n\ninterface QueryResponse {\n answer: string;\n sources: Source[];\n confidence: number;\n flaggedForReview: boolean;\n sessionId: string;\n escalated?: boolean;\n}\n\ninterface UseChatReturn {\n /** All conversation turns so far */\n turns: Turn[];\n /** True while an AI response is in flight */\n loading: boolean;\n /** Partial token stream content during SSE streaming */\n streaming: string;\n /** Current session ID (null until first message) */\n sessionId: string | null;\n /** True once the session has been escalated to a human */\n isEscalated: boolean;\n /** Send a message. Routes to live agent if session is escalated. */\n send: (message: string) => Promise<void>;\n /** Manually trigger escalation to a human agent */\n escalate: (reason?: string) => Promise<void>;\n /** Post a thumbs-up/down reaction for a turn by index */\n react: (turnIndex: number, reaction: \"helpful\" | \"unhelpful\") => Promise<void>;\n /** Push page context to the active session (URL, title, content summary, etc.) */\n setPageContext: (ctx: Record<string, unknown>) => Promise<void>;\n /** Clear all turns and start fresh */\n reset: () => void;\n}\n\nexport function useChat(): UseChatReturn {\n const {\n apiBase,\n getToken,\n turns,\n setTurns,\n loading,\n setLoading,\n streaming,\n setStreaming,\n sessionId,\n liveEscalationId,\n setLiveEscalationId,\n } = usePanaceaContext();\n\n const send = useCallback(\n async (message: string) => {\n // While escalated, route to the live customer-message endpoint\n if (liveEscalationId) {\n setTurns((prev) => [...prev, { role: \"user\", content: message }]);\n try {\n const token = await getToken();\n await fetch(`${apiBase}/api/v1/inbox/${liveEscalationId}/customer-message`, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n Authorization: `Bearer ${token}`,\n },\n body: JSON.stringify({ content: message }),\n });\n } catch {\n // Message shown optimistically — non-critical\n }\n return;\n }\n\n setLoading(true);\n setStreaming(\"\");\n setTurns((prev) => [...prev, { role: \"user\", content: message }]);\n\n try {\n const token = await getToken();\n const res = await fetch(`${apiBase}/api/v1/query`, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n Authorization: `Bearer ${token}`,\n Accept: \"text/event-stream\",\n },\n body: JSON.stringify({\n question: message,\n sessionId: sessionId.current,\n }),\n });\n\n if (!res.ok || !res.body) {\n throw new Error(`Query failed: ${res.status}`);\n }\n\n // SSE streaming\n const reader = res.body.getReader();\n const decoder = new TextDecoder();\n let buffer = \"\";\n let finalResponse: QueryResponse | null = null;\n\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n buffer += decoder.decode(value, { stream: true });\n const lines = buffer.split(\"\\n\");\n buffer = lines.pop() ?? \"\";\n\n for (const line of lines) {\n if (!line.startsWith(\"data: \")) continue;\n const raw = line.slice(6).trim();\n if (!raw || raw === \"[DONE]\") continue;\n try {\n const frame = JSON.parse(raw) as {\n type: \"token\" | \"done\" | \"error\";\n delta?: string;\n answer?: string;\n sources?: Source[];\n confidence?: number;\n sessionId?: string;\n flaggedForReview?: boolean;\n escalated?: boolean;\n message?: string;\n };\n if (frame.type === \"token\" && frame.delta) {\n setStreaming((s) => s + frame.delta);\n } else if (frame.type === \"done\") {\n finalResponse = {\n answer: frame.answer ?? \"\",\n sources: frame.sources ?? [],\n confidence: frame.confidence ?? 0,\n flaggedForReview: frame.flaggedForReview ?? false,\n sessionId: frame.sessionId ?? \"\",\n escalated: frame.escalated,\n };\n } else if (frame.type === \"error\") {\n throw new Error(frame.message ?? \"Stream error\");\n }\n } catch {\n // Ignore malformed frames\n }\n }\n }\n\n if (!finalResponse) throw new Error(\"Stream ended without done frame\");\n\n sessionId.current = finalResponse.sessionId;\n\n setTurns((prev) => [\n ...prev,\n {\n role: \"assistant\",\n content: finalResponse!.answer,\n confidence: finalResponse!.confidence,\n sources: finalResponse!.sources,\n flaggedForReview: finalResponse!.flaggedForReview,\n reaction: null,\n escalated: finalResponse!.escalated,\n },\n ]);\n } catch (err) {\n setTurns((prev) => [\n ...prev,\n {\n role: \"assistant\",\n content:\n err instanceof Error\n ? `Something went wrong: ${err.message}`\n : \"Something went wrong. Please try again.\",\n },\n ]);\n } finally {\n setLoading(false);\n setStreaming(\"\");\n }\n },\n [apiBase, getToken, liveEscalationId, sessionId, setLoading, setStreaming, setTurns],\n );\n\n const escalate = useCallback(\n async (reason = \"Customer requested human support\") => {\n if (!sessionId.current) return;\n try {\n const token = await getToken();\n const res = await fetch(`${apiBase}/api/v1/sessions/${sessionId.current}/escalate`, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n Authorization: `Bearer ${token}`,\n },\n body: JSON.stringify({ reason }),\n });\n if (res.ok) {\n const data = (await res.json()) as {\n data?: { escalationId?: string };\n escalationId?: string;\n };\n const id = data?.data?.escalationId ?? data?.escalationId;\n if (id) setLiveEscalationId(id);\n }\n } catch {\n // Non-critical\n }\n },\n [apiBase, getToken, sessionId, setLiveEscalationId],\n );\n\n const react = useCallback(\n async (turnIndex: number, reaction: \"helpful\" | \"unhelpful\") => {\n if (!sessionId.current) return;\n setTurns((prev) => prev.map((t, i) => (i === turnIndex ? { ...t, reaction } : t)));\n try {\n const token = await getToken();\n await fetch(`${apiBase}/api/v1/sessions/${sessionId.current}/reaction`, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n Authorization: `Bearer ${token}`,\n },\n body: JSON.stringify({ reaction, turnIndex }),\n });\n } catch {\n // Non-critical\n }\n },\n [apiBase, getToken, sessionId, setTurns],\n );\n\n const reset = useCallback(() => {\n setTurns([]);\n setStreaming(\"\");\n sessionId.current = null;\n }, [sessionId, setStreaming, setTurns]);\n\n const setPageContext = useCallback(\n async (ctx: Record<string, unknown>) => {\n if (!sessionId.current) return;\n try {\n const token = await getToken();\n await fetch(`${apiBase}/api/v1/sessions/${sessionId.current}`, {\n method: \"PATCH\",\n headers: {\n \"Content-Type\": \"application/json\",\n Authorization: `Bearer ${token}`,\n },\n body: JSON.stringify({ pageContext: ctx }),\n });\n } catch {\n // Non-critical\n }\n },\n [apiBase, getToken, sessionId],\n );\n\n return {\n turns,\n loading,\n streaming,\n sessionId: sessionId.current,\n isEscalated: !!liveEscalationId,\n send,\n escalate,\n react,\n setPageContext,\n reset,\n };\n}\n","\"use client\";\n\nimport { useCallback, useEffect, useRef } from \"react\";\nimport { usePanaceaContext } from \"../provider\";\nimport type { LiveMessage } from \"../types\";\n\ninterface UseLiveSessionReturn {\n /** True once the session has been escalated */\n isLive: boolean;\n /** The active escalation ID, or null */\n escalationId: string | null;\n /** All messages exchanged since escalation (agent + customer) */\n liveMessages: LiveMessage[];\n /** Agent-only messages (for display in widget — customer messages shown optimistically) */\n agentMessages: LiveMessage[];\n /** Send a customer message to the live agent */\n sendMessage: (content: string) => Promise<void>;\n}\n\nexport function useLiveSession(): UseLiveSessionReturn {\n const { apiBase, getToken, liveEscalationId, liveMessages, setLiveMessages } =\n usePanaceaContext();\n\n const seenIds = useRef<Set<string>>(new Set());\n\n // Poll for new messages every 3s while escalated\n useEffect(() => {\n if (!liveEscalationId) return;\n\n const poll = async () => {\n try {\n const token = await getToken();\n const res = await fetch(`${apiBase}/api/v1/inbox/${liveEscalationId}/messages`, {\n headers: { Authorization: `Bearer ${token}` },\n });\n if (!res.ok) return;\n\n const data = (await res.json()) as {\n data?: { messages?: LiveMessage[] };\n messages?: LiveMessage[];\n };\n const all: LiveMessage[] = data?.data?.messages ?? data?.messages ?? [];\n\n // Only add messages we haven't seen yet\n const newMsgs = all.filter((m) => !seenIds.current.has(m.id));\n if (newMsgs.length > 0) {\n newMsgs.forEach((m) => seenIds.current.add(m.id));\n setLiveMessages((prev) => [...prev, ...newMsgs]);\n }\n } catch {\n // Non-critical\n }\n };\n\n poll();\n const id = setInterval(poll, 3_000);\n return () => clearInterval(id);\n }, [liveEscalationId, apiBase, getToken, setLiveMessages]);\n\n const sendMessage = useCallback(\n async (content: string) => {\n if (!liveEscalationId) return;\n try {\n const token = await getToken();\n await fetch(`${apiBase}/api/v1/inbox/${liveEscalationId}/customer-message`, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n Authorization: `Bearer ${token}`,\n },\n body: JSON.stringify({ content }),\n });\n } catch {\n // Non-critical — message shown optimistically by the caller\n }\n },\n [liveEscalationId, apiBase, getToken],\n );\n\n return {\n isLive: !!liveEscalationId,\n escalationId: liveEscalationId,\n liveMessages,\n agentMessages: liveMessages.filter((m) => m.senderRole === \"agent\"),\n sendMessage,\n };\n}\n","\"use client\";\n\nimport { useCallback } from \"react\";\nimport { usePanaceaContext } from \"../provider\";\n\ninterface UseWidgetReturn {\n isOpen: boolean;\n open: () => void;\n close: () => void;\n toggle: () => void;\n}\n\nexport function useWidget(): UseWidgetReturn {\n const { isOpen, setIsOpen } = usePanaceaContext();\n\n const open = useCallback(() => setIsOpen(true), [setIsOpen]);\n const close = useCallback(() => setIsOpen(false), [setIsOpen]);\n const toggle = useCallback(() => setIsOpen((v) => !v), [setIsOpen]);\n\n return { isOpen, open, close, toggle };\n}\n","\"use client\";\n\nimport { useCallback, useEffect, useState } from \"react\";\nimport { usePanaceaContext } from \"../provider\";\nimport type { HistorySession, HistoryTurn, Turn } from \"../types\";\n\ninterface UseSessionHistoryReturn {\n /** List of past sessions for this customer */\n sessions: HistorySession[];\n /** True while fetching the session list */\n loading: boolean;\n /** Load and display a specific past session's turns in the active chat */\n loadSession: (sessionId: string) => Promise<void>;\n /** Refetch the session list */\n refresh: () => Promise<void>;\n}\n\nexport function useSessionHistory(): UseSessionHistoryReturn {\n const { apiBase, getToken, config, setTurns, sessionId: activeSessionIdRef } = usePanaceaContext();\n\n const [sessions, setSessions] = useState<HistorySession[]>([]);\n const [loading, setLoading] = useState(false);\n\n const fetchSessions = useCallback(async () => {\n if (!config.customerToken) return;\n setLoading(true);\n try {\n const token = await getToken();\n const url = new URL(`${apiBase}/api/v1/sessions`);\n url.searchParams.set(\"customerToken\", config.customerToken);\n const res = await fetch(url.toString(), {\n headers: { Authorization: `Bearer ${token}` },\n });\n if (!res.ok) return;\n const data = (await res.json()) as {\n data?: HistorySession[];\n sessions?: HistorySession[];\n } | HistorySession[];\n const list = Array.isArray(data)\n ? data\n : (data as { data?: HistorySession[]; sessions?: HistorySession[] })?.data ??\n (data as { sessions?: HistorySession[] })?.sessions ??\n [];\n setSessions(list);\n } catch {\n // silent\n } finally {\n setLoading(false);\n }\n }, [apiBase, getToken, config.customerToken]);\n\n useEffect(() => {\n // eslint-disable-next-line react-hooks/set-state-in-effect\n void fetchSessions();\n }, [fetchSessions]);\n\n const loadSession = useCallback(\n async (sessionId: string) => {\n try {\n const token = await getToken();\n const res = await fetch(`${apiBase}/api/v1/sessions/${sessionId}/turns`, {\n headers: { Authorization: `Bearer ${token}` },\n });\n if (!res.ok) return;\n const data = (await res.json()) as {\n data?: { turns?: HistoryTurn[] };\n turns?: HistoryTurn[];\n };\n const raw = data?.data?.turns ?? data?.turns ?? [];\n const turns: Turn[] = raw.flatMap((t) => [\n { role: \"user\" as const, content: t.query },\n { role: \"assistant\" as const, content: t.response },\n ]);\n activeSessionIdRef.current = sessionId;\n setTurns(turns);\n } catch {\n // silent\n }\n },\n [apiBase, getToken, setTurns, activeSessionIdRef],\n );\n\n return { sessions, loading, loadSession, refresh: fetchSessions };\n}\n","import { clsx, type ClassValue } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\nexport function cn(...inputs: ClassValue[]) {\n return twMerge(clsx(inputs));\n}\n","\"use client\";\n\nimport React, { useEffect, useRef } from \"react\";\nimport { cva, type VariantProps } from \"class-variance-authority\";\nimport { cn } from \"../lib/utils\";\nimport { useChat } from \"../hooks/useChat\";\nimport { useLiveSession } from \"../hooks/useLiveSession\";\nimport { useWidget } from \"../hooks/useWidget\";\nimport { usePanaceaContext } from \"../provider\";\nimport type { Turn } from \"../types\";\n\n// ---------------------------------------------------------------------------\n// Button (shadcn pattern)\n// ---------------------------------------------------------------------------\n\nconst buttonVariants = cva(\n \"inline-flex items-center justify-center gap-1.5 rounded-lg text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 disabled:pointer-events-none disabled:opacity-50\",\n {\n variants: {\n variant: {\n default: \"bg-primary text-primary-foreground hover:bg-primary/90\",\n outline: \"border border-input bg-background hover:bg-accent hover:text-accent-foreground\",\n ghost: \"hover:bg-accent hover:text-accent-foreground\",\n },\n size: {\n default: \"h-9 px-4 py-2\",\n sm: \"h-8 px-3 text-xs\",\n icon: \"size-9\",\n },\n },\n defaultVariants: { variant: \"default\", size: \"default\" },\n },\n);\n\ninterface ButtonProps\n extends React.ButtonHTMLAttributes<HTMLButtonElement>, VariantProps<typeof buttonVariants> {}\n\nfunction Button({ className, variant, size, ...props }: ButtonProps) {\n return <button className={cn(buttonVariants({ variant, size }), className)} {...props} />;\n}\n\n// ---------------------------------------------------------------------------\n// FAB\n// ---------------------------------------------------------------------------\n\nexport function PanaceaFAB({ className }: { className?: string }) {\n const { toggle } = useWidget();\n return (\n <button\n aria-label=\"Open support chat\"\n onClick={toggle}\n className={cn(\n \"fixed bottom-6 right-6 z-[2147483647] flex size-14 items-center justify-center rounded-full bg-primary text-2xl text-primary-foreground shadow-lg transition-transform hover:scale-105\",\n className,\n )}\n >\n 💬\n </button>\n );\n}\n\n// ---------------------------------------------------------------------------\n// Message bubble\n// ---------------------------------------------------------------------------\n\n/**\n * Parse [[Label|wiki/path]] or [[wiki/path]] citations from agent answers\n * and render them as styled inline spans (or links when sourceUrl is known).\n * Falls back to plain text for malformed tokens.\n */\nfunction renderContent(text: string): React.ReactNode[] {\n const parts = text.split(/(\\[\\[[^\\]]+\\]\\])/g);\n return parts\n .map((part, i) => {\n const m = part.match(/^\\[\\[(?:([^|\\]]+)\\|)?([^\\]]+)\\]\\]$/);\n if (m) {\n const label = (m[1] ?? m[2] ?? part).trim();\n return (\n <span\n key={i}\n className=\"inline-flex items-center gap-0.5 rounded bg-blue-50 px-1 py-0.5 text-xs font-medium text-blue-700\"\n >\n <svg className=\"inline size-3 shrink-0\" viewBox=\"0 0 16 16\" fill=\"currentColor\">\n <path d=\"M2 2h5v2H4v8h8v-3h2v5H2V2zm7 0h5v5h-2V4.414L6.707 9.707 5.293 8.293 10.586 3H9V2z\" />\n </svg>\n {label}\n </span>\n );\n }\n if (!part) return null;\n return <span key={i}>{part}</span>;\n })\n .filter(Boolean) as React.ReactNode[];\n}\n\nfunction Bubble({ turn }: { turn: Turn }) {\n const isUser = turn.role === \"user\";\n const isAgent = turn.isLiveAgent;\n return (\n <div className={cn(\"mb-3 flex flex-col\", isUser ? \"items-end\" : \"items-start\")}>\n {isAgent && (\n <span className=\"mb-1 text-[10px] font-bold uppercase tracking-wide text-blue-600\">\n Agent\n </span>\n )}\n <div\n className={cn(\n \"max-w-[82%] rounded-2xl px-3.5 py-2.5 text-sm leading-relaxed\",\n isUser\n ? \"rounded-tr-sm bg-primary text-primary-foreground\"\n : isAgent\n ? \"rounded-tl-sm bg-blue-100 text-blue-900\"\n : \"rounded-tl-sm bg-muted text-foreground\",\n )}\n >\n {isUser ? turn.content : renderContent(turn.content)}\n </div>\n </div>\n );\n}\n\nfunction TypingDots() {\n return (\n <div className=\"mb-3 flex items-start\">\n <div className=\"flex gap-1 rounded-2xl rounded-tl-sm bg-muted px-3.5 py-3\">\n {[0, 1, 2].map((i) => (\n <span\n key={i}\n className=\"size-1.5 animate-bounce rounded-full bg-muted-foreground/50\"\n style={{ animationDelay: `${i * 0.15}s` }}\n />\n ))}\n </div>\n </div>\n );\n}\n\n// ---------------------------------------------------------------------------\n// PanaceaMessages\n// ---------------------------------------------------------------------------\n\nexport function PanaceaMessages({ className }: { className?: string }) {\n const { turns, loading, streaming } = useChat();\n const { agentMessages } = useLiveSession();\n const bottomRef = useRef<HTMLDivElement>(null);\n\n const agentTurns: Turn[] = agentMessages.map((m) => ({\n role: \"assistant\",\n content: m.content,\n isLiveAgent: true,\n }));\n const allTurns = [...turns, ...agentTurns];\n\n useEffect(() => {\n bottomRef.current?.scrollIntoView({ behavior: \"smooth\" });\n }, [allTurns.length]);\n\n return (\n <div className={cn(\"flex flex-1 flex-col overflow-y-auto p-4\", className)}>\n {allTurns.map((turn, i) => (\n <Bubble key={i} turn={turn} />\n ))}\n {loading && !streaming && <TypingDots />}\n {streaming && <Bubble turn={{ role: \"assistant\", content: streaming }} />}\n <div ref={bottomRef} />\n </div>\n );\n}\n\n// ---------------------------------------------------------------------------\n// PanaceaInput\n// ---------------------------------------------------------------------------\n\nexport function PanaceaInput({\n placeholder,\n className,\n}: {\n placeholder?: string;\n className?: string;\n}) {\n const { send, loading, isEscalated } = useChat();\n const inputRef = useRef<HTMLInputElement>(null);\n\n const handleSend = () => {\n const val = inputRef.current?.value.trim();\n if (!val || loading) return;\n void send(val);\n if (inputRef.current) inputRef.current.value = \"\";\n };\n\n return (\n <div className={cn(\"flex gap-2 border-t border-border bg-background p-3\", className)}>\n <input\n ref={inputRef}\n placeholder={isEscalated ? \"Reply to agent…\" : (placeholder ?? \"Ask a question…\")}\n disabled={loading}\n onKeyDown={(e) => e.key === \"Enter\" && handleSend()}\n className=\"flex-1 rounded-full border border-input bg-muted/40 px-4 py-2 text-sm outline-none placeholder:text-muted-foreground focus:border-primary focus:bg-background disabled:opacity-50\"\n />\n <Button\n onClick={handleSend}\n disabled={loading}\n size=\"sm\"\n className=\"shrink-0 rounded-full px-4\"\n >\n Send\n </Button>\n </div>\n );\n}\n\n// ---------------------------------------------------------------------------\n// PanaceaChat — full pre-built floating panel\n// ---------------------------------------------------------------------------\n\nexport function PanaceaChat({\n title,\n placeholder,\n className,\n}: {\n title?: string;\n placeholder?: string;\n className?: string;\n}) {\n const { config } = usePanaceaContext();\n const { isOpen, close } = useWidget();\n const panelTitle = title ?? config.persona?.name ?? \"Support\";\n\n return (\n <>\n <PanaceaFAB />\n <div\n className={cn(\n \"fixed bottom-24 right-6 z-[2147483646] flex w-[360px] flex-col overflow-hidden rounded-2xl border border-border bg-background shadow-2xl transition-all duration-200\",\n isOpen\n ? \"pointer-events-auto h-[520px] opacity-100\"\n : \"pointer-events-none h-0 opacity-0\",\n className,\n )}\n >\n {/* Header */}\n <div className=\"flex shrink-0 items-center justify-between bg-primary px-4 py-3.5\">\n <span className=\"text-sm font-semibold text-primary-foreground\">{panelTitle}</span>\n <button\n onClick={close}\n aria-label=\"Close\"\n className=\"text-primary-foreground/70 transition-colors hover:text-primary-foreground\"\n >\n ✕\n </button>\n </div>\n\n <PanaceaMessages />\n <PanaceaInput placeholder={placeholder} />\n </div>\n </>\n );\n}\n","\"use client\";\n\nimport React, { useState } from \"react\";\nimport { cn } from \"../lib/utils\";\nimport { useSessionHistory } from \"../hooks/useSessionHistory\";\nimport { usePanaceaContext } from \"../provider\";\nimport type { HistorySession } from \"../types\";\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\nfunction formatDate(iso: string): string {\n try {\n return new Intl.DateTimeFormat(undefined, {\n month: \"short\",\n day: \"numeric\",\n hour: \"2-digit\",\n minute: \"2-digit\",\n }).format(new Date(iso));\n } catch {\n return iso;\n }\n}\n\n// ---------------------------------------------------------------------------\n// PanaceaHistory\n// ---------------------------------------------------------------------------\n\ninterface PanaceaHistoryProps {\n /** Called when the user clicks a session row and it loads into chat */\n onSessionLoaded?: (sessionId: string) => void;\n className?: string;\n}\n\n/**\n * Renders a scrollable list of past sessions for the authenticated customer.\n * Requires `customerToken` to be set on the parent `<PanaceaProvider>`.\n * Clicking a row loads the turns into the active chat.\n */\nexport function PanaceaHistory({ onSessionLoaded, className }: PanaceaHistoryProps) {\n const { config } = usePanaceaContext();\n const { sessions, loading, loadSession } = useSessionHistory();\n const [active, setActive] = useState<string | null>(null);\n const [loadingId, setLoadingId] = useState<string | null>(null);\n\n if (!config.customerToken) {\n return (\n <div className={cn(\"flex flex-col items-center justify-center gap-2 py-8 text-center text-sm text-muted-foreground\", className)}>\n <span>Sign in to see your conversation history.</span>\n </div>\n );\n }\n\n if (loading) {\n return (\n <div className={cn(\"flex flex-col gap-2 p-3\", className)}>\n {[1, 2, 3].map((i) => (\n <div\n key={i}\n className=\"h-14 animate-pulse rounded-lg bg-muted\"\n />\n ))}\n </div>\n );\n }\n\n if (sessions.length === 0) {\n return (\n <div className={cn(\"flex flex-col items-center justify-center gap-2 py-8 text-center text-sm text-muted-foreground\", className)}>\n <span>No previous conversations found.</span>\n </div>\n );\n }\n\n async function handleLoad(session: HistorySession) {\n setLoadingId(session.sessionId);\n await loadSession(session.sessionId);\n setActive(session.sessionId);\n setLoadingId(null);\n onSessionLoaded?.(session.sessionId);\n }\n\n return (\n <div className={cn(\"flex flex-col gap-1 overflow-y-auto p-2\", className)}>\n {sessions.map((session) => {\n const isActive = active === session.sessionId;\n const isLoading = loadingId === session.sessionId;\n return (\n <button\n key={session.sessionId}\n onClick={() => void handleLoad(session)}\n disabled={isLoading}\n className={cn(\n \"flex w-full flex-col gap-0.5 rounded-lg px-3 py-2.5 text-left text-sm transition-colors hover:bg-accent disabled:cursor-wait\",\n isActive && \"bg-accent\",\n )}\n >\n <span className=\"truncate font-medium leading-snug text-foreground\">\n {session.preview ?? \"Conversation\"}\n </span>\n <div className=\"flex items-center gap-2 text-xs text-muted-foreground\">\n <span>{formatDate(session.createdAt)}</span>\n {session.turnCount !== undefined && (\n <>\n <span aria-hidden>·</span>\n <span>{session.turnCount} {session.turnCount === 1 ? \"message\" : \"messages\"}</span>\n </>\n )}\n {isLoading && (\n <>\n <span aria-hidden>·</span>\n <span>Loading…</span>\n </>\n )}\n </div>\n </button>\n );\n })}\n </div>\n );\n}\n"]}
|
package/dist/index.d.cts
CHANGED
|
@@ -38,6 +38,20 @@ interface LiveMessage {
|
|
|
38
38
|
content: string;
|
|
39
39
|
createdAt: string;
|
|
40
40
|
}
|
|
41
|
+
interface HistoryTurn {
|
|
42
|
+
id: string;
|
|
43
|
+
query: string;
|
|
44
|
+
response: string;
|
|
45
|
+
createdAt: string;
|
|
46
|
+
}
|
|
47
|
+
interface HistorySession {
|
|
48
|
+
sessionId: string;
|
|
49
|
+
createdAt: string;
|
|
50
|
+
updatedAt?: string;
|
|
51
|
+
/** Preview of the first message in the session */
|
|
52
|
+
preview?: string;
|
|
53
|
+
turnCount?: number;
|
|
54
|
+
}
|
|
41
55
|
|
|
42
56
|
interface PanaceaProviderProps {
|
|
43
57
|
children: React.ReactNode;
|
|
@@ -95,6 +109,18 @@ interface UseWidgetReturn {
|
|
|
95
109
|
}
|
|
96
110
|
declare function useWidget(): UseWidgetReturn;
|
|
97
111
|
|
|
112
|
+
interface UseSessionHistoryReturn {
|
|
113
|
+
/** List of past sessions for this customer */
|
|
114
|
+
sessions: HistorySession[];
|
|
115
|
+
/** True while fetching the session list */
|
|
116
|
+
loading: boolean;
|
|
117
|
+
/** Load and display a specific past session's turns in the active chat */
|
|
118
|
+
loadSession: (sessionId: string) => Promise<void>;
|
|
119
|
+
/** Refetch the session list */
|
|
120
|
+
refresh: () => Promise<void>;
|
|
121
|
+
}
|
|
122
|
+
declare function useSessionHistory(): UseSessionHistoryReturn;
|
|
123
|
+
|
|
98
124
|
declare function PanaceaFAB({ className }: {
|
|
99
125
|
className?: string;
|
|
100
126
|
}): React.JSX.Element;
|
|
@@ -111,4 +137,16 @@ declare function PanaceaChat({ title, placeholder, className, }: {
|
|
|
111
137
|
className?: string;
|
|
112
138
|
}): React.JSX.Element;
|
|
113
139
|
|
|
114
|
-
|
|
140
|
+
interface PanaceaHistoryProps {
|
|
141
|
+
/** Called when the user clicks a session row and it loads into chat */
|
|
142
|
+
onSessionLoaded?: (sessionId: string) => void;
|
|
143
|
+
className?: string;
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* Renders a scrollable list of past sessions for the authenticated customer.
|
|
147
|
+
* Requires `customerToken` to be set on the parent `<PanaceaProvider>`.
|
|
148
|
+
* Clicking a row loads the turns into the active chat.
|
|
149
|
+
*/
|
|
150
|
+
declare function PanaceaHistory({ onSessionLoaded, className }: PanaceaHistoryProps): React.JSX.Element;
|
|
151
|
+
|
|
152
|
+
export { type HistorySession, type HistoryTurn, type LiveMessage, PanaceaChat, type PanaceaConfig, PanaceaFAB, PanaceaHistory, PanaceaInput, PanaceaMessages, PanaceaProvider, type Source, type Turn, useChat, useLiveSession, useSessionHistory, useWidget };
|
package/dist/index.d.ts
CHANGED
|
@@ -38,6 +38,20 @@ interface LiveMessage {
|
|
|
38
38
|
content: string;
|
|
39
39
|
createdAt: string;
|
|
40
40
|
}
|
|
41
|
+
interface HistoryTurn {
|
|
42
|
+
id: string;
|
|
43
|
+
query: string;
|
|
44
|
+
response: string;
|
|
45
|
+
createdAt: string;
|
|
46
|
+
}
|
|
47
|
+
interface HistorySession {
|
|
48
|
+
sessionId: string;
|
|
49
|
+
createdAt: string;
|
|
50
|
+
updatedAt?: string;
|
|
51
|
+
/** Preview of the first message in the session */
|
|
52
|
+
preview?: string;
|
|
53
|
+
turnCount?: number;
|
|
54
|
+
}
|
|
41
55
|
|
|
42
56
|
interface PanaceaProviderProps {
|
|
43
57
|
children: React.ReactNode;
|
|
@@ -95,6 +109,18 @@ interface UseWidgetReturn {
|
|
|
95
109
|
}
|
|
96
110
|
declare function useWidget(): UseWidgetReturn;
|
|
97
111
|
|
|
112
|
+
interface UseSessionHistoryReturn {
|
|
113
|
+
/** List of past sessions for this customer */
|
|
114
|
+
sessions: HistorySession[];
|
|
115
|
+
/** True while fetching the session list */
|
|
116
|
+
loading: boolean;
|
|
117
|
+
/** Load and display a specific past session's turns in the active chat */
|
|
118
|
+
loadSession: (sessionId: string) => Promise<void>;
|
|
119
|
+
/** Refetch the session list */
|
|
120
|
+
refresh: () => Promise<void>;
|
|
121
|
+
}
|
|
122
|
+
declare function useSessionHistory(): UseSessionHistoryReturn;
|
|
123
|
+
|
|
98
124
|
declare function PanaceaFAB({ className }: {
|
|
99
125
|
className?: string;
|
|
100
126
|
}): React.JSX.Element;
|
|
@@ -111,4 +137,16 @@ declare function PanaceaChat({ title, placeholder, className, }: {
|
|
|
111
137
|
className?: string;
|
|
112
138
|
}): React.JSX.Element;
|
|
113
139
|
|
|
114
|
-
|
|
140
|
+
interface PanaceaHistoryProps {
|
|
141
|
+
/** Called when the user clicks a session row and it loads into chat */
|
|
142
|
+
onSessionLoaded?: (sessionId: string) => void;
|
|
143
|
+
className?: string;
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* Renders a scrollable list of past sessions for the authenticated customer.
|
|
147
|
+
* Requires `customerToken` to be set on the parent `<PanaceaProvider>`.
|
|
148
|
+
* Clicking a row loads the turns into the active chat.
|
|
149
|
+
*/
|
|
150
|
+
declare function PanaceaHistory({ onSessionLoaded, className }: PanaceaHistoryProps): React.JSX.Element;
|
|
151
|
+
|
|
152
|
+
export { type HistorySession, type HistoryTurn, type LiveMessage, PanaceaChat, type PanaceaConfig, PanaceaFAB, PanaceaHistory, PanaceaInput, PanaceaMessages, PanaceaProvider, type Source, type Turn, useChat, useLiveSession, useSessionHistory, useWidget };
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { createContext, useMemo, useState, useRef,
|
|
1
|
+
import { createContext, useMemo, useState, useRef, useEffect, useCallback, useContext } from 'react';
|
|
2
2
|
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
3
3
|
import { cva } from 'class-variance-authority';
|
|
4
4
|
import { clsx } from 'clsx';
|
|
@@ -80,6 +80,42 @@ function PanaceaProvider({
|
|
|
80
80
|
const [liveEscalationId, setLiveEscalationId] = useState(null);
|
|
81
81
|
const [liveMessages, setLiveMessages] = useState([]);
|
|
82
82
|
const [isOpen, setIsOpen] = useState(false);
|
|
83
|
+
useEffect(() => {
|
|
84
|
+
if (!customerToken) return;
|
|
85
|
+
let cancelled = false;
|
|
86
|
+
async function tryResume() {
|
|
87
|
+
try {
|
|
88
|
+
const token = await tokenMgr.getToken();
|
|
89
|
+
const url = new URL(`${apiBase}/api/v1/sessions/resume`);
|
|
90
|
+
url.searchParams.set("customerToken", customerToken);
|
|
91
|
+
const res = await fetch(url.toString(), {
|
|
92
|
+
headers: { Authorization: `Bearer ${token}` }
|
|
93
|
+
});
|
|
94
|
+
if (!res.ok || cancelled) return;
|
|
95
|
+
const data = await res.json();
|
|
96
|
+
const resumedId = data?.session?.sessionId ?? null;
|
|
97
|
+
if (!resumedId || cancelled) return;
|
|
98
|
+
sessionId.current = resumedId;
|
|
99
|
+
const turnsRes = await fetch(`${apiBase}/api/v1/sessions/${resumedId}/turns`, {
|
|
100
|
+
headers: { Authorization: `Bearer ${token}` }
|
|
101
|
+
});
|
|
102
|
+
if (!turnsRes.ok || cancelled) return;
|
|
103
|
+
const turnsData = await turnsRes.json();
|
|
104
|
+
const rawTurns = turnsData?.data?.turns ?? turnsData?.turns ?? [];
|
|
105
|
+
if (cancelled) return;
|
|
106
|
+
const hydrated = rawTurns.flatMap((t) => [
|
|
107
|
+
{ role: "user", content: t.query },
|
|
108
|
+
{ role: "assistant", content: t.response }
|
|
109
|
+
]);
|
|
110
|
+
if (hydrated.length > 0) setTurns(hydrated);
|
|
111
|
+
} catch {
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
void tryResume();
|
|
115
|
+
return () => {
|
|
116
|
+
cancelled = true;
|
|
117
|
+
};
|
|
118
|
+
}, [customerToken, apiBase]);
|
|
83
119
|
const value = useMemo(
|
|
84
120
|
() => ({
|
|
85
121
|
config,
|
|
@@ -355,6 +391,55 @@ function useWidget() {
|
|
|
355
391
|
const toggle = useCallback(() => setIsOpen((v) => !v), [setIsOpen]);
|
|
356
392
|
return { isOpen, open, close, toggle };
|
|
357
393
|
}
|
|
394
|
+
function useSessionHistory() {
|
|
395
|
+
const { apiBase, getToken, config, setTurns, sessionId: activeSessionIdRef } = usePanaceaContext();
|
|
396
|
+
const [sessions, setSessions] = useState([]);
|
|
397
|
+
const [loading, setLoading] = useState(false);
|
|
398
|
+
const fetchSessions = useCallback(async () => {
|
|
399
|
+
if (!config.customerToken) return;
|
|
400
|
+
setLoading(true);
|
|
401
|
+
try {
|
|
402
|
+
const token = await getToken();
|
|
403
|
+
const url = new URL(`${apiBase}/api/v1/sessions`);
|
|
404
|
+
url.searchParams.set("customerToken", config.customerToken);
|
|
405
|
+
const res = await fetch(url.toString(), {
|
|
406
|
+
headers: { Authorization: `Bearer ${token}` }
|
|
407
|
+
});
|
|
408
|
+
if (!res.ok) return;
|
|
409
|
+
const data = await res.json();
|
|
410
|
+
const list = Array.isArray(data) ? data : data?.data ?? data?.sessions ?? [];
|
|
411
|
+
setSessions(list);
|
|
412
|
+
} catch {
|
|
413
|
+
} finally {
|
|
414
|
+
setLoading(false);
|
|
415
|
+
}
|
|
416
|
+
}, [apiBase, getToken, config.customerToken]);
|
|
417
|
+
useEffect(() => {
|
|
418
|
+
void fetchSessions();
|
|
419
|
+
}, [fetchSessions]);
|
|
420
|
+
const loadSession = useCallback(
|
|
421
|
+
async (sessionId) => {
|
|
422
|
+
try {
|
|
423
|
+
const token = await getToken();
|
|
424
|
+
const res = await fetch(`${apiBase}/api/v1/sessions/${sessionId}/turns`, {
|
|
425
|
+
headers: { Authorization: `Bearer ${token}` }
|
|
426
|
+
});
|
|
427
|
+
if (!res.ok) return;
|
|
428
|
+
const data = await res.json();
|
|
429
|
+
const raw = data?.data?.turns ?? data?.turns ?? [];
|
|
430
|
+
const turns = raw.flatMap((t) => [
|
|
431
|
+
{ role: "user", content: t.query },
|
|
432
|
+
{ role: "assistant", content: t.response }
|
|
433
|
+
]);
|
|
434
|
+
activeSessionIdRef.current = sessionId;
|
|
435
|
+
setTurns(turns);
|
|
436
|
+
} catch {
|
|
437
|
+
}
|
|
438
|
+
},
|
|
439
|
+
[apiBase, getToken, setTurns, activeSessionIdRef]
|
|
440
|
+
);
|
|
441
|
+
return { sessions, loading, loadSession, refresh: fetchSessions };
|
|
442
|
+
}
|
|
358
443
|
function cn(...inputs) {
|
|
359
444
|
return twMerge(clsx(inputs));
|
|
360
445
|
}
|
|
@@ -536,7 +621,81 @@ function PanaceaChat({
|
|
|
536
621
|
)
|
|
537
622
|
] });
|
|
538
623
|
}
|
|
624
|
+
function formatDate(iso) {
|
|
625
|
+
try {
|
|
626
|
+
return new Intl.DateTimeFormat(void 0, {
|
|
627
|
+
month: "short",
|
|
628
|
+
day: "numeric",
|
|
629
|
+
hour: "2-digit",
|
|
630
|
+
minute: "2-digit"
|
|
631
|
+
}).format(new Date(iso));
|
|
632
|
+
} catch {
|
|
633
|
+
return iso;
|
|
634
|
+
}
|
|
635
|
+
}
|
|
636
|
+
function PanaceaHistory({ onSessionLoaded, className }) {
|
|
637
|
+
const { config } = usePanaceaContext();
|
|
638
|
+
const { sessions, loading, loadSession } = useSessionHistory();
|
|
639
|
+
const [active, setActive] = useState(null);
|
|
640
|
+
const [loadingId, setLoadingId] = useState(null);
|
|
641
|
+
if (!config.customerToken) {
|
|
642
|
+
return /* @__PURE__ */ jsx("div", { className: cn("flex flex-col items-center justify-center gap-2 py-8 text-center text-sm text-muted-foreground", className), children: /* @__PURE__ */ jsx("span", { children: "Sign in to see your conversation history." }) });
|
|
643
|
+
}
|
|
644
|
+
if (loading) {
|
|
645
|
+
return /* @__PURE__ */ jsx("div", { className: cn("flex flex-col gap-2 p-3", className), children: [1, 2, 3].map((i) => /* @__PURE__ */ jsx(
|
|
646
|
+
"div",
|
|
647
|
+
{
|
|
648
|
+
className: "h-14 animate-pulse rounded-lg bg-muted"
|
|
649
|
+
},
|
|
650
|
+
i
|
|
651
|
+
)) });
|
|
652
|
+
}
|
|
653
|
+
if (sessions.length === 0) {
|
|
654
|
+
return /* @__PURE__ */ jsx("div", { className: cn("flex flex-col items-center justify-center gap-2 py-8 text-center text-sm text-muted-foreground", className), children: /* @__PURE__ */ jsx("span", { children: "No previous conversations found." }) });
|
|
655
|
+
}
|
|
656
|
+
async function handleLoad(session) {
|
|
657
|
+
setLoadingId(session.sessionId);
|
|
658
|
+
await loadSession(session.sessionId);
|
|
659
|
+
setActive(session.sessionId);
|
|
660
|
+
setLoadingId(null);
|
|
661
|
+
onSessionLoaded?.(session.sessionId);
|
|
662
|
+
}
|
|
663
|
+
return /* @__PURE__ */ jsx("div", { className: cn("flex flex-col gap-1 overflow-y-auto p-2", className), children: sessions.map((session) => {
|
|
664
|
+
const isActive = active === session.sessionId;
|
|
665
|
+
const isLoading = loadingId === session.sessionId;
|
|
666
|
+
return /* @__PURE__ */ jsxs(
|
|
667
|
+
"button",
|
|
668
|
+
{
|
|
669
|
+
onClick: () => void handleLoad(session),
|
|
670
|
+
disabled: isLoading,
|
|
671
|
+
className: cn(
|
|
672
|
+
"flex w-full flex-col gap-0.5 rounded-lg px-3 py-2.5 text-left text-sm transition-colors hover:bg-accent disabled:cursor-wait",
|
|
673
|
+
isActive && "bg-accent"
|
|
674
|
+
),
|
|
675
|
+
children: [
|
|
676
|
+
/* @__PURE__ */ jsx("span", { className: "truncate font-medium leading-snug text-foreground", children: session.preview ?? "Conversation" }),
|
|
677
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 text-xs text-muted-foreground", children: [
|
|
678
|
+
/* @__PURE__ */ jsx("span", { children: formatDate(session.createdAt) }),
|
|
679
|
+
session.turnCount !== void 0 && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
680
|
+
/* @__PURE__ */ jsx("span", { "aria-hidden": true, children: "\xB7" }),
|
|
681
|
+
/* @__PURE__ */ jsxs("span", { children: [
|
|
682
|
+
session.turnCount,
|
|
683
|
+
" ",
|
|
684
|
+
session.turnCount === 1 ? "message" : "messages"
|
|
685
|
+
] })
|
|
686
|
+
] }),
|
|
687
|
+
isLoading && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
688
|
+
/* @__PURE__ */ jsx("span", { "aria-hidden": true, children: "\xB7" }),
|
|
689
|
+
/* @__PURE__ */ jsx("span", { children: "Loading\u2026" })
|
|
690
|
+
] })
|
|
691
|
+
] })
|
|
692
|
+
]
|
|
693
|
+
},
|
|
694
|
+
session.sessionId
|
|
695
|
+
);
|
|
696
|
+
}) });
|
|
697
|
+
}
|
|
539
698
|
|
|
540
|
-
export { PanaceaChat, PanaceaFAB, PanaceaInput, PanaceaMessages, PanaceaProvider, useChat, useLiveSession, useWidget };
|
|
699
|
+
export { PanaceaChat, PanaceaFAB, PanaceaHistory, PanaceaInput, PanaceaMessages, PanaceaProvider, useChat, useLiveSession, useSessionHistory, useWidget };
|
|
541
700
|
//# sourceMappingURL=index.js.map
|
|
542
701
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/token.ts","../src/provider.tsx","../src/hooks/useChat.ts","../src/hooks/useLiveSession.ts","../src/hooks/useWidget.ts","../src/lib/utils.ts","../src/components/index.tsx"],"names":["useRef","useCallback","jsx","useEffect"],"mappings":"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","file":"index.js","sourcesContent":["import type { PanaceaConfig } from \"./types\";\n\ninterface TokenState {\n token: string;\n /** unix ms */\n expiresAt: number;\n}\n\n/**\n * Manages the short-lived widget JWT (15 min TTL).\n * Auto-refreshes 60s before expiry. Concurrent callers share one refresh promise.\n */\nexport class TokenManager {\n private state: TokenState | null = null;\n private refreshPromise: Promise<string> | null = null;\n\n constructor(\n private readonly config: PanaceaConfig,\n private readonly apiBase: string,\n ) {}\n\n async getToken(): Promise<string> {\n if (!this.state || Date.now() >= this.state.expiresAt - 60_000) {\n if (!this.refreshPromise) {\n this.refreshPromise = this.refresh().finally(() => {\n this.refreshPromise = null;\n });\n }\n return this.refreshPromise;\n }\n return this.state.token;\n }\n\n private async refresh(): Promise<string> {\n const res = await fetch(`${this.apiBase}/api/v1/auth/widget-token`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ tenantId: this.config.tenantId }),\n });\n\n if (!res.ok) {\n throw new Error(`Panacea: token refresh failed (${res.status})`);\n }\n\n const data = (await res.json()) as { token: string; expiresAt: string };\n this.state = {\n token: data.token,\n expiresAt: new Date(data.expiresAt).getTime(),\n };\n return this.state.token;\n }\n}\n","\"use client\";\n\nimport React, { createContext, useContext, useMemo, useRef, useState } from \"react\";\nimport type { LiveMessage, PanaceaConfig, PanaceaContextValue, Turn } from \"./types\";\nimport { TokenManager } from \"./token\";\n\n// ---------------------------------------------------------------------------\n// Context\n// ---------------------------------------------------------------------------\n\nconst PanaceaContext = createContext<PanaceaContextValue | null>(null);\n\nexport function usePanaceaContext(): PanaceaContextValue {\n const ctx = useContext(PanaceaContext);\n if (!ctx) {\n throw new Error(\n \"usePanaceaContext must be used inside <PanaceaProvider>. \" +\n 'Wrap your component tree with <PanaceaProvider tenantId=\"...\">.',\n );\n }\n return ctx;\n}\n\n// ---------------------------------------------------------------------------\n// Provider\n// ---------------------------------------------------------------------------\n\ninterface PanaceaProviderProps {\n children: React.ReactNode;\n tenantId: string;\n apiBase?: string;\n customerToken?: string;\n escalationKeywords?: string[];\n persona?: PanaceaConfig[\"persona\"];\n}\n\nexport function PanaceaProvider({\n children,\n tenantId,\n apiBase: apiBaseProp,\n customerToken,\n escalationKeywords,\n persona,\n}: PanaceaProviderProps) {\n const apiBase = apiBaseProp ?? (typeof window !== \"undefined\" ? window.location.origin : \"\");\n\n const config: PanaceaConfig = useMemo(\n () => ({ tenantId, apiBase, customerToken, escalationKeywords, persona }),\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [tenantId, apiBase, customerToken],\n );\n\n // Stable token manager instance across re-renders\n const tokenMgr = useMemo(\n () => new TokenManager(config, apiBase),\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [tenantId, apiBase],\n );\n\n // AI conversation\n const [turns, setTurns] = useState<Turn[]>([]);\n const [loading, setLoading] = useState(false);\n const [streaming, setStreaming] = useState(\"\");\n const sessionId = useRef<string | null>(null);\n\n // Live handover\n const [liveEscalationId, setLiveEscalationId] = useState<string | null>(null);\n const [liveMessages, setLiveMessages] = useState<LiveMessage[]>([]);\n\n // Panel\n const [isOpen, setIsOpen] = useState(false);\n\n const value: PanaceaContextValue = useMemo(\n () => ({\n config,\n apiBase,\n getToken: () => tokenMgr.getToken(),\n turns,\n setTurns,\n loading,\n setLoading,\n streaming,\n setStreaming,\n sessionId,\n liveEscalationId,\n setLiveEscalationId,\n liveMessages,\n setLiveMessages,\n isOpen,\n setIsOpen,\n }),\n [config, apiBase, tokenMgr, turns, loading, streaming, liveEscalationId, liveMessages, isOpen],\n );\n\n return <PanaceaContext.Provider value={value}>{children}</PanaceaContext.Provider>;\n}\n","\"use client\";\n\nimport { useCallback } from \"react\";\nimport { usePanaceaContext } from \"../provider\";\nimport type { Source, Turn } from \"../types\";\n\ninterface QueryResponse {\n answer: string;\n sources: Source[];\n confidence: number;\n flaggedForReview: boolean;\n sessionId: string;\n escalated?: boolean;\n}\n\ninterface UseChatReturn {\n /** All conversation turns so far */\n turns: Turn[];\n /** True while an AI response is in flight */\n loading: boolean;\n /** Partial token stream content during SSE streaming */\n streaming: string;\n /** Current session ID (null until first message) */\n sessionId: string | null;\n /** True once the session has been escalated to a human */\n isEscalated: boolean;\n /** Send a message. Routes to live agent if session is escalated. */\n send: (message: string) => Promise<void>;\n /** Manually trigger escalation to a human agent */\n escalate: (reason?: string) => Promise<void>;\n /** Post a thumbs-up/down reaction for a turn by index */\n react: (turnIndex: number, reaction: \"helpful\" | \"unhelpful\") => Promise<void>;\n /** Push page context to the active session (URL, title, content summary, etc.) */\n setPageContext: (ctx: Record<string, unknown>) => Promise<void>;\n /** Clear all turns and start fresh */\n reset: () => void;\n}\n\nexport function useChat(): UseChatReturn {\n const {\n apiBase,\n getToken,\n turns,\n setTurns,\n loading,\n setLoading,\n streaming,\n setStreaming,\n sessionId,\n liveEscalationId,\n setLiveEscalationId,\n } = usePanaceaContext();\n\n const send = useCallback(\n async (message: string) => {\n // While escalated, route to the live customer-message endpoint\n if (liveEscalationId) {\n setTurns((prev) => [...prev, { role: \"user\", content: message }]);\n try {\n const token = await getToken();\n await fetch(`${apiBase}/api/v1/inbox/${liveEscalationId}/customer-message`, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n Authorization: `Bearer ${token}`,\n },\n body: JSON.stringify({ content: message }),\n });\n } catch {\n // Message shown optimistically — non-critical\n }\n return;\n }\n\n setLoading(true);\n setStreaming(\"\");\n setTurns((prev) => [...prev, { role: \"user\", content: message }]);\n\n try {\n const token = await getToken();\n const res = await fetch(`${apiBase}/api/v1/query`, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n Authorization: `Bearer ${token}`,\n Accept: \"text/event-stream\",\n },\n body: JSON.stringify({\n question: message,\n sessionId: sessionId.current,\n }),\n });\n\n if (!res.ok || !res.body) {\n throw new Error(`Query failed: ${res.status}`);\n }\n\n // SSE streaming\n const reader = res.body.getReader();\n const decoder = new TextDecoder();\n let buffer = \"\";\n let finalResponse: QueryResponse | null = null;\n\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n buffer += decoder.decode(value, { stream: true });\n const lines = buffer.split(\"\\n\");\n buffer = lines.pop() ?? \"\";\n\n for (const line of lines) {\n if (!line.startsWith(\"data: \")) continue;\n const raw = line.slice(6).trim();\n if (!raw || raw === \"[DONE]\") continue;\n try {\n const frame = JSON.parse(raw) as {\n type: \"token\" | \"done\" | \"error\";\n delta?: string;\n answer?: string;\n sources?: Source[];\n confidence?: number;\n sessionId?: string;\n flaggedForReview?: boolean;\n escalated?: boolean;\n message?: string;\n };\n if (frame.type === \"token\" && frame.delta) {\n setStreaming((s) => s + frame.delta);\n } else if (frame.type === \"done\") {\n finalResponse = {\n answer: frame.answer ?? \"\",\n sources: frame.sources ?? [],\n confidence: frame.confidence ?? 0,\n flaggedForReview: frame.flaggedForReview ?? false,\n sessionId: frame.sessionId ?? \"\",\n escalated: frame.escalated,\n };\n } else if (frame.type === \"error\") {\n throw new Error(frame.message ?? \"Stream error\");\n }\n } catch {\n // Ignore malformed frames\n }\n }\n }\n\n if (!finalResponse) throw new Error(\"Stream ended without done frame\");\n\n sessionId.current = finalResponse.sessionId;\n\n setTurns((prev) => [\n ...prev,\n {\n role: \"assistant\",\n content: finalResponse!.answer,\n confidence: finalResponse!.confidence,\n sources: finalResponse!.sources,\n flaggedForReview: finalResponse!.flaggedForReview,\n reaction: null,\n escalated: finalResponse!.escalated,\n },\n ]);\n } catch (err) {\n setTurns((prev) => [\n ...prev,\n {\n role: \"assistant\",\n content:\n err instanceof Error\n ? `Something went wrong: ${err.message}`\n : \"Something went wrong. Please try again.\",\n },\n ]);\n } finally {\n setLoading(false);\n setStreaming(\"\");\n }\n },\n [apiBase, getToken, liveEscalationId, sessionId, setLoading, setStreaming, setTurns],\n );\n\n const escalate = useCallback(\n async (reason = \"Customer requested human support\") => {\n if (!sessionId.current) return;\n try {\n const token = await getToken();\n const res = await fetch(`${apiBase}/api/v1/sessions/${sessionId.current}/escalate`, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n Authorization: `Bearer ${token}`,\n },\n body: JSON.stringify({ reason }),\n });\n if (res.ok) {\n const data = (await res.json()) as {\n data?: { escalationId?: string };\n escalationId?: string;\n };\n const id = data?.data?.escalationId ?? data?.escalationId;\n if (id) setLiveEscalationId(id);\n }\n } catch {\n // Non-critical\n }\n },\n [apiBase, getToken, sessionId, setLiveEscalationId],\n );\n\n const react = useCallback(\n async (turnIndex: number, reaction: \"helpful\" | \"unhelpful\") => {\n if (!sessionId.current) return;\n setTurns((prev) => prev.map((t, i) => (i === turnIndex ? { ...t, reaction } : t)));\n try {\n const token = await getToken();\n await fetch(`${apiBase}/api/v1/sessions/${sessionId.current}/reaction`, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n Authorization: `Bearer ${token}`,\n },\n body: JSON.stringify({ reaction, turnIndex }),\n });\n } catch {\n // Non-critical\n }\n },\n [apiBase, getToken, sessionId, setTurns],\n );\n\n const reset = useCallback(() => {\n setTurns([]);\n setStreaming(\"\");\n sessionId.current = null;\n }, [sessionId, setStreaming, setTurns]);\n\n const setPageContext = useCallback(\n async (ctx: Record<string, unknown>) => {\n if (!sessionId.current) return;\n try {\n const token = await getToken();\n await fetch(`${apiBase}/api/v1/sessions/${sessionId.current}`, {\n method: \"PATCH\",\n headers: {\n \"Content-Type\": \"application/json\",\n Authorization: `Bearer ${token}`,\n },\n body: JSON.stringify({ pageContext: ctx }),\n });\n } catch {\n // Non-critical\n }\n },\n [apiBase, getToken, sessionId],\n );\n\n return {\n turns,\n loading,\n streaming,\n sessionId: sessionId.current,\n isEscalated: !!liveEscalationId,\n send,\n escalate,\n react,\n setPageContext,\n reset,\n };\n}\n","\"use client\";\n\nimport { useCallback, useEffect, useRef } from \"react\";\nimport { usePanaceaContext } from \"../provider\";\nimport type { LiveMessage } from \"../types\";\n\ninterface UseLiveSessionReturn {\n /** True once the session has been escalated */\n isLive: boolean;\n /** The active escalation ID, or null */\n escalationId: string | null;\n /** All messages exchanged since escalation (agent + customer) */\n liveMessages: LiveMessage[];\n /** Agent-only messages (for display in widget — customer messages shown optimistically) */\n agentMessages: LiveMessage[];\n /** Send a customer message to the live agent */\n sendMessage: (content: string) => Promise<void>;\n}\n\nexport function useLiveSession(): UseLiveSessionReturn {\n const { apiBase, getToken, liveEscalationId, liveMessages, setLiveMessages } =\n usePanaceaContext();\n\n const seenIds = useRef<Set<string>>(new Set());\n\n // Poll for new messages every 3s while escalated\n useEffect(() => {\n if (!liveEscalationId) return;\n\n const poll = async () => {\n try {\n const token = await getToken();\n const res = await fetch(`${apiBase}/api/v1/inbox/${liveEscalationId}/messages`, {\n headers: { Authorization: `Bearer ${token}` },\n });\n if (!res.ok) return;\n\n const data = (await res.json()) as {\n data?: { messages?: LiveMessage[] };\n messages?: LiveMessage[];\n };\n const all: LiveMessage[] = data?.data?.messages ?? data?.messages ?? [];\n\n // Only add messages we haven't seen yet\n const newMsgs = all.filter((m) => !seenIds.current.has(m.id));\n if (newMsgs.length > 0) {\n newMsgs.forEach((m) => seenIds.current.add(m.id));\n setLiveMessages((prev) => [...prev, ...newMsgs]);\n }\n } catch {\n // Non-critical\n }\n };\n\n poll();\n const id = setInterval(poll, 3_000);\n return () => clearInterval(id);\n }, [liveEscalationId, apiBase, getToken, setLiveMessages]);\n\n const sendMessage = useCallback(\n async (content: string) => {\n if (!liveEscalationId) return;\n try {\n const token = await getToken();\n await fetch(`${apiBase}/api/v1/inbox/${liveEscalationId}/customer-message`, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n Authorization: `Bearer ${token}`,\n },\n body: JSON.stringify({ content }),\n });\n } catch {\n // Non-critical — message shown optimistically by the caller\n }\n },\n [liveEscalationId, apiBase, getToken],\n );\n\n return {\n isLive: !!liveEscalationId,\n escalationId: liveEscalationId,\n liveMessages,\n agentMessages: liveMessages.filter((m) => m.senderRole === \"agent\"),\n sendMessage,\n };\n}\n","\"use client\";\n\nimport { useCallback } from \"react\";\nimport { usePanaceaContext } from \"../provider\";\n\ninterface UseWidgetReturn {\n isOpen: boolean;\n open: () => void;\n close: () => void;\n toggle: () => void;\n}\n\nexport function useWidget(): UseWidgetReturn {\n const { isOpen, setIsOpen } = usePanaceaContext();\n\n const open = useCallback(() => setIsOpen(true), [setIsOpen]);\n const close = useCallback(() => setIsOpen(false), [setIsOpen]);\n const toggle = useCallback(() => setIsOpen((v) => !v), [setIsOpen]);\n\n return { isOpen, open, close, toggle };\n}\n","import { clsx, type ClassValue } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\nexport function cn(...inputs: ClassValue[]) {\n return twMerge(clsx(inputs));\n}\n","\"use client\";\n\nimport React, { useEffect, useRef } from \"react\";\nimport { cva, type VariantProps } from \"class-variance-authority\";\nimport { cn } from \"../lib/utils\";\nimport { useChat } from \"../hooks/useChat\";\nimport { useLiveSession } from \"../hooks/useLiveSession\";\nimport { useWidget } from \"../hooks/useWidget\";\nimport { usePanaceaContext } from \"../provider\";\nimport type { Turn } from \"../types\";\n\n// ---------------------------------------------------------------------------\n// Button (shadcn pattern)\n// ---------------------------------------------------------------------------\n\nconst buttonVariants = cva(\n \"inline-flex items-center justify-center gap-1.5 rounded-lg text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 disabled:pointer-events-none disabled:opacity-50\",\n {\n variants: {\n variant: {\n default: \"bg-primary text-primary-foreground hover:bg-primary/90\",\n outline: \"border border-input bg-background hover:bg-accent hover:text-accent-foreground\",\n ghost: \"hover:bg-accent hover:text-accent-foreground\",\n },\n size: {\n default: \"h-9 px-4 py-2\",\n sm: \"h-8 px-3 text-xs\",\n icon: \"size-9\",\n },\n },\n defaultVariants: { variant: \"default\", size: \"default\" },\n },\n);\n\ninterface ButtonProps\n extends React.ButtonHTMLAttributes<HTMLButtonElement>, VariantProps<typeof buttonVariants> {}\n\nfunction Button({ className, variant, size, ...props }: ButtonProps) {\n return <button className={cn(buttonVariants({ variant, size }), className)} {...props} />;\n}\n\n// ---------------------------------------------------------------------------\n// FAB\n// ---------------------------------------------------------------------------\n\nexport function PanaceaFAB({ className }: { className?: string }) {\n const { toggle } = useWidget();\n return (\n <button\n aria-label=\"Open support chat\"\n onClick={toggle}\n className={cn(\n \"fixed bottom-6 right-6 z-[2147483647] flex size-14 items-center justify-center rounded-full bg-primary text-2xl text-primary-foreground shadow-lg transition-transform hover:scale-105\",\n className,\n )}\n >\n 💬\n </button>\n );\n}\n\n// ---------------------------------------------------------------------------\n// Message bubble\n// ---------------------------------------------------------------------------\n\n/**\n * Parse [[Label|wiki/path]] or [[wiki/path]] citations from agent answers\n * and render them as styled inline spans (or links when sourceUrl is known).\n * Falls back to plain text for malformed tokens.\n */\nfunction renderContent(text: string): React.ReactNode[] {\n const parts = text.split(/(\\[\\[[^\\]]+\\]\\])/g);\n return parts.map((part, i) => {\n const m = part.match(/^\\[\\[(?:([^|\\]]+)\\|)?([^\\]]+)\\]\\]$/);\n if (m) {\n const label = (m[1] ?? m[2] ?? part).trim();\n return (\n <span\n key={i}\n className=\"inline-flex items-center gap-0.5 rounded bg-blue-50 px-1 py-0.5 text-xs font-medium text-blue-700\"\n >\n <svg className=\"inline size-3 shrink-0\" viewBox=\"0 0 16 16\" fill=\"currentColor\">\n <path d=\"M2 2h5v2H4v8h8v-3h2v5H2V2zm7 0h5v5h-2V4.414L6.707 9.707 5.293 8.293 10.586 3H9V2z\" />\n </svg>\n {label}\n </span>\n );\n }\n if (!part) return null;\n return <span key={i}>{part}</span>;\n }).filter(Boolean) as React.ReactNode[];\n}\n\nfunction Bubble({ turn }: { turn: Turn }) {\n const isUser = turn.role === \"user\";\n const isAgent = turn.isLiveAgent;\n return (\n <div className={cn(\"mb-3 flex flex-col\", isUser ? \"items-end\" : \"items-start\")}>\n {isAgent && (\n <span className=\"mb-1 text-[10px] font-bold uppercase tracking-wide text-blue-600\">\n Agent\n </span>\n )}\n <div\n className={cn(\n \"max-w-[82%] rounded-2xl px-3.5 py-2.5 text-sm leading-relaxed\",\n isUser\n ? \"rounded-tr-sm bg-primary text-primary-foreground\"\n : isAgent\n ? \"rounded-tl-sm bg-blue-100 text-blue-900\"\n : \"rounded-tl-sm bg-muted text-foreground\",\n )}\n >\n {isUser ? turn.content : renderContent(turn.content)}\n </div>\n </div>\n );\n}\n\nfunction TypingDots() {\n return (\n <div className=\"mb-3 flex items-start\">\n <div className=\"flex gap-1 rounded-2xl rounded-tl-sm bg-muted px-3.5 py-3\">\n {[0, 1, 2].map((i) => (\n <span\n key={i}\n className=\"size-1.5 animate-bounce rounded-full bg-muted-foreground/50\"\n style={{ animationDelay: `${i * 0.15}s` }}\n />\n ))}\n </div>\n </div>\n );\n}\n\n// ---------------------------------------------------------------------------\n// PanaceaMessages\n// ---------------------------------------------------------------------------\n\nexport function PanaceaMessages({ className }: { className?: string }) {\n const { turns, loading, streaming } = useChat();\n const { agentMessages } = useLiveSession();\n const bottomRef = useRef<HTMLDivElement>(null);\n\n const agentTurns: Turn[] = agentMessages.map((m) => ({\n role: \"assistant\",\n content: m.content,\n isLiveAgent: true,\n }));\n const allTurns = [...turns, ...agentTurns];\n\n useEffect(() => {\n bottomRef.current?.scrollIntoView({ behavior: \"smooth\" });\n }, [allTurns.length]);\n\n return (\n <div className={cn(\"flex flex-1 flex-col overflow-y-auto p-4\", className)}>\n {allTurns.map((turn, i) => (\n <Bubble key={i} turn={turn} />\n ))}\n {loading && !streaming && <TypingDots />}\n {streaming && <Bubble turn={{ role: \"assistant\", content: streaming }} />}\n <div ref={bottomRef} />\n </div>\n );\n}\n\n// ---------------------------------------------------------------------------\n// PanaceaInput\n// ---------------------------------------------------------------------------\n\nexport function PanaceaInput({\n placeholder,\n className,\n}: {\n placeholder?: string;\n className?: string;\n}) {\n const { send, loading, isEscalated } = useChat();\n const inputRef = useRef<HTMLInputElement>(null);\n\n const handleSend = () => {\n const val = inputRef.current?.value.trim();\n if (!val || loading) return;\n void send(val);\n if (inputRef.current) inputRef.current.value = \"\";\n };\n\n return (\n <div className={cn(\"flex gap-2 border-t border-border bg-background p-3\", className)}>\n <input\n ref={inputRef}\n placeholder={isEscalated ? \"Reply to agent…\" : (placeholder ?? \"Ask a question…\")}\n disabled={loading}\n onKeyDown={(e) => e.key === \"Enter\" && handleSend()}\n className=\"flex-1 rounded-full border border-input bg-muted/40 px-4 py-2 text-sm outline-none placeholder:text-muted-foreground focus:border-primary focus:bg-background disabled:opacity-50\"\n />\n <Button\n onClick={handleSend}\n disabled={loading}\n size=\"sm\"\n className=\"shrink-0 rounded-full px-4\"\n >\n Send\n </Button>\n </div>\n );\n}\n\n// ---------------------------------------------------------------------------\n// PanaceaChat — full pre-built floating panel\n// ---------------------------------------------------------------------------\n\nexport function PanaceaChat({\n title,\n placeholder,\n className,\n}: {\n title?: string;\n placeholder?: string;\n className?: string;\n}) {\n const { config } = usePanaceaContext();\n const { isOpen, close } = useWidget();\n const panelTitle = title ?? config.persona?.name ?? \"Support\";\n\n return (\n <>\n <PanaceaFAB />\n <div\n className={cn(\n \"fixed bottom-24 right-6 z-[2147483646] flex w-[360px] flex-col overflow-hidden rounded-2xl border border-border bg-background shadow-2xl transition-all duration-200\",\n isOpen\n ? \"pointer-events-auto h-[520px] opacity-100\"\n : \"pointer-events-none h-0 opacity-0\",\n className,\n )}\n >\n {/* Header */}\n <div className=\"flex shrink-0 items-center justify-between bg-primary px-4 py-3.5\">\n <span className=\"text-sm font-semibold text-primary-foreground\">{panelTitle}</span>\n <button\n onClick={close}\n aria-label=\"Close\"\n className=\"text-primary-foreground/70 transition-colors hover:text-primary-foreground\"\n >\n ✕\n </button>\n </div>\n\n <PanaceaMessages />\n <PanaceaInput placeholder={placeholder} />\n </div>\n </>\n );\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/token.ts","../src/provider.tsx","../src/hooks/useChat.ts","../src/hooks/useLiveSession.ts","../src/hooks/useWidget.ts","../src/hooks/useSessionHistory.ts","../src/lib/utils.ts","../src/components/index.tsx","../src/components/PanaceaHistory.tsx"],"names":["useRef","useEffect","useCallback","useState","jsx","jsxs","Fragment"],"mappings":"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","file":"index.js","sourcesContent":["import type { PanaceaConfig } from \"./types\";\n\ninterface TokenState {\n token: string;\n /** unix ms */\n expiresAt: number;\n}\n\n/**\n * Manages the short-lived widget JWT (15 min TTL).\n * Auto-refreshes 60s before expiry. Concurrent callers share one refresh promise.\n */\nexport class TokenManager {\n private state: TokenState | null = null;\n private refreshPromise: Promise<string> | null = null;\n\n constructor(\n private readonly config: PanaceaConfig,\n private readonly apiBase: string,\n ) {}\n\n async getToken(): Promise<string> {\n if (!this.state || Date.now() >= this.state.expiresAt - 60_000) {\n if (!this.refreshPromise) {\n this.refreshPromise = this.refresh().finally(() => {\n this.refreshPromise = null;\n });\n }\n return this.refreshPromise;\n }\n return this.state.token;\n }\n\n private async refresh(): Promise<string> {\n const res = await fetch(`${this.apiBase}/api/v1/auth/widget-token`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ tenantId: this.config.tenantId }),\n });\n\n if (!res.ok) {\n throw new Error(`Panacea: token refresh failed (${res.status})`);\n }\n\n const data = (await res.json()) as { token: string; expiresAt: string };\n this.state = {\n token: data.token,\n expiresAt: new Date(data.expiresAt).getTime(),\n };\n return this.state.token;\n }\n}\n","\"use client\";\n\nimport React, { createContext, useContext, useEffect, useMemo, useRef, useState } from \"react\";\nimport type { LiveMessage, PanaceaConfig, PanaceaContextValue, Turn } from \"./types\";\nimport { TokenManager } from \"./token\";\n\n// ---------------------------------------------------------------------------\n// Context\n// ---------------------------------------------------------------------------\n\nconst PanaceaContext = createContext<PanaceaContextValue | null>(null);\n\nexport function usePanaceaContext(): PanaceaContextValue {\n const ctx = useContext(PanaceaContext);\n if (!ctx) {\n throw new Error(\n \"usePanaceaContext must be used inside <PanaceaProvider>. \" +\n 'Wrap your component tree with <PanaceaProvider tenantId=\"...\">.',\n );\n }\n return ctx;\n}\n\n// ---------------------------------------------------------------------------\n// Provider\n// ---------------------------------------------------------------------------\n\ninterface PanaceaProviderProps {\n children: React.ReactNode;\n tenantId: string;\n apiBase?: string;\n customerToken?: string;\n escalationKeywords?: string[];\n persona?: PanaceaConfig[\"persona\"];\n}\n\nexport function PanaceaProvider({\n children,\n tenantId,\n apiBase: apiBaseProp,\n customerToken,\n escalationKeywords,\n persona,\n}: PanaceaProviderProps) {\n const apiBase = apiBaseProp ?? (typeof window !== \"undefined\" ? window.location.origin : \"\");\n\n const config: PanaceaConfig = useMemo(\n () => ({ tenantId, apiBase, customerToken, escalationKeywords, persona }),\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [tenantId, apiBase, customerToken],\n );\n\n // Stable token manager instance across re-renders\n const tokenMgr = useMemo(\n () => new TokenManager(config, apiBase),\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [tenantId, apiBase],\n );\n\n // AI conversation\n const [turns, setTurns] = useState<Turn[]>([]);\n const [loading, setLoading] = useState(false);\n const [streaming, setStreaming] = useState(\"\");\n const sessionId = useRef<string | null>(null);\n\n // Live handover\n const [liveEscalationId, setLiveEscalationId] = useState<string | null>(null);\n const [liveMessages, setLiveMessages] = useState<LiveMessage[]>([]);\n\n // Panel\n const [isOpen, setIsOpen] = useState(false);\n\n // Session resume: on mount (or when customerToken changes), attempt to\n // restore the most recent resumable session for this identified customer.\n useEffect(() => {\n if (!customerToken) return;\n let cancelled = false;\n\n async function tryResume() {\n try {\n const token = await tokenMgr.getToken();\n const url = new URL(`${apiBase}/api/v1/sessions/resume`);\n url.searchParams.set(\"customerToken\", customerToken!);\n const res = await fetch(url.toString(), {\n headers: { Authorization: `Bearer ${token}` },\n });\n if (!res.ok || cancelled) return;\n const data = (await res.json()) as { session: { sessionId: string } | null };\n const resumedId = data?.session?.sessionId ?? null;\n if (!resumedId || cancelled) return;\n\n sessionId.current = resumedId;\n\n // Hydrate turns from history\n const turnsRes = await fetch(`${apiBase}/api/v1/sessions/${resumedId}/turns`, {\n headers: { Authorization: `Bearer ${token}` },\n });\n if (!turnsRes.ok || cancelled) return;\n const turnsData = (await turnsRes.json()) as {\n data?: { turns?: Array<{ query: string; response: string }> };\n turns?: Array<{ query: string; response: string }>;\n };\n const rawTurns = turnsData?.data?.turns ?? turnsData?.turns ?? [];\n if (cancelled) return;\n const hydrated: Turn[] = rawTurns.flatMap((t) => [\n { role: \"user\" as const, content: t.query },\n { role: \"assistant\" as const, content: t.response },\n ]);\n if (hydrated.length > 0) setTurns(hydrated);\n } catch {\n // Resume is best-effort — silent fail\n }\n }\n\n void tryResume();\n return () => {\n cancelled = true;\n };\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [customerToken, apiBase]);\n\n const value: PanaceaContextValue = useMemo(\n () => ({\n config,\n apiBase,\n getToken: () => tokenMgr.getToken(),\n turns,\n setTurns,\n loading,\n setLoading,\n streaming,\n setStreaming,\n sessionId,\n liveEscalationId,\n setLiveEscalationId,\n liveMessages,\n setLiveMessages,\n isOpen,\n setIsOpen,\n }),\n [config, apiBase, tokenMgr, turns, loading, streaming, liveEscalationId, liveMessages, isOpen],\n );\n\n return <PanaceaContext.Provider value={value}>{children}</PanaceaContext.Provider>;\n}\n","\"use client\";\n\nimport { useCallback } from \"react\";\nimport { usePanaceaContext } from \"../provider\";\nimport type { Source, Turn } from \"../types\";\n\ninterface QueryResponse {\n answer: string;\n sources: Source[];\n confidence: number;\n flaggedForReview: boolean;\n sessionId: string;\n escalated?: boolean;\n}\n\ninterface UseChatReturn {\n /** All conversation turns so far */\n turns: Turn[];\n /** True while an AI response is in flight */\n loading: boolean;\n /** Partial token stream content during SSE streaming */\n streaming: string;\n /** Current session ID (null until first message) */\n sessionId: string | null;\n /** True once the session has been escalated to a human */\n isEscalated: boolean;\n /** Send a message. Routes to live agent if session is escalated. */\n send: (message: string) => Promise<void>;\n /** Manually trigger escalation to a human agent */\n escalate: (reason?: string) => Promise<void>;\n /** Post a thumbs-up/down reaction for a turn by index */\n react: (turnIndex: number, reaction: \"helpful\" | \"unhelpful\") => Promise<void>;\n /** Push page context to the active session (URL, title, content summary, etc.) */\n setPageContext: (ctx: Record<string, unknown>) => Promise<void>;\n /** Clear all turns and start fresh */\n reset: () => void;\n}\n\nexport function useChat(): UseChatReturn {\n const {\n apiBase,\n getToken,\n turns,\n setTurns,\n loading,\n setLoading,\n streaming,\n setStreaming,\n sessionId,\n liveEscalationId,\n setLiveEscalationId,\n } = usePanaceaContext();\n\n const send = useCallback(\n async (message: string) => {\n // While escalated, route to the live customer-message endpoint\n if (liveEscalationId) {\n setTurns((prev) => [...prev, { role: \"user\", content: message }]);\n try {\n const token = await getToken();\n await fetch(`${apiBase}/api/v1/inbox/${liveEscalationId}/customer-message`, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n Authorization: `Bearer ${token}`,\n },\n body: JSON.stringify({ content: message }),\n });\n } catch {\n // Message shown optimistically — non-critical\n }\n return;\n }\n\n setLoading(true);\n setStreaming(\"\");\n setTurns((prev) => [...prev, { role: \"user\", content: message }]);\n\n try {\n const token = await getToken();\n const res = await fetch(`${apiBase}/api/v1/query`, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n Authorization: `Bearer ${token}`,\n Accept: \"text/event-stream\",\n },\n body: JSON.stringify({\n question: message,\n sessionId: sessionId.current,\n }),\n });\n\n if (!res.ok || !res.body) {\n throw new Error(`Query failed: ${res.status}`);\n }\n\n // SSE streaming\n const reader = res.body.getReader();\n const decoder = new TextDecoder();\n let buffer = \"\";\n let finalResponse: QueryResponse | null = null;\n\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n buffer += decoder.decode(value, { stream: true });\n const lines = buffer.split(\"\\n\");\n buffer = lines.pop() ?? \"\";\n\n for (const line of lines) {\n if (!line.startsWith(\"data: \")) continue;\n const raw = line.slice(6).trim();\n if (!raw || raw === \"[DONE]\") continue;\n try {\n const frame = JSON.parse(raw) as {\n type: \"token\" | \"done\" | \"error\";\n delta?: string;\n answer?: string;\n sources?: Source[];\n confidence?: number;\n sessionId?: string;\n flaggedForReview?: boolean;\n escalated?: boolean;\n message?: string;\n };\n if (frame.type === \"token\" && frame.delta) {\n setStreaming((s) => s + frame.delta);\n } else if (frame.type === \"done\") {\n finalResponse = {\n answer: frame.answer ?? \"\",\n sources: frame.sources ?? [],\n confidence: frame.confidence ?? 0,\n flaggedForReview: frame.flaggedForReview ?? false,\n sessionId: frame.sessionId ?? \"\",\n escalated: frame.escalated,\n };\n } else if (frame.type === \"error\") {\n throw new Error(frame.message ?? \"Stream error\");\n }\n } catch {\n // Ignore malformed frames\n }\n }\n }\n\n if (!finalResponse) throw new Error(\"Stream ended without done frame\");\n\n sessionId.current = finalResponse.sessionId;\n\n setTurns((prev) => [\n ...prev,\n {\n role: \"assistant\",\n content: finalResponse!.answer,\n confidence: finalResponse!.confidence,\n sources: finalResponse!.sources,\n flaggedForReview: finalResponse!.flaggedForReview,\n reaction: null,\n escalated: finalResponse!.escalated,\n },\n ]);\n } catch (err) {\n setTurns((prev) => [\n ...prev,\n {\n role: \"assistant\",\n content:\n err instanceof Error\n ? `Something went wrong: ${err.message}`\n : \"Something went wrong. Please try again.\",\n },\n ]);\n } finally {\n setLoading(false);\n setStreaming(\"\");\n }\n },\n [apiBase, getToken, liveEscalationId, sessionId, setLoading, setStreaming, setTurns],\n );\n\n const escalate = useCallback(\n async (reason = \"Customer requested human support\") => {\n if (!sessionId.current) return;\n try {\n const token = await getToken();\n const res = await fetch(`${apiBase}/api/v1/sessions/${sessionId.current}/escalate`, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n Authorization: `Bearer ${token}`,\n },\n body: JSON.stringify({ reason }),\n });\n if (res.ok) {\n const data = (await res.json()) as {\n data?: { escalationId?: string };\n escalationId?: string;\n };\n const id = data?.data?.escalationId ?? data?.escalationId;\n if (id) setLiveEscalationId(id);\n }\n } catch {\n // Non-critical\n }\n },\n [apiBase, getToken, sessionId, setLiveEscalationId],\n );\n\n const react = useCallback(\n async (turnIndex: number, reaction: \"helpful\" | \"unhelpful\") => {\n if (!sessionId.current) return;\n setTurns((prev) => prev.map((t, i) => (i === turnIndex ? { ...t, reaction } : t)));\n try {\n const token = await getToken();\n await fetch(`${apiBase}/api/v1/sessions/${sessionId.current}/reaction`, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n Authorization: `Bearer ${token}`,\n },\n body: JSON.stringify({ reaction, turnIndex }),\n });\n } catch {\n // Non-critical\n }\n },\n [apiBase, getToken, sessionId, setTurns],\n );\n\n const reset = useCallback(() => {\n setTurns([]);\n setStreaming(\"\");\n sessionId.current = null;\n }, [sessionId, setStreaming, setTurns]);\n\n const setPageContext = useCallback(\n async (ctx: Record<string, unknown>) => {\n if (!sessionId.current) return;\n try {\n const token = await getToken();\n await fetch(`${apiBase}/api/v1/sessions/${sessionId.current}`, {\n method: \"PATCH\",\n headers: {\n \"Content-Type\": \"application/json\",\n Authorization: `Bearer ${token}`,\n },\n body: JSON.stringify({ pageContext: ctx }),\n });\n } catch {\n // Non-critical\n }\n },\n [apiBase, getToken, sessionId],\n );\n\n return {\n turns,\n loading,\n streaming,\n sessionId: sessionId.current,\n isEscalated: !!liveEscalationId,\n send,\n escalate,\n react,\n setPageContext,\n reset,\n };\n}\n","\"use client\";\n\nimport { useCallback, useEffect, useRef } from \"react\";\nimport { usePanaceaContext } from \"../provider\";\nimport type { LiveMessage } from \"../types\";\n\ninterface UseLiveSessionReturn {\n /** True once the session has been escalated */\n isLive: boolean;\n /** The active escalation ID, or null */\n escalationId: string | null;\n /** All messages exchanged since escalation (agent + customer) */\n liveMessages: LiveMessage[];\n /** Agent-only messages (for display in widget — customer messages shown optimistically) */\n agentMessages: LiveMessage[];\n /** Send a customer message to the live agent */\n sendMessage: (content: string) => Promise<void>;\n}\n\nexport function useLiveSession(): UseLiveSessionReturn {\n const { apiBase, getToken, liveEscalationId, liveMessages, setLiveMessages } =\n usePanaceaContext();\n\n const seenIds = useRef<Set<string>>(new Set());\n\n // Poll for new messages every 3s while escalated\n useEffect(() => {\n if (!liveEscalationId) return;\n\n const poll = async () => {\n try {\n const token = await getToken();\n const res = await fetch(`${apiBase}/api/v1/inbox/${liveEscalationId}/messages`, {\n headers: { Authorization: `Bearer ${token}` },\n });\n if (!res.ok) return;\n\n const data = (await res.json()) as {\n data?: { messages?: LiveMessage[] };\n messages?: LiveMessage[];\n };\n const all: LiveMessage[] = data?.data?.messages ?? data?.messages ?? [];\n\n // Only add messages we haven't seen yet\n const newMsgs = all.filter((m) => !seenIds.current.has(m.id));\n if (newMsgs.length > 0) {\n newMsgs.forEach((m) => seenIds.current.add(m.id));\n setLiveMessages((prev) => [...prev, ...newMsgs]);\n }\n } catch {\n // Non-critical\n }\n };\n\n poll();\n const id = setInterval(poll, 3_000);\n return () => clearInterval(id);\n }, [liveEscalationId, apiBase, getToken, setLiveMessages]);\n\n const sendMessage = useCallback(\n async (content: string) => {\n if (!liveEscalationId) return;\n try {\n const token = await getToken();\n await fetch(`${apiBase}/api/v1/inbox/${liveEscalationId}/customer-message`, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n Authorization: `Bearer ${token}`,\n },\n body: JSON.stringify({ content }),\n });\n } catch {\n // Non-critical — message shown optimistically by the caller\n }\n },\n [liveEscalationId, apiBase, getToken],\n );\n\n return {\n isLive: !!liveEscalationId,\n escalationId: liveEscalationId,\n liveMessages,\n agentMessages: liveMessages.filter((m) => m.senderRole === \"agent\"),\n sendMessage,\n };\n}\n","\"use client\";\n\nimport { useCallback } from \"react\";\nimport { usePanaceaContext } from \"../provider\";\n\ninterface UseWidgetReturn {\n isOpen: boolean;\n open: () => void;\n close: () => void;\n toggle: () => void;\n}\n\nexport function useWidget(): UseWidgetReturn {\n const { isOpen, setIsOpen } = usePanaceaContext();\n\n const open = useCallback(() => setIsOpen(true), [setIsOpen]);\n const close = useCallback(() => setIsOpen(false), [setIsOpen]);\n const toggle = useCallback(() => setIsOpen((v) => !v), [setIsOpen]);\n\n return { isOpen, open, close, toggle };\n}\n","\"use client\";\n\nimport { useCallback, useEffect, useState } from \"react\";\nimport { usePanaceaContext } from \"../provider\";\nimport type { HistorySession, HistoryTurn, Turn } from \"../types\";\n\ninterface UseSessionHistoryReturn {\n /** List of past sessions for this customer */\n sessions: HistorySession[];\n /** True while fetching the session list */\n loading: boolean;\n /** Load and display a specific past session's turns in the active chat */\n loadSession: (sessionId: string) => Promise<void>;\n /** Refetch the session list */\n refresh: () => Promise<void>;\n}\n\nexport function useSessionHistory(): UseSessionHistoryReturn {\n const { apiBase, getToken, config, setTurns, sessionId: activeSessionIdRef } = usePanaceaContext();\n\n const [sessions, setSessions] = useState<HistorySession[]>([]);\n const [loading, setLoading] = useState(false);\n\n const fetchSessions = useCallback(async () => {\n if (!config.customerToken) return;\n setLoading(true);\n try {\n const token = await getToken();\n const url = new URL(`${apiBase}/api/v1/sessions`);\n url.searchParams.set(\"customerToken\", config.customerToken);\n const res = await fetch(url.toString(), {\n headers: { Authorization: `Bearer ${token}` },\n });\n if (!res.ok) return;\n const data = (await res.json()) as {\n data?: HistorySession[];\n sessions?: HistorySession[];\n } | HistorySession[];\n const list = Array.isArray(data)\n ? data\n : (data as { data?: HistorySession[]; sessions?: HistorySession[] })?.data ??\n (data as { sessions?: HistorySession[] })?.sessions ??\n [];\n setSessions(list);\n } catch {\n // silent\n } finally {\n setLoading(false);\n }\n }, [apiBase, getToken, config.customerToken]);\n\n useEffect(() => {\n // eslint-disable-next-line react-hooks/set-state-in-effect\n void fetchSessions();\n }, [fetchSessions]);\n\n const loadSession = useCallback(\n async (sessionId: string) => {\n try {\n const token = await getToken();\n const res = await fetch(`${apiBase}/api/v1/sessions/${sessionId}/turns`, {\n headers: { Authorization: `Bearer ${token}` },\n });\n if (!res.ok) return;\n const data = (await res.json()) as {\n data?: { turns?: HistoryTurn[] };\n turns?: HistoryTurn[];\n };\n const raw = data?.data?.turns ?? data?.turns ?? [];\n const turns: Turn[] = raw.flatMap((t) => [\n { role: \"user\" as const, content: t.query },\n { role: \"assistant\" as const, content: t.response },\n ]);\n activeSessionIdRef.current = sessionId;\n setTurns(turns);\n } catch {\n // silent\n }\n },\n [apiBase, getToken, setTurns, activeSessionIdRef],\n );\n\n return { sessions, loading, loadSession, refresh: fetchSessions };\n}\n","import { clsx, type ClassValue } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\nexport function cn(...inputs: ClassValue[]) {\n return twMerge(clsx(inputs));\n}\n","\"use client\";\n\nimport React, { useEffect, useRef } from \"react\";\nimport { cva, type VariantProps } from \"class-variance-authority\";\nimport { cn } from \"../lib/utils\";\nimport { useChat } from \"../hooks/useChat\";\nimport { useLiveSession } from \"../hooks/useLiveSession\";\nimport { useWidget } from \"../hooks/useWidget\";\nimport { usePanaceaContext } from \"../provider\";\nimport type { Turn } from \"../types\";\n\n// ---------------------------------------------------------------------------\n// Button (shadcn pattern)\n// ---------------------------------------------------------------------------\n\nconst buttonVariants = cva(\n \"inline-flex items-center justify-center gap-1.5 rounded-lg text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 disabled:pointer-events-none disabled:opacity-50\",\n {\n variants: {\n variant: {\n default: \"bg-primary text-primary-foreground hover:bg-primary/90\",\n outline: \"border border-input bg-background hover:bg-accent hover:text-accent-foreground\",\n ghost: \"hover:bg-accent hover:text-accent-foreground\",\n },\n size: {\n default: \"h-9 px-4 py-2\",\n sm: \"h-8 px-3 text-xs\",\n icon: \"size-9\",\n },\n },\n defaultVariants: { variant: \"default\", size: \"default\" },\n },\n);\n\ninterface ButtonProps\n extends React.ButtonHTMLAttributes<HTMLButtonElement>, VariantProps<typeof buttonVariants> {}\n\nfunction Button({ className, variant, size, ...props }: ButtonProps) {\n return <button className={cn(buttonVariants({ variant, size }), className)} {...props} />;\n}\n\n// ---------------------------------------------------------------------------\n// FAB\n// ---------------------------------------------------------------------------\n\nexport function PanaceaFAB({ className }: { className?: string }) {\n const { toggle } = useWidget();\n return (\n <button\n aria-label=\"Open support chat\"\n onClick={toggle}\n className={cn(\n \"fixed bottom-6 right-6 z-[2147483647] flex size-14 items-center justify-center rounded-full bg-primary text-2xl text-primary-foreground shadow-lg transition-transform hover:scale-105\",\n className,\n )}\n >\n 💬\n </button>\n );\n}\n\n// ---------------------------------------------------------------------------\n// Message bubble\n// ---------------------------------------------------------------------------\n\n/**\n * Parse [[Label|wiki/path]] or [[wiki/path]] citations from agent answers\n * and render them as styled inline spans (or links when sourceUrl is known).\n * Falls back to plain text for malformed tokens.\n */\nfunction renderContent(text: string): React.ReactNode[] {\n const parts = text.split(/(\\[\\[[^\\]]+\\]\\])/g);\n return parts\n .map((part, i) => {\n const m = part.match(/^\\[\\[(?:([^|\\]]+)\\|)?([^\\]]+)\\]\\]$/);\n if (m) {\n const label = (m[1] ?? m[2] ?? part).trim();\n return (\n <span\n key={i}\n className=\"inline-flex items-center gap-0.5 rounded bg-blue-50 px-1 py-0.5 text-xs font-medium text-blue-700\"\n >\n <svg className=\"inline size-3 shrink-0\" viewBox=\"0 0 16 16\" fill=\"currentColor\">\n <path d=\"M2 2h5v2H4v8h8v-3h2v5H2V2zm7 0h5v5h-2V4.414L6.707 9.707 5.293 8.293 10.586 3H9V2z\" />\n </svg>\n {label}\n </span>\n );\n }\n if (!part) return null;\n return <span key={i}>{part}</span>;\n })\n .filter(Boolean) as React.ReactNode[];\n}\n\nfunction Bubble({ turn }: { turn: Turn }) {\n const isUser = turn.role === \"user\";\n const isAgent = turn.isLiveAgent;\n return (\n <div className={cn(\"mb-3 flex flex-col\", isUser ? \"items-end\" : \"items-start\")}>\n {isAgent && (\n <span className=\"mb-1 text-[10px] font-bold uppercase tracking-wide text-blue-600\">\n Agent\n </span>\n )}\n <div\n className={cn(\n \"max-w-[82%] rounded-2xl px-3.5 py-2.5 text-sm leading-relaxed\",\n isUser\n ? \"rounded-tr-sm bg-primary text-primary-foreground\"\n : isAgent\n ? \"rounded-tl-sm bg-blue-100 text-blue-900\"\n : \"rounded-tl-sm bg-muted text-foreground\",\n )}\n >\n {isUser ? turn.content : renderContent(turn.content)}\n </div>\n </div>\n );\n}\n\nfunction TypingDots() {\n return (\n <div className=\"mb-3 flex items-start\">\n <div className=\"flex gap-1 rounded-2xl rounded-tl-sm bg-muted px-3.5 py-3\">\n {[0, 1, 2].map((i) => (\n <span\n key={i}\n className=\"size-1.5 animate-bounce rounded-full bg-muted-foreground/50\"\n style={{ animationDelay: `${i * 0.15}s` }}\n />\n ))}\n </div>\n </div>\n );\n}\n\n// ---------------------------------------------------------------------------\n// PanaceaMessages\n// ---------------------------------------------------------------------------\n\nexport function PanaceaMessages({ className }: { className?: string }) {\n const { turns, loading, streaming } = useChat();\n const { agentMessages } = useLiveSession();\n const bottomRef = useRef<HTMLDivElement>(null);\n\n const agentTurns: Turn[] = agentMessages.map((m) => ({\n role: \"assistant\",\n content: m.content,\n isLiveAgent: true,\n }));\n const allTurns = [...turns, ...agentTurns];\n\n useEffect(() => {\n bottomRef.current?.scrollIntoView({ behavior: \"smooth\" });\n }, [allTurns.length]);\n\n return (\n <div className={cn(\"flex flex-1 flex-col overflow-y-auto p-4\", className)}>\n {allTurns.map((turn, i) => (\n <Bubble key={i} turn={turn} />\n ))}\n {loading && !streaming && <TypingDots />}\n {streaming && <Bubble turn={{ role: \"assistant\", content: streaming }} />}\n <div ref={bottomRef} />\n </div>\n );\n}\n\n// ---------------------------------------------------------------------------\n// PanaceaInput\n// ---------------------------------------------------------------------------\n\nexport function PanaceaInput({\n placeholder,\n className,\n}: {\n placeholder?: string;\n className?: string;\n}) {\n const { send, loading, isEscalated } = useChat();\n const inputRef = useRef<HTMLInputElement>(null);\n\n const handleSend = () => {\n const val = inputRef.current?.value.trim();\n if (!val || loading) return;\n void send(val);\n if (inputRef.current) inputRef.current.value = \"\";\n };\n\n return (\n <div className={cn(\"flex gap-2 border-t border-border bg-background p-3\", className)}>\n <input\n ref={inputRef}\n placeholder={isEscalated ? \"Reply to agent…\" : (placeholder ?? \"Ask a question…\")}\n disabled={loading}\n onKeyDown={(e) => e.key === \"Enter\" && handleSend()}\n className=\"flex-1 rounded-full border border-input bg-muted/40 px-4 py-2 text-sm outline-none placeholder:text-muted-foreground focus:border-primary focus:bg-background disabled:opacity-50\"\n />\n <Button\n onClick={handleSend}\n disabled={loading}\n size=\"sm\"\n className=\"shrink-0 rounded-full px-4\"\n >\n Send\n </Button>\n </div>\n );\n}\n\n// ---------------------------------------------------------------------------\n// PanaceaChat — full pre-built floating panel\n// ---------------------------------------------------------------------------\n\nexport function PanaceaChat({\n title,\n placeholder,\n className,\n}: {\n title?: string;\n placeholder?: string;\n className?: string;\n}) {\n const { config } = usePanaceaContext();\n const { isOpen, close } = useWidget();\n const panelTitle = title ?? config.persona?.name ?? \"Support\";\n\n return (\n <>\n <PanaceaFAB />\n <div\n className={cn(\n \"fixed bottom-24 right-6 z-[2147483646] flex w-[360px] flex-col overflow-hidden rounded-2xl border border-border bg-background shadow-2xl transition-all duration-200\",\n isOpen\n ? \"pointer-events-auto h-[520px] opacity-100\"\n : \"pointer-events-none h-0 opacity-0\",\n className,\n )}\n >\n {/* Header */}\n <div className=\"flex shrink-0 items-center justify-between bg-primary px-4 py-3.5\">\n <span className=\"text-sm font-semibold text-primary-foreground\">{panelTitle}</span>\n <button\n onClick={close}\n aria-label=\"Close\"\n className=\"text-primary-foreground/70 transition-colors hover:text-primary-foreground\"\n >\n ✕\n </button>\n </div>\n\n <PanaceaMessages />\n <PanaceaInput placeholder={placeholder} />\n </div>\n </>\n );\n}\n","\"use client\";\n\nimport React, { useState } from \"react\";\nimport { cn } from \"../lib/utils\";\nimport { useSessionHistory } from \"../hooks/useSessionHistory\";\nimport { usePanaceaContext } from \"../provider\";\nimport type { HistorySession } from \"../types\";\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\nfunction formatDate(iso: string): string {\n try {\n return new Intl.DateTimeFormat(undefined, {\n month: \"short\",\n day: \"numeric\",\n hour: \"2-digit\",\n minute: \"2-digit\",\n }).format(new Date(iso));\n } catch {\n return iso;\n }\n}\n\n// ---------------------------------------------------------------------------\n// PanaceaHistory\n// ---------------------------------------------------------------------------\n\ninterface PanaceaHistoryProps {\n /** Called when the user clicks a session row and it loads into chat */\n onSessionLoaded?: (sessionId: string) => void;\n className?: string;\n}\n\n/**\n * Renders a scrollable list of past sessions for the authenticated customer.\n * Requires `customerToken` to be set on the parent `<PanaceaProvider>`.\n * Clicking a row loads the turns into the active chat.\n */\nexport function PanaceaHistory({ onSessionLoaded, className }: PanaceaHistoryProps) {\n const { config } = usePanaceaContext();\n const { sessions, loading, loadSession } = useSessionHistory();\n const [active, setActive] = useState<string | null>(null);\n const [loadingId, setLoadingId] = useState<string | null>(null);\n\n if (!config.customerToken) {\n return (\n <div className={cn(\"flex flex-col items-center justify-center gap-2 py-8 text-center text-sm text-muted-foreground\", className)}>\n <span>Sign in to see your conversation history.</span>\n </div>\n );\n }\n\n if (loading) {\n return (\n <div className={cn(\"flex flex-col gap-2 p-3\", className)}>\n {[1, 2, 3].map((i) => (\n <div\n key={i}\n className=\"h-14 animate-pulse rounded-lg bg-muted\"\n />\n ))}\n </div>\n );\n }\n\n if (sessions.length === 0) {\n return (\n <div className={cn(\"flex flex-col items-center justify-center gap-2 py-8 text-center text-sm text-muted-foreground\", className)}>\n <span>No previous conversations found.</span>\n </div>\n );\n }\n\n async function handleLoad(session: HistorySession) {\n setLoadingId(session.sessionId);\n await loadSession(session.sessionId);\n setActive(session.sessionId);\n setLoadingId(null);\n onSessionLoaded?.(session.sessionId);\n }\n\n return (\n <div className={cn(\"flex flex-col gap-1 overflow-y-auto p-2\", className)}>\n {sessions.map((session) => {\n const isActive = active === session.sessionId;\n const isLoading = loadingId === session.sessionId;\n return (\n <button\n key={session.sessionId}\n onClick={() => void handleLoad(session)}\n disabled={isLoading}\n className={cn(\n \"flex w-full flex-col gap-0.5 rounded-lg px-3 py-2.5 text-left text-sm transition-colors hover:bg-accent disabled:cursor-wait\",\n isActive && \"bg-accent\",\n )}\n >\n <span className=\"truncate font-medium leading-snug text-foreground\">\n {session.preview ?? \"Conversation\"}\n </span>\n <div className=\"flex items-center gap-2 text-xs text-muted-foreground\">\n <span>{formatDate(session.createdAt)}</span>\n {session.turnCount !== undefined && (\n <>\n <span aria-hidden>·</span>\n <span>{session.turnCount} {session.turnCount === 1 ? \"message\" : \"messages\"}</span>\n </>\n )}\n {isLoading && (\n <>\n <span aria-hidden>·</span>\n <span>Loading…</span>\n </>\n )}\n </div>\n </button>\n );\n })}\n </div>\n );\n}\n"]}
|
package/dist/styles.css
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
/*! tailwindcss v4.3.0 | MIT License | https://tailwindcss.com */
|
|
2
|
-
@layer properties{@supports (((-webkit-hyphens:none)) and (not (margin-trim:inline))) or ((-moz-orient:inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-border-style:solid;--tw-leading:initial;--tw-font-weight:initial;--tw-tracking:initial;--tw-shadow:0 0 #0000;--tw-shadow-color:initial;--tw-shadow-alpha:100%;--tw-inset-shadow:0 0 #0000;--tw-inset-shadow-color:initial;--tw-inset-shadow-alpha:100%;--tw-ring-color:initial;--tw-ring-shadow:0 0 #0000;--tw-inset-ring-color:initial;--tw-inset-ring-shadow:0 0 #0000;--tw-ring-inset:initial;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-offset-shadow:0 0 #0000;--tw-outline-style:solid;--tw-duration:initial;--tw-scale-x:1;--tw-scale-y:1;--tw-scale-z:1}}}@layer theme{:root,:host{--font-sans:ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";--font-mono:ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;--color-blue-50:oklch(97% .014 254.604);--color-blue-100:oklch(93.2% .032 255.585);--color-blue-600:oklch(54.6% .245 262.881);--color-blue-700:oklch(48.8% .243 264.376);--color-blue-900:oklch(37.9% .146 265.522);--spacing:.25rem;--text-xs:.75rem;--text-xs--line-height:calc(1 / .75);--text-sm:.875rem;--text-sm--line-height:calc(1.25 / .875);--text-2xl:1.5rem;--text-2xl--line-height:calc(2 / 1.5);--font-weight-medium:500;--font-weight-semibold:600;--font-weight-bold:700;--tracking-wide:.025em;--leading-relaxed:1.625;--radius-sm:.25rem;--radius-lg:.5rem;--radius-2xl:1rem;--animate-bounce:bounce 1s infinite;--default-transition-duration:.15s;--default-transition-timing-function:cubic-bezier(.4, 0, .2, 1);--default-font-family:var(--font-sans);--default-mono-font-family:var(--font-mono)}}@layer base{*,:after,:before,::backdrop{box-sizing:border-box;border:0 solid;margin:0;padding:0}::file-selector-button{box-sizing:border-box;border:0 solid;margin:0;padding:0}html,:host{-webkit-text-size-adjust:100%;tab-size:4;line-height:1.5;font-family:var(--default-font-family,ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji");font-feature-settings:var(--default-font-feature-settings,normal);font-variation-settings:var(--default-font-variation-settings,normal);-webkit-tap-highlight-color:transparent}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:var(--default-mono-font-family,ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace);font-feature-settings:var(--default-mono-font-feature-settings,normal);font-variation-settings:var(--default-mono-font-variation-settings,normal);font-size:1em}small{font-size:80%}sub,sup{vertical-align:baseline;font-size:75%;line-height:0;position:relative}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}:-moz-focusring{outline:auto}progress{vertical-align:baseline}summary{display:list-item}ol,ul,menu{list-style:none}img,svg,video,canvas,audio,iframe,embed,object{vertical-align:middle;display:block}img,video{max-width:100%;height:auto}button,input,select,optgroup,textarea{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}::file-selector-button{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}:where(select:is([multiple],[size])) optgroup{font-weight:bolder}:where(select:is([multiple],[size])) optgroup option{padding-inline-start:20px}::file-selector-button{margin-inline-end:4px}::placeholder{opacity:1}@supports (not ((-webkit-appearance:-apple-pay-button))) or (contain-intrinsic-size:1px){::placeholder{color:currentColor}@supports (color:color-mix(in lab, red, red)){::placeholder{color:color-mix(in oklab, currentcolor 50%, transparent)}}}textarea{resize:vertical}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-date-and-time-value{min-height:1lh;text-align:inherit}::-webkit-datetime-edit{display:inline-flex}::-webkit-datetime-edit-fields-wrapper{padding:0}::-webkit-datetime-edit{padding-block:0}::-webkit-datetime-edit-year-field{padding-block:0}::-webkit-datetime-edit-month-field{padding-block:0}::-webkit-datetime-edit-day-field{padding-block:0}::-webkit-datetime-edit-hour-field{padding-block:0}::-webkit-datetime-edit-minute-field{padding-block:0}::-webkit-datetime-edit-second-field{padding-block:0}::-webkit-datetime-edit-millisecond-field{padding-block:0}::-webkit-datetime-edit-meridiem-field{padding-block:0}::-webkit-calendar-picker-indicator{line-height:1}:-moz-ui-invalid{box-shadow:none}button,input:where([type=button],[type=reset],[type=submit]){appearance:button}::file-selector-button{appearance:button}::-webkit-inner-spin-button{height:auto}::-webkit-outer-spin-button{height:auto}[hidden]:where(:not([hidden=until-found])){display:none!important}}@layer components;@layer utilities{.pointer-events-auto{pointer-events:auto}.pointer-events-none{pointer-events:none}.visible{visibility:visible}.fixed{position:fixed}.right-6{right:calc(var(--spacing) * 6)}.right-8{right:calc(var(--spacing) * 8)}.bottom-6{bottom:calc(var(--spacing) * 6)}.bottom-8{bottom:calc(var(--spacing) * 8)}.bottom-24{bottom:calc(var(--spacing) * 24)}.z-\[2147483646\]{z-index:2147483646}.z-\[2147483647\]{z-index:2147483647}.mb-1{margin-bottom:calc(var(--spacing) * 1)}.mb-3{margin-bottom:calc(var(--spacing) * 3)}.flex{display:flex}.inline{display:inline}.inline-flex{display:inline-flex}.size-1\.5{width:calc(var(--spacing) * 1.5);height:calc(var(--spacing) * 1.5)}.size-3{width:calc(var(--spacing) * 3);height:calc(var(--spacing) * 3)}.size-9{width:calc(var(--spacing) * 9);height:calc(var(--spacing) * 9)}.size-14{width:calc(var(--spacing) * 14);height:calc(var(--spacing) * 14)}.h-0{height:calc(var(--spacing) * 0)}.h-8{height:calc(var(--spacing) * 8)}.h-9{height:calc(var(--spacing) * 9)}.h-96{height:calc(var(--spacing) * 96)}.h-\[520px\]{height:520px}.w-\[360px\]{width:360px}.max-w-\[82\%\]{max-width:82%}.flex-1{flex:1}.shrink-0{flex-shrink:0}.animate-bounce{animation:var(--animate-bounce)}.flex-col{flex-direction:column}.items-center{align-items:center}.items-end{align-items:flex-end}.items-start{align-items:flex-start}.justify-between{justify-content:space-between}.justify-center{justify-content:center}.gap-0\.5{gap:calc(var(--spacing) * .5)}.gap-1{gap:calc(var(--spacing) * 1)}.gap-1\.5{gap:calc(var(--spacing) * 1.5)}.gap-2{gap:calc(var(--spacing) * 2)}.overflow-hidden{overflow:hidden}.overflow-y-auto{overflow-y:auto}.rounded{border-radius:.25rem}.rounded-2xl{border-radius:var(--radius-2xl)}.rounded-full{border-radius:3.40282e38px}.rounded-lg{border-radius:var(--radius-lg)}.rounded-tl-sm{border-top-left-radius:var(--radius-sm)}.rounded-tr-sm{border-top-right-radius:var(--radius-sm)}.border{border-style:var(--tw-border-style);border-width:1px}.border-t{border-top-style:var(--tw-border-style);border-top-width:1px}.bg-blue-50{background-color:var(--color-blue-50)}.bg-blue-100{background-color:var(--color-blue-100)}.p-3{padding:calc(var(--spacing) * 3)}.p-4{padding:calc(var(--spacing) * 4)}.px-1{padding-inline:calc(var(--spacing) * 1)}.px-3{padding-inline:calc(var(--spacing) * 3)}.px-3\.5{padding-inline:calc(var(--spacing) * 3.5)}.px-4{padding-inline:calc(var(--spacing) * 4)}.py-0\.5{padding-block:calc(var(--spacing) * .5)}.py-2{padding-block:calc(var(--spacing) * 2)}.py-2\.5{padding-block:calc(var(--spacing) * 2.5)}.py-3{padding-block:calc(var(--spacing) * 3)}.py-3\.5{padding-block:calc(var(--spacing) * 3.5)}.text-2xl{font-size:var(--text-2xl);line-height:var(--tw-leading,var(--text-2xl--line-height))}.text-sm{font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height))}.text-xs{font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height))}.text-\[10px\]{font-size:10px}.leading-relaxed{--tw-leading:var(--leading-relaxed);line-height:var(--leading-relaxed)}.font-bold{--tw-font-weight:var(--font-weight-bold);font-weight:var(--font-weight-bold)}.font-medium{--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium)}.font-semibold{--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold)}.tracking-wide{--tw-tracking:var(--tracking-wide);letter-spacing:var(--tracking-wide)}.text-blue-600{color:var(--color-blue-600)}.text-blue-700{color:var(--color-blue-700)}.text-blue-900{color:var(--color-blue-900)}.uppercase{text-transform:uppercase}.opacity-0{opacity:0}.opacity-100{opacity:1}.shadow-2xl{--tw-shadow:0 25px 50px -12px var(--tw-shadow-color,#00000040);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.shadow-lg{--tw-shadow:0 10px 15px -3px var(--tw-shadow-color,#0000001a), 0 4px 6px -4px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.outline{outline-style:var(--tw-outline-style);outline-width:1px}.transition-all{transition-property:all;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-colors{transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-transform{transition-property:transform,translate,scale,rotate;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.duration-200{--tw-duration:.2s;transition-duration:.2s}.outline-none{--tw-outline-style:none;outline-style:none}@media (hover:hover){.hover\:scale-105:hover{--tw-scale-x:105%;--tw-scale-y:105%;--tw-scale-z:105%;scale:var(--tw-scale-x) var(--tw-scale-y)}}.focus-visible\:ring-2:focus-visible{--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.focus-visible\:outline-none:focus-visible{--tw-outline-style:none;outline-style:none}.disabled\:pointer-events-none:disabled{pointer-events:none}.disabled\:opacity-50:disabled{opacity:.5}}:root{--panacea-primary:oklch(52.7% .154 150.069);--panacea-primary-fg:oklch(98.2% .018 155.826);--panacea-muted:oklch(96.7% .001 286.375);--panacea-muted-fg:oklch(55.2% .016 285.938);--panacea-border:oklch(92% .004 286.32);--panacea-bg:oklch(100% 0 0);--panacea-fg:oklch(14.1% .005 285.823);--panacea-radius:.75rem}@property --tw-border-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-leading{syntax:"*";inherits:false}@property --tw-font-weight{syntax:"*";inherits:false}@property --tw-tracking{syntax:"*";inherits:false}@property --tw-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-shadow-color{syntax:"*";inherits:false}@property --tw-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-inset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-shadow-color{syntax:"*";inherits:false}@property --tw-inset-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-ring-color{syntax:"*";inherits:false}@property --tw-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-ring-color{syntax:"*";inherits:false}@property --tw-inset-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-ring-inset{syntax:"*";inherits:false}@property --tw-ring-offset-width{syntax:"<length>";inherits:false;initial-value:0}@property --tw-ring-offset-color{syntax:"*";inherits:false;initial-value:#fff}@property --tw-ring-offset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-outline-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-duration{syntax:"*";inherits:false}@property --tw-scale-x{syntax:"*";inherits:false;initial-value:1}@property --tw-scale-y{syntax:"*";inherits:false;initial-value:1}@property --tw-scale-z{syntax:"*";inherits:false;initial-value:1}@keyframes bounce{0%,to{animation-timing-function:cubic-bezier(.8,0,1,1);transform:translateY(-25%)}50%{animation-timing-function:cubic-bezier(0,0,.2,1);transform:none}}
|
|
2
|
+
@layer properties{@supports (((-webkit-hyphens:none)) and (not (margin-trim:inline))) or ((-moz-orient:inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-border-style:solid;--tw-leading:initial;--tw-font-weight:initial;--tw-tracking:initial;--tw-shadow:0 0 #0000;--tw-shadow-color:initial;--tw-shadow-alpha:100%;--tw-inset-shadow:0 0 #0000;--tw-inset-shadow-color:initial;--tw-inset-shadow-alpha:100%;--tw-ring-color:initial;--tw-ring-shadow:0 0 #0000;--tw-inset-ring-color:initial;--tw-inset-ring-shadow:0 0 #0000;--tw-ring-inset:initial;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-offset-shadow:0 0 #0000;--tw-outline-style:solid;--tw-duration:initial;--tw-scale-x:1;--tw-scale-y:1;--tw-scale-z:1}}}@layer theme{:root,:host{--font-sans:ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";--font-mono:ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;--color-blue-50:oklch(97% .014 254.604);--color-blue-100:oklch(93.2% .032 255.585);--color-blue-600:oklch(54.6% .245 262.881);--color-blue-700:oklch(48.8% .243 264.376);--color-blue-900:oklch(37.9% .146 265.522);--spacing:.25rem;--text-xs:.75rem;--text-xs--line-height:calc(1 / .75);--text-sm:.875rem;--text-sm--line-height:calc(1.25 / .875);--text-2xl:1.5rem;--text-2xl--line-height:calc(2 / 1.5);--font-weight-medium:500;--font-weight-semibold:600;--font-weight-bold:700;--tracking-wide:.025em;--leading-snug:1.375;--leading-relaxed:1.625;--radius-sm:.25rem;--radius-lg:.5rem;--radius-2xl:1rem;--animate-pulse:pulse 2s cubic-bezier(.4, 0, .6, 1) infinite;--animate-bounce:bounce 1s infinite;--default-transition-duration:.15s;--default-transition-timing-function:cubic-bezier(.4, 0, .2, 1);--default-font-family:var(--font-sans);--default-mono-font-family:var(--font-mono)}}@layer base{*,:after,:before,::backdrop{box-sizing:border-box;border:0 solid;margin:0;padding:0}::file-selector-button{box-sizing:border-box;border:0 solid;margin:0;padding:0}html,:host{-webkit-text-size-adjust:100%;tab-size:4;line-height:1.5;font-family:var(--default-font-family,ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji");font-feature-settings:var(--default-font-feature-settings,normal);font-variation-settings:var(--default-font-variation-settings,normal);-webkit-tap-highlight-color:transparent}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:var(--default-mono-font-family,ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace);font-feature-settings:var(--default-mono-font-feature-settings,normal);font-variation-settings:var(--default-mono-font-variation-settings,normal);font-size:1em}small{font-size:80%}sub,sup{vertical-align:baseline;font-size:75%;line-height:0;position:relative}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}:-moz-focusring{outline:auto}progress{vertical-align:baseline}summary{display:list-item}ol,ul,menu{list-style:none}img,svg,video,canvas,audio,iframe,embed,object{vertical-align:middle;display:block}img,video{max-width:100%;height:auto}button,input,select,optgroup,textarea{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}::file-selector-button{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}:where(select:is([multiple],[size])) optgroup{font-weight:bolder}:where(select:is([multiple],[size])) optgroup option{padding-inline-start:20px}::file-selector-button{margin-inline-end:4px}::placeholder{opacity:1}@supports (not ((-webkit-appearance:-apple-pay-button))) or (contain-intrinsic-size:1px){::placeholder{color:currentColor}@supports (color:color-mix(in lab, red, red)){::placeholder{color:color-mix(in oklab, currentcolor 50%, transparent)}}}textarea{resize:vertical}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-date-and-time-value{min-height:1lh;text-align:inherit}::-webkit-datetime-edit{display:inline-flex}::-webkit-datetime-edit-fields-wrapper{padding:0}::-webkit-datetime-edit{padding-block:0}::-webkit-datetime-edit-year-field{padding-block:0}::-webkit-datetime-edit-month-field{padding-block:0}::-webkit-datetime-edit-day-field{padding-block:0}::-webkit-datetime-edit-hour-field{padding-block:0}::-webkit-datetime-edit-minute-field{padding-block:0}::-webkit-datetime-edit-second-field{padding-block:0}::-webkit-datetime-edit-millisecond-field{padding-block:0}::-webkit-datetime-edit-meridiem-field{padding-block:0}::-webkit-calendar-picker-indicator{line-height:1}:-moz-ui-invalid{box-shadow:none}button,input:where([type=button],[type=reset],[type=submit]){appearance:button}::file-selector-button{appearance:button}::-webkit-inner-spin-button{height:auto}::-webkit-outer-spin-button{height:auto}[hidden]:where(:not([hidden=until-found])){display:none!important}}@layer components;@layer utilities{.pointer-events-auto{pointer-events:auto}.pointer-events-none{pointer-events:none}.visible{visibility:visible}.fixed{position:fixed}.right-6{right:calc(var(--spacing) * 6)}.right-8{right:calc(var(--spacing) * 8)}.bottom-6{bottom:calc(var(--spacing) * 6)}.bottom-8{bottom:calc(var(--spacing) * 8)}.bottom-24{bottom:calc(var(--spacing) * 24)}.z-\[2147483646\]{z-index:2147483646}.z-\[2147483647\]{z-index:2147483647}.mb-1{margin-bottom:calc(var(--spacing) * 1)}.mb-3{margin-bottom:calc(var(--spacing) * 3)}.flex{display:flex}.inline{display:inline}.inline-flex{display:inline-flex}.size-1\.5{width:calc(var(--spacing) * 1.5);height:calc(var(--spacing) * 1.5)}.size-3{width:calc(var(--spacing) * 3);height:calc(var(--spacing) * 3)}.size-9{width:calc(var(--spacing) * 9);height:calc(var(--spacing) * 9)}.size-14{width:calc(var(--spacing) * 14);height:calc(var(--spacing) * 14)}.h-0{height:calc(var(--spacing) * 0)}.h-8{height:calc(var(--spacing) * 8)}.h-9{height:calc(var(--spacing) * 9)}.h-14{height:calc(var(--spacing) * 14)}.h-96{height:calc(var(--spacing) * 96)}.h-\[520px\]{height:520px}.w-\[360px\]{width:360px}.w-full{width:100%}.max-w-\[82\%\]{max-width:82%}.flex-1{flex:1}.shrink-0{flex-shrink:0}.animate-bounce{animation:var(--animate-bounce)}.animate-pulse{animation:var(--animate-pulse)}.flex-col{flex-direction:column}.items-center{align-items:center}.items-end{align-items:flex-end}.items-start{align-items:flex-start}.justify-between{justify-content:space-between}.justify-center{justify-content:center}.gap-0\.5{gap:calc(var(--spacing) * .5)}.gap-1{gap:calc(var(--spacing) * 1)}.gap-1\.5{gap:calc(var(--spacing) * 1.5)}.gap-2{gap:calc(var(--spacing) * 2)}.truncate{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.overflow-hidden{overflow:hidden}.overflow-y-auto{overflow-y:auto}.rounded{border-radius:.25rem}.rounded-2xl{border-radius:var(--radius-2xl)}.rounded-full{border-radius:3.40282e38px}.rounded-lg{border-radius:var(--radius-lg)}.rounded-tl-sm{border-top-left-radius:var(--radius-sm)}.rounded-tr-sm{border-top-right-radius:var(--radius-sm)}.border{border-style:var(--tw-border-style);border-width:1px}.border-t{border-top-style:var(--tw-border-style);border-top-width:1px}.bg-blue-50{background-color:var(--color-blue-50)}.bg-blue-100{background-color:var(--color-blue-100)}.p-2{padding:calc(var(--spacing) * 2)}.p-3{padding:calc(var(--spacing) * 3)}.p-4{padding:calc(var(--spacing) * 4)}.px-1{padding-inline:calc(var(--spacing) * 1)}.px-3{padding-inline:calc(var(--spacing) * 3)}.px-3\.5{padding-inline:calc(var(--spacing) * 3.5)}.px-4{padding-inline:calc(var(--spacing) * 4)}.py-0\.5{padding-block:calc(var(--spacing) * .5)}.py-2{padding-block:calc(var(--spacing) * 2)}.py-2\.5{padding-block:calc(var(--spacing) * 2.5)}.py-3{padding-block:calc(var(--spacing) * 3)}.py-3\.5{padding-block:calc(var(--spacing) * 3.5)}.py-8{padding-block:calc(var(--spacing) * 8)}.text-center{text-align:center}.text-left{text-align:left}.text-2xl{font-size:var(--text-2xl);line-height:var(--tw-leading,var(--text-2xl--line-height))}.text-sm{font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height))}.text-xs{font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height))}.text-\[10px\]{font-size:10px}.leading-relaxed{--tw-leading:var(--leading-relaxed);line-height:var(--leading-relaxed)}.leading-snug{--tw-leading:var(--leading-snug);line-height:var(--leading-snug)}.font-bold{--tw-font-weight:var(--font-weight-bold);font-weight:var(--font-weight-bold)}.font-medium{--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium)}.font-semibold{--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold)}.tracking-wide{--tw-tracking:var(--tracking-wide);letter-spacing:var(--tracking-wide)}.text-blue-600{color:var(--color-blue-600)}.text-blue-700{color:var(--color-blue-700)}.text-blue-900{color:var(--color-blue-900)}.uppercase{text-transform:uppercase}.opacity-0{opacity:0}.opacity-100{opacity:1}.shadow-2xl{--tw-shadow:0 25px 50px -12px var(--tw-shadow-color,#00000040);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.shadow-lg{--tw-shadow:0 10px 15px -3px var(--tw-shadow-color,#0000001a), 0 4px 6px -4px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.outline{outline-style:var(--tw-outline-style);outline-width:1px}.transition-all{transition-property:all;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-colors{transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-transform{transition-property:transform,translate,scale,rotate;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.duration-200{--tw-duration:.2s;transition-duration:.2s}.outline-none{--tw-outline-style:none;outline-style:none}@media (hover:hover){.hover\:scale-105:hover{--tw-scale-x:105%;--tw-scale-y:105%;--tw-scale-z:105%;scale:var(--tw-scale-x) var(--tw-scale-y)}}.focus-visible\:ring-2:focus-visible{--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.focus-visible\:outline-none:focus-visible{--tw-outline-style:none;outline-style:none}.disabled\:pointer-events-none:disabled{pointer-events:none}.disabled\:cursor-wait:disabled{cursor:wait}.disabled\:opacity-50:disabled{opacity:.5}}:root{--panacea-primary:oklch(52.7% .154 150.069);--panacea-primary-fg:oklch(98.2% .018 155.826);--panacea-muted:oklch(96.7% .001 286.375);--panacea-muted-fg:oklch(55.2% .016 285.938);--panacea-border:oklch(92% .004 286.32);--panacea-bg:oklch(100% 0 0);--panacea-fg:oklch(14.1% .005 285.823);--panacea-radius:.75rem}@property --tw-border-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-leading{syntax:"*";inherits:false}@property --tw-font-weight{syntax:"*";inherits:false}@property --tw-tracking{syntax:"*";inherits:false}@property --tw-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-shadow-color{syntax:"*";inherits:false}@property --tw-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-inset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-shadow-color{syntax:"*";inherits:false}@property --tw-inset-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-ring-color{syntax:"*";inherits:false}@property --tw-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-ring-color{syntax:"*";inherits:false}@property --tw-inset-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-ring-inset{syntax:"*";inherits:false}@property --tw-ring-offset-width{syntax:"<length>";inherits:false;initial-value:0}@property --tw-ring-offset-color{syntax:"*";inherits:false;initial-value:#fff}@property --tw-ring-offset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-outline-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-duration{syntax:"*";inherits:false}@property --tw-scale-x{syntax:"*";inherits:false;initial-value:1}@property --tw-scale-y{syntax:"*";inherits:false;initial-value:1}@property --tw-scale-z{syntax:"*";inherits:false;initial-value:1}@keyframes pulse{50%{opacity:.5}}@keyframes bounce{0%,to{animation-timing-function:cubic-bezier(.8,0,1,1);transform:translateY(-25%)}50%{animation-timing-function:cubic-bezier(0,0,.2,1);transform:none}}
|