@usepanacea/react 0.1.0 → 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -101,23 +101,12 @@ function PanaceaProvider({
101
101
  isOpen,
102
102
  setIsOpen
103
103
  }),
104
- [
105
- config,
106
- apiBase,
107
- tokenMgr,
108
- turns,
109
- loading,
110
- streaming,
111
- liveEscalationId,
112
- liveMessages,
113
- isOpen
114
- ]
104
+ [config, apiBase, tokenMgr, turns, loading, streaming, liveEscalationId, liveMessages, isOpen]
115
105
  );
116
106
  return /* @__PURE__ */ jsxRuntime.jsx(PanaceaContext.Provider, { value, children });
117
107
  }
118
108
  function useChat() {
119
109
  const {
120
- config,
121
110
  apiBase,
122
111
  getToken,
123
112
  turns,
@@ -136,17 +125,14 @@ function useChat() {
136
125
  setTurns((prev) => [...prev, { role: "user", content: message }]);
137
126
  try {
138
127
  const token = await getToken();
139
- await fetch(
140
- `${apiBase}/api/v1/inbox/${liveEscalationId}/customer-message`,
141
- {
142
- method: "POST",
143
- headers: {
144
- "Content-Type": "application/json",
145
- Authorization: `Bearer ${token}`
146
- },
147
- body: JSON.stringify({ content: message })
148
- }
149
- );
128
+ await fetch(`${apiBase}/api/v1/inbox/${liveEscalationId}/customer-message`, {
129
+ method: "POST",
130
+ headers: {
131
+ "Content-Type": "application/json",
132
+ Authorization: `Bearer ${token}`
133
+ },
134
+ body: JSON.stringify({ content: message })
135
+ });
150
136
  } catch {
151
137
  }
152
138
  return;
@@ -232,32 +218,21 @@ function useChat() {
232
218
  setStreaming("");
233
219
  }
234
220
  },
235
- [
236
- apiBase,
237
- getToken,
238
- liveEscalationId,
239
- sessionId,
240
- setLoading,
241
- setStreaming,
242
- setTurns
243
- ]
221
+ [apiBase, getToken, liveEscalationId, sessionId, setLoading, setStreaming, setTurns]
244
222
  );
245
223
  const escalate = react.useCallback(
246
224
  async (reason = "Customer requested human support") => {
247
225
  if (!sessionId.current) return;
248
226
  try {
249
227
  const token = await getToken();
250
- const res = await fetch(
251
- `${apiBase}/api/v1/sessions/${sessionId.current}/escalate`,
252
- {
253
- method: "POST",
254
- headers: {
255
- "Content-Type": "application/json",
256
- Authorization: `Bearer ${token}`
257
- },
258
- body: JSON.stringify({ reason })
259
- }
260
- );
228
+ const res = await fetch(`${apiBase}/api/v1/sessions/${sessionId.current}/escalate`, {
229
+ method: "POST",
230
+ headers: {
231
+ "Content-Type": "application/json",
232
+ Authorization: `Bearer ${token}`
233
+ },
234
+ body: JSON.stringify({ reason })
235
+ });
261
236
  if (res.ok) {
262
237
  const data = await res.json();
263
238
  const id = data?.data?.escalationId ?? data?.escalationId;
@@ -271,22 +246,17 @@ function useChat() {
271
246
  const react$1 = react.useCallback(
272
247
  async (turnIndex, reaction) => {
273
248
  if (!sessionId.current) return;
274
- setTurns(
275
- (prev) => prev.map((t, i) => i === turnIndex ? { ...t, reaction } : t)
276
- );
249
+ setTurns((prev) => prev.map((t, i) => i === turnIndex ? { ...t, reaction } : t));
277
250
  try {
278
251
  const token = await getToken();
279
- await fetch(
280
- `${apiBase}/api/v1/sessions/${sessionId.current}/reaction`,
281
- {
282
- method: "POST",
283
- headers: {
284
- "Content-Type": "application/json",
285
- Authorization: `Bearer ${token}`
286
- },
287
- body: JSON.stringify({ reaction, turnIndex })
288
- }
289
- );
252
+ await fetch(`${apiBase}/api/v1/sessions/${sessionId.current}/reaction`, {
253
+ method: "POST",
254
+ headers: {
255
+ "Content-Type": "application/json",
256
+ Authorization: `Bearer ${token}`
257
+ },
258
+ body: JSON.stringify({ reaction, turnIndex })
259
+ });
290
260
  } catch {
291
261
  }
292
262
  },
@@ -297,6 +267,24 @@ function useChat() {
297
267
  setStreaming("");
298
268
  sessionId.current = null;
299
269
  }, [sessionId, setStreaming, setTurns]);
270
+ const setPageContext = react.useCallback(
271
+ async (ctx) => {
272
+ if (!sessionId.current) return;
273
+ try {
274
+ const token = await getToken();
275
+ await fetch(`${apiBase}/api/v1/sessions/${sessionId.current}`, {
276
+ method: "PATCH",
277
+ headers: {
278
+ "Content-Type": "application/json",
279
+ Authorization: `Bearer ${token}`
280
+ },
281
+ body: JSON.stringify({ pageContext: ctx })
282
+ });
283
+ } catch {
284
+ }
285
+ },
286
+ [apiBase, getToken, sessionId]
287
+ );
300
288
  return {
301
289
  turns,
302
290
  loading,
@@ -306,27 +294,21 @@ function useChat() {
306
294
  send,
307
295
  escalate,
308
296
  react: react$1,
297
+ setPageContext,
309
298
  reset
310
299
  };
311
300
  }
312
301
  function useLiveSession() {
313
- const {
314
- apiBase,
315
- getToken,
316
- liveEscalationId,
317
- liveMessages,
318
- setLiveMessages
319
- } = usePanaceaContext();
302
+ const { apiBase, getToken, liveEscalationId, liveMessages, setLiveMessages } = usePanaceaContext();
320
303
  const seenIds = react.useRef(/* @__PURE__ */ new Set());
321
304
  react.useEffect(() => {
322
305
  if (!liveEscalationId) return;
323
306
  const poll = async () => {
324
307
  try {
325
308
  const token = await getToken();
326
- const res = await fetch(
327
- `${apiBase}/api/v1/inbox/${liveEscalationId}/messages`,
328
- { headers: { Authorization: `Bearer ${token}` } }
329
- );
309
+ const res = await fetch(`${apiBase}/api/v1/inbox/${liveEscalationId}/messages`, {
310
+ headers: { Authorization: `Bearer ${token}` }
311
+ });
330
312
  if (!res.ok) return;
331
313
  const data = await res.json();
332
314
  const all = data?.data?.messages ?? data?.messages ?? [];
@@ -347,17 +329,14 @@ function useLiveSession() {
347
329
  if (!liveEscalationId) return;
348
330
  try {
349
331
  const token = await getToken();
350
- await fetch(
351
- `${apiBase}/api/v1/inbox/${liveEscalationId}/customer-message`,
352
- {
353
- method: "POST",
354
- headers: {
355
- "Content-Type": "application/json",
356
- Authorization: `Bearer ${token}`
357
- },
358
- body: JSON.stringify({ content })
359
- }
360
- );
332
+ await fetch(`${apiBase}/api/v1/inbox/${liveEscalationId}/customer-message`, {
333
+ method: "POST",
334
+ headers: {
335
+ "Content-Type": "application/json",
336
+ Authorization: `Bearer ${token}`
337
+ },
338
+ body: JSON.stringify({ content })
339
+ });
361
340
  } catch {
362
341
  }
363
342
  },
@@ -417,6 +396,28 @@ function PanaceaFAB({ className }) {
417
396
  }
418
397
  );
419
398
  }
399
+ function renderContent(text) {
400
+ const parts = text.split(/(\[\[[^\]]+\]\])/g);
401
+ return parts.map((part, i) => {
402
+ const m = part.match(/^\[\[(?:([^|\]]+)\|)?([^\]]+)\]\]$/);
403
+ if (m) {
404
+ const label = (m[1] ?? m[2] ?? part).trim();
405
+ return /* @__PURE__ */ jsxRuntime.jsxs(
406
+ "span",
407
+ {
408
+ className: "inline-flex items-center gap-0.5 rounded bg-blue-50 px-1 py-0.5 text-xs font-medium text-blue-700",
409
+ children: [
410
+ /* @__PURE__ */ jsxRuntime.jsx("svg", { className: "inline size-3 shrink-0", viewBox: "0 0 16 16", fill: "currentColor", children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M2 2h5v2H4v8h8v-3h2v5H2V2zm7 0h5v5h-2V4.414L6.707 9.707 5.293 8.293 10.586 3H9V2z" }) }),
411
+ label
412
+ ]
413
+ },
414
+ i
415
+ );
416
+ }
417
+ if (!part) return null;
418
+ return /* @__PURE__ */ jsxRuntime.jsx("span", { children: part }, i);
419
+ }).filter(Boolean);
420
+ }
420
421
  function Bubble({ turn }) {
421
422
  const isUser = turn.role === "user";
422
423
  const isAgent = turn.isLiveAgent;
@@ -429,7 +430,7 @@ function Bubble({ turn }) {
429
430
  "max-w-[82%] rounded-2xl px-3.5 py-2.5 text-sm leading-relaxed",
430
431
  isUser ? "rounded-tr-sm bg-primary text-primary-foreground" : isAgent ? "rounded-tl-sm bg-blue-100 text-blue-900" : "rounded-tl-sm bg-muted text-foreground"
431
432
  ),
432
- children: turn.content
433
+ children: isUser ? turn.content : renderContent(turn.content)
433
434
  }
434
435
  )
435
436
  ] });
@@ -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, {\n createContext,\n useContext,\n useMemo,\n useRef,\n useState,\n} from \"react\";\nimport type {\n LiveMessage,\n PanaceaConfig,\n PanaceaContextValue,\n Turn,\n} 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 =\n apiBaseProp ??\n (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 [\n config,\n apiBase,\n tokenMgr,\n turns,\n loading,\n streaming,\n liveEscalationId,\n liveMessages,\n isOpen,\n ]\n );\n\n return (\n <PanaceaContext.Provider value={value}>{children}</PanaceaContext.Provider>\n );\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 /** Clear all turns and start fresh */\n reset: () => void;\n}\n\nexport function useChat(): UseChatReturn {\n const {\n config,\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(\n `${apiBase}/api/v1/inbox/${liveEscalationId}/customer-message`,\n {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n Authorization: `Bearer ${token}`,\n },\n body: JSON.stringify({ content: message }),\n }\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 [\n apiBase,\n getToken,\n liveEscalationId,\n sessionId,\n setLoading,\n setStreaming,\n setTurns,\n ]\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(\n `${apiBase}/api/v1/sessions/${sessionId.current}/escalate`,\n {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n Authorization: `Bearer ${token}`,\n },\n body: JSON.stringify({ reason }),\n }\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) =>\n prev.map((t, i) => (i === turnIndex ? { ...t, reaction } : t))\n );\n try {\n const token = await getToken();\n await fetch(\n `${apiBase}/api/v1/sessions/${sessionId.current}/reaction`,\n {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n Authorization: `Bearer ${token}`,\n },\n body: JSON.stringify({ reaction, turnIndex }),\n }\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 return {\n turns,\n loading,\n streaming,\n sessionId: sessionId.current,\n isEscalated: !!liveEscalationId,\n send,\n escalate,\n react,\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 {\n apiBase,\n getToken,\n liveEscalationId,\n liveMessages,\n 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(\n `${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[] =\n 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(\n `${apiBase}/api/v1/inbox/${liveEscalationId}/customer-message`,\n {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n Authorization: `Bearer ${token}`,\n },\n body: JSON.stringify({ content }),\n }\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:\n \"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>,\n VariantProps<typeof buttonVariants> {}\n\nfunction Button({ className, variant, size, ...props }: ButtonProps) {\n return (\n <button className={cn(buttonVariants({ variant, size }), className)} {...props} />\n );\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\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 {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\">\n {panelTitle}\n </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/lib/utils.ts","../src/components/index.tsx"],"names":["createContext","useContext","useMemo","useState","useRef","jsx","useCallback","react","useEffect","twMerge","clsx","cva","jsxs","Fragment"],"mappings":";;;;;;;;;;;AAYO,IAAM,eAAN,MAAmB;AAAA,EAIxB,WAAA,CACmB,QACA,OAAA,EACjB;AAFiB,IAAA,IAAA,CAAA,MAAA,GAAA,MAAA;AACA,IAAA,IAAA,CAAA,OAAA,GAAA,OAAA;AAAA,EAChB;AAAA,EAFgB,MAAA;AAAA,EACA,OAAA;AAAA,EALX,KAAA,GAA2B,IAAA;AAAA,EAC3B,cAAA,GAAyC,IAAA;AAAA,EAOjD,MAAM,QAAA,GAA4B;AAChC,IAAA,IAAI,CAAC,KAAK,KAAA,IAAS,IAAA,CAAK,KAAI,IAAK,IAAA,CAAK,KAAA,CAAM,SAAA,GAAY,GAAA,EAAQ;AAC9D,MAAA,IAAI,CAAC,KAAK,cAAA,EAAgB;AACxB,QAAA,IAAA,CAAK,cAAA,GAAiB,IAAA,CAAK,OAAA,EAAQ,CAAE,QAAQ,MAAM;AACjD,UAAA,IAAA,CAAK,cAAA,GAAiB,IAAA;AAAA,QACxB,CAAC,CAAA;AAAA,MACH;AACA,MAAA,OAAO,IAAA,CAAK,cAAA;AAAA,IACd;AACA,IAAA,OAAO,KAAK,KAAA,CAAM,KAAA;AAAA,EACpB;AAAA,EAEA,MAAc,OAAA,GAA2B;AACvC,IAAA,MAAM,MAAM,MAAM,KAAA,CAAM,CAAA,EAAG,IAAA,CAAK,OAAO,CAAA,yBAAA,CAAA,EAA6B;AAAA,MAClE,MAAA,EAAQ,MAAA;AAAA,MACR,OAAA,EAAS,EAAE,cAAA,EAAgB,kBAAA,EAAmB;AAAA,MAC9C,IAAA,EAAM,KAAK,SAAA,CAAU,EAAE,UAAU,IAAA,CAAK,MAAA,CAAO,UAAU;AAAA,KACxD,CAAA;AAED,IAAA,IAAI,CAAC,IAAI,EAAA,EAAI;AACX,MAAA,MAAM,IAAI,KAAA,CAAM,CAAA,+BAAA,EAAkC,GAAA,CAAI,MAAM,CAAA,CAAA,CAAG,CAAA;AAAA,IACjE;AAEA,IAAA,MAAM,IAAA,GAAQ,MAAM,GAAA,CAAI,IAAA,EAAK;AAC7B,IAAA,IAAA,CAAK,KAAA,GAAQ;AAAA,MACX,OAAO,IAAA,CAAK,KAAA;AAAA,MACZ,WAAW,IAAI,IAAA,CAAK,IAAA,CAAK,SAAS,EAAE,OAAA;AAAQ,KAC9C;AACA,IAAA,OAAO,KAAK,KAAA,CAAM,KAAA;AAAA,EACpB;AACF,CAAA;ACzCA,IAAM,cAAA,GAAiBA,oBAA0C,IAAI,CAAA;AAE9D,SAAS,iBAAA,GAAyC;AACvD,EAAA,MAAM,GAAA,GAAMC,iBAAW,cAAc,CAAA;AACrC,EAAA,IAAI,CAAC,GAAA,EAAK;AACR,IAAA,MAAM,IAAI,KAAA;AAAA,MACR;AAAA,KAEF;AAAA,EACF;AACA,EAAA,OAAO,GAAA;AACT;AAeO,SAAS,eAAA,CAAgB;AAAA,EAC9B,QAAA;AAAA,EACA,QAAA;AAAA,EACA,OAAA,EAAS,WAAA;AAAA,EACT,aAAA;AAAA,EACA,kBAAA;AAAA,EACA;AACF,CAAA,EAAyB;AACvB,EAAA,MAAM,UAAU,WAAA,KAAgB,OAAO,WAAW,WAAA,GAAc,MAAA,CAAO,SAAS,MAAA,GAAS,EAAA,CAAA;AAEzF,EAAA,MAAM,MAAA,GAAwBC,aAAA;AAAA,IAC5B,OAAO,EAAE,QAAA,EAAU,OAAA,EAAS,aAAA,EAAe,oBAAoB,OAAA,EAAQ,CAAA;AAAA;AAAA,IAEvE,CAAC,QAAA,EAAU,OAAA,EAAS,aAAa;AAAA,GACnC;AAGA,EAAA,MAAM,QAAA,GAAWA,aAAA;AAAA,IACf,MAAM,IAAI,YAAA,CAAa,MAAA,EAAQ,OAAO,CAAA;AAAA;AAAA,IAEtC,CAAC,UAAU,OAAO;AAAA,GACpB;AAGA,EAAA,MAAM,CAAC,KAAA,EAAO,QAAQ,CAAA,GAAIC,cAAA,CAAiB,EAAE,CAAA;AAC7C,EAAA,MAAM,CAAC,OAAA,EAAS,UAAU,CAAA,GAAIA,eAAS,KAAK,CAAA;AAC5C,EAAA,MAAM,CAAC,SAAA,EAAW,YAAY,CAAA,GAAIA,eAAS,EAAE,CAAA;AAC7C,EAAA,MAAM,SAAA,GAAYC,aAAsB,IAAI,CAAA;AAG5C,EAAA,MAAM,CAAC,gBAAA,EAAkB,mBAAmB,CAAA,GAAID,eAAwB,IAAI,CAAA;AAC5E,EAAA,MAAM,CAAC,YAAA,EAAc,eAAe,CAAA,GAAIA,cAAA,CAAwB,EAAE,CAAA;AAGlE,EAAA,MAAM,CAAC,MAAA,EAAQ,SAAS,CAAA,GAAIA,eAAS,KAAK,CAAA;AAE1C,EAAA,MAAM,KAAA,GAA6BD,aAAA;AAAA,IACjC,OAAO;AAAA,MACL,MAAA;AAAA,MACA,OAAA;AAAA,MACA,QAAA,EAAU,MAAM,QAAA,CAAS,QAAA,EAAS;AAAA,MAClC,KAAA;AAAA,MACA,QAAA;AAAA,MACA,OAAA;AAAA,MACA,UAAA;AAAA,MACA,SAAA;AAAA,MACA,YAAA;AAAA,MACA,SAAA;AAAA,MACA,gBAAA;AAAA,MACA,mBAAA;AAAA,MACA,YAAA;AAAA,MACA,eAAA;AAAA,MACA,MAAA;AAAA,MACA;AAAA,KACF,CAAA;AAAA,IACA,CAAC,QAAQ,OAAA,EAAS,QAAA,EAAU,OAAO,OAAA,EAAS,SAAA,EAAW,gBAAA,EAAkB,YAAA,EAAc,MAAM;AAAA,GAC/F;AAEA,EAAA,uBAAOG,cAAA,CAAC,cAAA,CAAe,QAAA,EAAf,EAAwB,OAAe,QAAA,EAAS,CAAA;AAC1D;ACzDO,SAAS,OAAA,GAAyB;AACvC,EAAA,MAAM;AAAA,IACJ,OAAA;AAAA,IACA,QAAA;AAAA,IACA,KAAA;AAAA,IACA,QAAA;AAAA,IACA,OAAA;AAAA,IACA,UAAA;AAAA,IACA,SAAA;AAAA,IACA,YAAA;AAAA,IACA,SAAA;AAAA,IACA,gBAAA;AAAA,IACA;AAAA,MACE,iBAAA,EAAkB;AAEtB,EAAA,MAAM,IAAA,GAAOC,iBAAA;AAAA,IACX,OAAO,OAAA,KAAoB;AAEzB,MAAA,IAAI,gBAAA,EAAkB;AACpB,QAAA,QAAA,CAAS,CAAC,IAAA,KAAS,CAAC,GAAG,IAAA,EAAM,EAAE,IAAA,EAAM,MAAA,EAAQ,OAAA,EAAS,OAAA,EAAS,CAAC,CAAA;AAChE,QAAA,IAAI;AACF,UAAA,MAAM,KAAA,GAAQ,MAAM,QAAA,EAAS;AAC7B,UAAA,MAAM,KAAA,CAAM,CAAA,EAAG,OAAO,CAAA,cAAA,EAAiB,gBAAgB,CAAA,iBAAA,CAAA,EAAqB;AAAA,YAC1E,MAAA,EAAQ,MAAA;AAAA,YACR,OAAA,EAAS;AAAA,cACP,cAAA,EAAgB,kBAAA;AAAA,cAChB,aAAA,EAAe,UAAU,KAAK,CAAA;AAAA,aAChC;AAAA,YACA,MAAM,IAAA,CAAK,SAAA,CAAU,EAAE,OAAA,EAAS,SAAS;AAAA,WAC1C,CAAA;AAAA,QACH,CAAA,CAAA,MAAQ;AAAA,QAER;AACA,QAAA;AAAA,MACF;AAEA,MAAA,UAAA,CAAW,IAAI,CAAA;AACf,MAAA,YAAA,CAAa,EAAE,CAAA;AACf,MAAA,QAAA,CAAS,CAAC,IAAA,KAAS,CAAC,GAAG,IAAA,EAAM,EAAE,IAAA,EAAM,MAAA,EAAQ,OAAA,EAAS,OAAA,EAAS,CAAC,CAAA;AAEhE,MAAA,IAAI;AACF,QAAA,MAAM,KAAA,GAAQ,MAAM,QAAA,EAAS;AAC7B,QAAA,MAAM,GAAA,GAAM,MAAM,KAAA,CAAM,CAAA,EAAG,OAAO,CAAA,aAAA,CAAA,EAAiB;AAAA,UACjD,MAAA,EAAQ,MAAA;AAAA,UACR,OAAA,EAAS;AAAA,YACP,cAAA,EAAgB,kBAAA;AAAA,YAChB,aAAA,EAAe,UAAU,KAAK,CAAA,CAAA;AAAA,YAC9B,MAAA,EAAQ;AAAA,WACV;AAAA,UACA,IAAA,EAAM,KAAK,SAAA,CAAU;AAAA,YACnB,QAAA,EAAU,OAAA;AAAA,YACV,WAAW,SAAA,CAAU;AAAA,WACtB;AAAA,SACF,CAAA;AAED,QAAA,IAAI,CAAC,GAAA,CAAI,EAAA,IAAM,CAAC,IAAI,IAAA,EAAM;AACxB,UAAA,MAAM,IAAI,KAAA,CAAM,CAAA,cAAA,EAAiB,GAAA,CAAI,MAAM,CAAA,CAAE,CAAA;AAAA,QAC/C;AAGA,QAAA,MAAM,MAAA,GAAS,GAAA,CAAI,IAAA,CAAK,SAAA,EAAU;AAClC,QAAA,MAAM,OAAA,GAAU,IAAI,WAAA,EAAY;AAChC,QAAA,IAAI,MAAA,GAAS,EAAA;AACb,QAAA,IAAI,aAAA,GAAsC,IAAA;AAE1C,QAAA,OAAO,IAAA,EAAM;AACX,UAAA,MAAM,EAAE,IAAA,EAAM,KAAA,EAAM,GAAI,MAAM,OAAO,IAAA,EAAK;AAC1C,UAAA,IAAI,IAAA,EAAM;AACV,UAAA,MAAA,IAAU,QAAQ,MAAA,CAAO,KAAA,EAAO,EAAE,MAAA,EAAQ,MAAM,CAAA;AAChD,UAAA,MAAM,KAAA,GAAQ,MAAA,CAAO,KAAA,CAAM,IAAI,CAAA;AAC/B,UAAA,MAAA,GAAS,KAAA,CAAM,KAAI,IAAK,EAAA;AAExB,UAAA,KAAA,MAAW,QAAQ,KAAA,EAAO;AACxB,YAAA,IAAI,CAAC,IAAA,CAAK,UAAA,CAAW,QAAQ,CAAA,EAAG;AAChC,YAAA,MAAM,GAAA,GAAM,IAAA,CAAK,KAAA,CAAM,CAAC,EAAE,IAAA,EAAK;AAC/B,YAAA,IAAI,CAAC,GAAA,IAAO,GAAA,KAAQ,QAAA,EAAU;AAC9B,YAAA,IAAI;AACF,cAAA,MAAM,KAAA,GAAQ,IAAA,CAAK,KAAA,CAAM,GAAG,CAAA;AAW5B,cAAA,IAAI,KAAA,CAAM,IAAA,KAAS,OAAA,IAAW,KAAA,CAAM,KAAA,EAAO;AACzC,gBAAA,YAAA,CAAa,CAAC,CAAA,KAAM,CAAA,GAAI,KAAA,CAAM,KAAK,CAAA;AAAA,cACrC,CAAA,MAAA,IAAW,KAAA,CAAM,IAAA,KAAS,MAAA,EAAQ;AAChC,gBAAA,aAAA,GAAgB;AAAA,kBACd,MAAA,EAAQ,MAAM,MAAA,IAAU,EAAA;AAAA,kBACxB,OAAA,EAAS,KAAA,CAAM,OAAA,IAAW,EAAC;AAAA,kBAC3B,UAAA,EAAY,MAAM,UAAA,IAAc,CAAA;AAAA,kBAChC,gBAAA,EAAkB,MAAM,gBAAA,IAAoB,KAAA;AAAA,kBAC5C,SAAA,EAAW,MAAM,SAAA,IAAa,EAAA;AAAA,kBAC9B,WAAW,KAAA,CAAM;AAAA,iBACnB;AAAA,cACF,CAAA,MAAA,IAAW,KAAA,CAAM,IAAA,KAAS,OAAA,EAAS;AACjC,gBAAA,MAAM,IAAI,KAAA,CAAM,KAAA,CAAM,OAAA,IAAW,cAAc,CAAA;AAAA,cACjD;AAAA,YACF,CAAA,CAAA,MAAQ;AAAA,YAER;AAAA,UACF;AAAA,QACF;AAEA,QAAA,IAAI,CAAC,aAAA,EAAe,MAAM,IAAI,MAAM,iCAAiC,CAAA;AAErE,QAAA,SAAA,CAAU,UAAU,aAAA,CAAc,SAAA;AAElC,QAAA,QAAA,CAAS,CAAC,IAAA,KAAS;AAAA,UACjB,GAAG,IAAA;AAAA,UACH;AAAA,YACE,IAAA,EAAM,WAAA;AAAA,YACN,SAAS,aAAA,CAAe,MAAA;AAAA,YACxB,YAAY,aAAA,CAAe,UAAA;AAAA,YAC3B,SAAS,aAAA,CAAe,OAAA;AAAA,YACxB,kBAAkB,aAAA,CAAe,gBAAA;AAAA,YACjC,QAAA,EAAU,IAAA;AAAA,YACV,WAAW,aAAA,CAAe;AAAA;AAC5B,SACD,CAAA;AAAA,MACH,SAAS,GAAA,EAAK;AACZ,QAAA,QAAA,CAAS,CAAC,IAAA,KAAS;AAAA,UACjB,GAAG,IAAA;AAAA,UACH;AAAA,YACE,IAAA,EAAM,WAAA;AAAA,YACN,SACE,GAAA,YAAe,KAAA,GACX,CAAA,sBAAA,EAAyB,GAAA,CAAI,OAAO,CAAA,CAAA,GACpC;AAAA;AACR,SACD,CAAA;AAAA,MACH,CAAA,SAAE;AACA,QAAA,UAAA,CAAW,KAAK,CAAA;AAChB,QAAA,YAAA,CAAa,EAAE,CAAA;AAAA,MACjB;AAAA,IACF,CAAA;AAAA,IACA,CAAC,OAAA,EAAS,QAAA,EAAU,kBAAkB,SAAA,EAAW,UAAA,EAAY,cAAc,QAAQ;AAAA,GACrF;AAEA,EAAA,MAAM,QAAA,GAAWA,iBAAA;AAAA,IACf,OAAO,SAAS,kCAAA,KAAuC;AACrD,MAAA,IAAI,CAAC,UAAU,OAAA,EAAS;AACxB,MAAA,IAAI;AACF,QAAA,MAAM,KAAA,GAAQ,MAAM,QAAA,EAAS;AAC7B,QAAA,MAAM,GAAA,GAAM,MAAM,KAAA,CAAM,CAAA,EAAG,OAAO,CAAA,iBAAA,EAAoB,SAAA,CAAU,OAAO,CAAA,SAAA,CAAA,EAAa;AAAA,UAClF,MAAA,EAAQ,MAAA;AAAA,UACR,OAAA,EAAS;AAAA,YACP,cAAA,EAAgB,kBAAA;AAAA,YAChB,aAAA,EAAe,UAAU,KAAK,CAAA;AAAA,WAChC;AAAA,UACA,IAAA,EAAM,IAAA,CAAK,SAAA,CAAU,EAAE,QAAQ;AAAA,SAChC,CAAA;AACD,QAAA,IAAI,IAAI,EAAA,EAAI;AACV,UAAA,MAAM,IAAA,GAAQ,MAAM,GAAA,CAAI,IAAA,EAAK;AAI7B,UAAA,MAAM,EAAA,GAAK,IAAA,EAAM,IAAA,EAAM,YAAA,IAAgB,IAAA,EAAM,YAAA;AAC7C,UAAA,IAAI,EAAA,sBAAwB,EAAE,CAAA;AAAA,QAChC;AAAA,MACF,CAAA,CAAA,MAAQ;AAAA,MAER;AAAA,IACF,CAAA;AAAA,IACA,CAAC,OAAA,EAAS,QAAA,EAAU,SAAA,EAAW,mBAAmB;AAAA,GACpD;AAEA,EAAA,MAAMC,OAAA,GAAQD,iBAAA;AAAA,IACZ,OAAO,WAAmB,QAAA,KAAsC;AAC9D,MAAA,IAAI,CAAC,UAAU,OAAA,EAAS;AACxB,MAAA,QAAA,CAAS,CAAC,IAAA,KAAS,IAAA,CAAK,GAAA,CAAI,CAAC,CAAA,EAAG,CAAA,KAAO,CAAA,KAAM,SAAA,GAAY,EAAE,GAAG,CAAA,EAAG,QAAA,EAAS,GAAI,CAAE,CAAC,CAAA;AACjF,MAAA,IAAI;AACF,QAAA,MAAM,KAAA,GAAQ,MAAM,QAAA,EAAS;AAC7B,QAAA,MAAM,MAAM,CAAA,EAAG,OAAO,CAAA,iBAAA,EAAoB,SAAA,CAAU,OAAO,CAAA,SAAA,CAAA,EAAa;AAAA,UACtE,MAAA,EAAQ,MAAA;AAAA,UACR,OAAA,EAAS;AAAA,YACP,cAAA,EAAgB,kBAAA;AAAA,YAChB,aAAA,EAAe,UAAU,KAAK,CAAA;AAAA,WAChC;AAAA,UACA,MAAM,IAAA,CAAK,SAAA,CAAU,EAAE,QAAA,EAAU,WAAW;AAAA,SAC7C,CAAA;AAAA,MACH,CAAA,CAAA,MAAQ;AAAA,MAER;AAAA,IACF,CAAA;AAAA,IACA,CAAC,OAAA,EAAS,QAAA,EAAU,SAAA,EAAW,QAAQ;AAAA,GACzC;AAEA,EAAA,MAAM,KAAA,GAAQA,kBAAY,MAAM;AAC9B,IAAA,QAAA,CAAS,EAAE,CAAA;AACX,IAAA,YAAA,CAAa,EAAE,CAAA;AACf,IAAA,SAAA,CAAU,OAAA,GAAU,IAAA;AAAA,EACtB,CAAA,EAAG,CAAC,SAAA,EAAW,YAAA,EAAc,QAAQ,CAAC,CAAA;AAEtC,EAAA,MAAM,cAAA,GAAiBA,iBAAA;AAAA,IACrB,OAAO,GAAA,KAAiC;AACtC,MAAA,IAAI,CAAC,UAAU,OAAA,EAAS;AACxB,MAAA,IAAI;AACF,QAAA,MAAM,KAAA,GAAQ,MAAM,QAAA,EAAS;AAC7B,QAAA,MAAM,MAAM,CAAA,EAAG,OAAO,CAAA,iBAAA,EAAoB,SAAA,CAAU,OAAO,CAAA,CAAA,EAAI;AAAA,UAC7D,MAAA,EAAQ,OAAA;AAAA,UACR,OAAA,EAAS;AAAA,YACP,cAAA,EAAgB,kBAAA;AAAA,YAChB,aAAA,EAAe,UAAU,KAAK,CAAA;AAAA,WAChC;AAAA,UACA,MAAM,IAAA,CAAK,SAAA,CAAU,EAAE,WAAA,EAAa,KAAK;AAAA,SAC1C,CAAA;AAAA,MACH,CAAA,CAAA,MAAQ;AAAA,MAER;AAAA,IACF,CAAA;AAAA,IACA,CAAC,OAAA,EAAS,QAAA,EAAU,SAAS;AAAA,GAC/B;AAEA,EAAA,OAAO;AAAA,IACL,KAAA;AAAA,IACA,OAAA;AAAA,IACA,SAAA;AAAA,IACA,WAAW,SAAA,CAAU,OAAA;AAAA,IACrB,WAAA,EAAa,CAAC,CAAC,gBAAA;AAAA,IACf,IAAA;AAAA,IACA,QAAA;AAAA,WACAC,OAAA;AAAA,IACA,cAAA;AAAA,IACA;AAAA,GACF;AACF;ACzPO,SAAS,cAAA,GAAuC;AACrD,EAAA,MAAM,EAAE,OAAA,EAAS,QAAA,EAAU,kBAAkB,YAAA,EAAc,eAAA,KACzD,iBAAA,EAAkB;AAEpB,EAAA,MAAM,OAAA,GAAUH,YAAAA,iBAAoB,IAAI,GAAA,EAAK,CAAA;AAG7C,EAAAI,eAAA,CAAU,MAAM;AACd,IAAA,IAAI,CAAC,gBAAA,EAAkB;AAEvB,IAAA,MAAM,OAAO,YAAY;AACvB,MAAA,IAAI;AACF,QAAA,MAAM,KAAA,GAAQ,MAAM,QAAA,EAAS;AAC7B,QAAA,MAAM,MAAM,MAAM,KAAA,CAAM,GAAG,OAAO,CAAA,cAAA,EAAiB,gBAAgB,CAAA,SAAA,CAAA,EAAa;AAAA,UAC9E,OAAA,EAAS,EAAE,aAAA,EAAe,CAAA,OAAA,EAAU,KAAK,CAAA,CAAA;AAAG,SAC7C,CAAA;AACD,QAAA,IAAI,CAAC,IAAI,EAAA,EAAI;AAEb,QAAA,MAAM,IAAA,GAAQ,MAAM,GAAA,CAAI,IAAA,EAAK;AAI7B,QAAA,MAAM,MAAqB,IAAA,EAAM,IAAA,EAAM,QAAA,IAAY,IAAA,EAAM,YAAY,EAAC;AAGtE,QAAA,MAAM,OAAA,GAAU,GAAA,CAAI,MAAA,CAAO,CAAC,CAAA,KAAM,CAAC,OAAA,CAAQ,OAAA,CAAQ,GAAA,CAAI,CAAA,CAAE,EAAE,CAAC,CAAA;AAC5D,QAAA,IAAI,OAAA,CAAQ,SAAS,CAAA,EAAG;AACtB,UAAA,OAAA,CAAQ,OAAA,CAAQ,CAAC,CAAA,KAAM,OAAA,CAAQ,QAAQ,GAAA,CAAI,CAAA,CAAE,EAAE,CAAC,CAAA;AAChD,UAAA,eAAA,CAAgB,CAAC,IAAA,KAAS,CAAC,GAAG,IAAA,EAAM,GAAG,OAAO,CAAC,CAAA;AAAA,QACjD;AAAA,MACF,CAAA,CAAA,MAAQ;AAAA,MAER;AAAA,IACF,CAAA;AAEA,IAAA,IAAA,EAAK;AACL,IAAA,MAAM,EAAA,GAAK,WAAA,CAAY,IAAA,EAAM,GAAK,CAAA;AAClC,IAAA,OAAO,MAAM,cAAc,EAAE,CAAA;AAAA,EAC/B,GAAG,CAAC,gBAAA,EAAkB,OAAA,EAAS,QAAA,EAAU,eAAe,CAAC,CAAA;AAEzD,EAAA,MAAM,WAAA,GAAcF,iBAAAA;AAAA,IAClB,OAAO,OAAA,KAAoB;AACzB,MAAA,IAAI,CAAC,gBAAA,EAAkB;AACvB,MAAA,IAAI;AACF,QAAA,MAAM,KAAA,GAAQ,MAAM,QAAA,EAAS;AAC7B,QAAA,MAAM,KAAA,CAAM,CAAA,EAAG,OAAO,CAAA,cAAA,EAAiB,gBAAgB,CAAA,iBAAA,CAAA,EAAqB;AAAA,UAC1E,MAAA,EAAQ,MAAA;AAAA,UACR,OAAA,EAAS;AAAA,YACP,cAAA,EAAgB,kBAAA;AAAA,YAChB,aAAA,EAAe,UAAU,KAAK,CAAA;AAAA,WAChC;AAAA,UACA,IAAA,EAAM,IAAA,CAAK,SAAA,CAAU,EAAE,SAAS;AAAA,SACjC,CAAA;AAAA,MACH,CAAA,CAAA,MAAQ;AAAA,MAER;AAAA,IACF,CAAA;AAAA,IACA,CAAC,gBAAA,EAAkB,OAAA,EAAS,QAAQ;AAAA,GACtC;AAEA,EAAA,OAAO;AAAA,IACL,MAAA,EAAQ,CAAC,CAAC,gBAAA;AAAA,IACV,YAAA,EAAc,gBAAA;AAAA,IACd,YAAA;AAAA,IACA,eAAe,YAAA,CAAa,MAAA,CAAO,CAAC,CAAA,KAAM,CAAA,CAAE,eAAe,OAAO,CAAA;AAAA,IAClE;AAAA,GACF;AACF;AC1EO,SAAS,SAAA,GAA6B;AAC3C,EAAA,MAAM,EAAE,MAAA,EAAQ,SAAA,EAAU,GAAI,iBAAA,EAAkB;AAEhD,EAAA,MAAM,IAAA,GAAOA,kBAAY,MAAM,SAAA,CAAU,IAAI,CAAA,EAAG,CAAC,SAAS,CAAC,CAAA;AAC3D,EAAA,MAAM,KAAA,GAAQA,kBAAY,MAAM,SAAA,CAAU,KAAK,CAAA,EAAG,CAAC,SAAS,CAAC,CAAA;AAC7D,EAAA,MAAM,MAAA,GAASA,iBAAAA,CAAY,MAAM,SAAA,CAAU,CAAC,CAAA,KAAM,CAAC,CAAC,CAAA,EAAG,CAAC,SAAS,CAAC,CAAA;AAElE,EAAA,OAAO,EAAE,MAAA,EAAQ,IAAA,EAAM,KAAA,EAAO,MAAA,EAAO;AACvC;ACjBO,SAAS,MAAM,MAAA,EAAsB;AAC1C,EAAA,OAAOG,qBAAA,CAAQC,SAAA,CAAK,MAAM,CAAC,CAAA;AAC7B;ACUA,IAAM,cAAA,GAAiBC,0BAAA;AAAA,EACrB,mMAAA;AAAA,EACA;AAAA,IACE,QAAA,EAAU;AAAA,MACR,OAAA,EAAS;AAAA,QACP,OAAA,EAAS,wDAAA;AAAA,QACT,OAAA,EAAS,gFAAA;AAAA,QACT,KAAA,EAAO;AAAA,OACT;AAAA,MACA,IAAA,EAAM;AAAA,QACJ,OAAA,EAAS,eAAA;AAAA,QACT,EAAA,EAAI,kBAAA;AAAA,QACJ,IAAA,EAAM;AAAA;AACR,KACF;AAAA,IACA,eAAA,EAAiB,EAAE,OAAA,EAAS,SAAA,EAAW,MAAM,SAAA;AAAU;AAE3D,CAAA;AAKA,SAAS,OAAO,EAAE,SAAA,EAAW,SAAS,IAAA,EAAM,GAAG,OAAM,EAAgB;AACnE,EAAA,uBAAON,cAAAA,CAAC,QAAA,EAAA,EAAO,SAAA,EAAW,GAAG,cAAA,CAAe,EAAE,OAAA,EAAS,IAAA,EAAM,CAAA,EAAG,SAAS,CAAA,EAAI,GAAG,KAAA,EAAO,CAAA;AACzF;AAMO,SAAS,UAAA,CAAW,EAAE,SAAA,EAAU,EAA2B;AAChE,EAAA,MAAM,EAAE,MAAA,EAAO,GAAI,SAAA,EAAU;AAC7B,EAAA,uBACEA,cAAAA;AAAA,IAAC,QAAA;AAAA,IAAA;AAAA,MACC,YAAA,EAAW,mBAAA;AAAA,MACX,OAAA,EAAS,MAAA;AAAA,MACT,SAAA,EAAW,EAAA;AAAA,QACT,wLAAA;AAAA,QACA;AAAA,OACF;AAAA,MACD,QAAA,EAAA;AAAA;AAAA,GAED;AAEJ;AAWA,SAAS,cAAc,IAAA,EAAiC;AACtD,EAAA,MAAM,KAAA,GAAQ,IAAA,CAAK,KAAA,CAAM,mBAAmB,CAAA;AAC5C,EAAA,OAAO,KAAA,CAAM,GAAA,CAAI,CAAC,IAAA,EAAM,CAAA,KAAM;AAC5B,IAAA,MAAM,CAAA,GAAI,IAAA,CAAK,KAAA,CAAM,oCAAoC,CAAA;AACzD,IAAA,IAAI,CAAA,EAAG;AACL,MAAA,MAAM,KAAA,GAAA,CAAS,EAAE,CAAC,CAAA,IAAK,EAAE,CAAC,CAAA,IAAK,MAAM,IAAA,EAAK;AAC1C,MAAA,uBACEO,eAAA;AAAA,QAAC,MAAA;AAAA,QAAA;AAAA,UAEC,SAAA,EAAU,mGAAA;AAAA,UAEV,QAAA,EAAA;AAAA,4BAAAP,cAAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,wBAAA,EAAyB,OAAA,EAAQ,WAAA,EAAY,IAAA,EAAK,cAAA,EAC/D,QAAA,kBAAAA,cAAAA,CAAC,MAAA,EAAA,EAAK,CAAA,EAAE,qFAAoF,CAAA,EAC9F,CAAA;AAAA,YACC;AAAA;AAAA,SAAA;AAAA,QANI;AAAA,OAOP;AAAA,IAEJ;AACA,IAAA,IAAI,CAAC,MAAM,OAAO,IAAA;AAClB,IAAA,uBAAOA,cAAAA,CAAC,MAAA,EAAA,EAAc,QAAA,EAAA,IAAA,EAAA,EAAJ,CAAS,CAAA;AAAA,EAC7B,CAAC,CAAA,CAAE,MAAA,CAAO,OAAO,CAAA;AACnB;AAEA,SAAS,MAAA,CAAO,EAAE,IAAA,EAAK,EAAmB;AACxC,EAAA,MAAM,MAAA,GAAS,KAAK,IAAA,KAAS,MAAA;AAC7B,EAAA,MAAM,UAAU,IAAA,CAAK,WAAA;AACrB,EAAA,uBACEO,eAAA,CAAC,SAAI,SAAA,EAAW,EAAA,CAAG,sBAAsB,MAAA,GAAS,WAAA,GAAc,aAAa,CAAA,EAC1E,QAAA,EAAA;AAAA,IAAA,OAAA,oBACCP,cAAAA,CAAC,MAAA,EAAA,EAAK,SAAA,EAAU,oEAAmE,QAAA,EAAA,OAAA,EAEnF,CAAA;AAAA,oBAEFA,cAAAA;AAAA,MAAC,KAAA;AAAA,MAAA;AAAA,QACC,SAAA,EAAW,EAAA;AAAA,UACT,+DAAA;AAAA,UACA,MAAA,GACI,kDAAA,GACA,OAAA,GACE,yCAAA,GACA;AAAA,SACR;AAAA,QAEC,QAAA,EAAA,MAAA,GAAS,IAAA,CAAK,OAAA,GAAU,aAAA,CAAc,KAAK,OAAO;AAAA;AAAA;AACrD,GAAA,EACF,CAAA;AAEJ;AAEA,SAAS,UAAA,GAAa;AACpB,EAAA,uBACEA,cAAAA,CAAC,KAAA,EAAA,EAAI,WAAU,uBAAA,EACb,QAAA,kBAAAA,eAAC,KAAA,EAAA,EAAI,SAAA,EAAU,2DAAA,EACZ,QAAA,EAAA,CAAC,GAAG,CAAA,EAAG,CAAC,EAAE,GAAA,CAAI,CAAC,sBACdA,cAAAA;AAAA,IAAC,MAAA;AAAA,IAAA;AAAA,MAEC,SAAA,EAAU,6DAAA;AAAA,MACV,OAAO,EAAE,cAAA,EAAgB,CAAA,EAAG,CAAA,GAAI,IAAI,CAAA,CAAA,CAAA;AAAI,KAAA;AAAA,IAFnC;AAAA,GAIR,GACH,CAAA,EACF,CAAA;AAEJ;AAMO,SAAS,eAAA,CAAgB,EAAE,SAAA,EAAU,EAA2B;AACrE,EAAA,MAAM,EAAE,KAAA,EAAO,OAAA,EAAS,SAAA,KAAc,OAAA,EAAQ;AAC9C,EAAA,MAAM,EAAE,aAAA,EAAc,GAAI,cAAA,EAAe;AACzC,EAAA,MAAM,SAAA,GAAYD,aAAuB,IAAI,CAAA;AAE7C,EAAA,MAAM,UAAA,GAAqB,aAAA,CAAc,GAAA,CAAI,CAAC,CAAA,MAAO;AAAA,IACnD,IAAA,EAAM,WAAA;AAAA,IACN,SAAS,CAAA,CAAE,OAAA;AAAA,IACX,WAAA,EAAa;AAAA,GACf,CAAE,CAAA;AACF,EAAA,MAAM,QAAA,GAAW,CAAC,GAAG,KAAA,EAAO,GAAG,UAAU,CAAA;AAEzC,EAAAI,gBAAU,MAAM;AACd,IAAA,SAAA,CAAU,OAAA,EAAS,cAAA,CAAe,EAAE,QAAA,EAAU,UAAU,CAAA;AAAA,EAC1D,CAAA,EAAG,CAAC,QAAA,CAAS,MAAM,CAAC,CAAA;AAEpB,EAAA,uCACG,KAAA,EAAA,EAAI,SAAA,EAAW,EAAA,CAAG,0CAAA,EAA4C,SAAS,CAAA,EACrE,QAAA,EAAA;AAAA,IAAA,QAAA,CAAS,GAAA,CAAI,CAAC,IAAA,EAAM,CAAA,qBACnBH,cAAAA,CAAC,MAAA,EAAA,EAAe,IAAA,EAAA,EAAH,CAAe,CAC7B,CAAA;AAAA,IACA,OAAA,IAAW,CAAC,SAAA,oBAAaA,eAAC,UAAA,EAAA,EAAW,CAAA;AAAA,IACrC,SAAA,oBAAaA,cAAAA,CAAC,MAAA,EAAA,EAAO,IAAA,EAAM,EAAE,IAAA,EAAM,WAAA,EAAa,OAAA,EAAS,SAAA,EAAU,EAAG,CAAA;AAAA,oBACvEA,cAAAA,CAAC,KAAA,EAAA,EAAI,GAAA,EAAK,SAAA,EAAW;AAAA,GAAA,EACvB,CAAA;AAEJ;AAMO,SAAS,YAAA,CAAa;AAAA,EAC3B,WAAA;AAAA,EACA;AACF,CAAA,EAGG;AACD,EAAA,MAAM,EAAE,IAAA,EAAM,OAAA,EAAS,WAAA,KAAgB,OAAA,EAAQ;AAC/C,EAAA,MAAM,QAAA,GAAWD,aAAyB,IAAI,CAAA;AAE9C,EAAA,MAAM,aAAa,MAAM;AACvB,IAAA,MAAM,GAAA,GAAM,QAAA,CAAS,OAAA,EAAS,KAAA,CAAM,IAAA,EAAK;AACzC,IAAA,IAAI,CAAC,OAAO,OAAA,EAAS;AACrB,IAAA,KAAK,KAAK,GAAG,CAAA;AACb,IAAA,IAAI,QAAA,CAAS,OAAA,EAAS,QAAA,CAAS,OAAA,CAAQ,KAAA,GAAQ,EAAA;AAAA,EACjD,CAAA;AAEA,EAAA,uCACG,KAAA,EAAA,EAAI,SAAA,EAAW,EAAA,CAAG,qDAAA,EAAuD,SAAS,CAAA,EACjF,QAAA,EAAA;AAAA,oBAAAC,cAAAA;AAAA,MAAC,OAAA;AAAA,MAAA;AAAA,QACC,GAAA,EAAK,QAAA;AAAA,QACL,WAAA,EAAa,WAAA,GAAc,sBAAA,GAAqB,WAAA,IAAe,sBAAA;AAAA,QAC/D,QAAA,EAAU,OAAA;AAAA,QACV,WAAW,CAAC,CAAA,KAAM,CAAA,CAAE,GAAA,KAAQ,WAAW,UAAA,EAAW;AAAA,QAClD,SAAA,EAAU;AAAA;AAAA,KACZ;AAAA,oBACAA,cAAAA;AAAA,MAAC,MAAA;AAAA,MAAA;AAAA,QACC,OAAA,EAAS,UAAA;AAAA,QACT,QAAA,EAAU,OAAA;AAAA,QACV,IAAA,EAAK,IAAA;AAAA,QACL,SAAA,EAAU,4BAAA;AAAA,QACX,QAAA,EAAA;AAAA;AAAA;AAED,GAAA,EACF,CAAA;AAEJ;AAMO,SAAS,WAAA,CAAY;AAAA,EAC1B,KAAA;AAAA,EACA,WAAA;AAAA,EACA;AACF,CAAA,EAIG;AACD,EAAA,MAAM,EAAE,MAAA,EAAO,GAAI,iBAAA,EAAkB;AACrC,EAAA,MAAM,EAAE,MAAA,EAAQ,KAAA,EAAM,GAAI,SAAA,EAAU;AACpC,EAAA,MAAM,UAAA,GAAa,KAAA,IAAS,MAAA,CAAO,OAAA,EAAS,IAAA,IAAQ,SAAA;AAEpD,EAAA,uBACEO,eAAA,CAAAC,mBAAA,EAAA,EACE,QAAA,EAAA;AAAA,oBAAAR,eAAC,UAAA,EAAA,EAAW,CAAA;AAAA,oBACZO,eAAA;AAAA,MAAC,KAAA;AAAA,MAAA;AAAA,QACC,SAAA,EAAW,EAAA;AAAA,UACT,sKAAA;AAAA,UACA,SACI,2CAAA,GACA,mCAAA;AAAA,UACJ;AAAA,SACF;AAAA,QAGA,QAAA,EAAA;AAAA,0BAAAA,eAAA,CAAC,KAAA,EAAA,EAAI,WAAU,mEAAA,EACb,QAAA,EAAA;AAAA,4BAAAP,cAAAA,CAAC,MAAA,EAAA,EAAK,SAAA,EAAU,+CAAA,EAAiD,QAAA,EAAA,UAAA,EAAW,CAAA;AAAA,4BAC5EA,cAAAA;AAAA,cAAC,QAAA;AAAA,cAAA;AAAA,gBACC,OAAA,EAAS,KAAA;AAAA,gBACT,YAAA,EAAW,OAAA;AAAA,gBACX,SAAA,EAAU,4EAAA;AAAA,gBACX,QAAA,EAAA;AAAA;AAAA;AAED,WAAA,EACF,CAAA;AAAA,0BAEAA,eAAC,eAAA,EAAA,EAAgB,CAAA;AAAA,0BACjBA,cAAAA,CAAC,YAAA,EAAA,EAAa,WAAA,EAA0B;AAAA;AAAA;AAAA;AAC1C,GAAA,EACF,CAAA;AAEJ","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"]}
package/dist/index.d.cts CHANGED
@@ -66,6 +66,8 @@ interface UseChatReturn {
66
66
  escalate: (reason?: string) => Promise<void>;
67
67
  /** Post a thumbs-up/down reaction for a turn by index */
68
68
  react: (turnIndex: number, reaction: "helpful" | "unhelpful") => Promise<void>;
69
+ /** Push page context to the active session (URL, title, content summary, etc.) */
70
+ setPageContext: (ctx: Record<string, unknown>) => Promise<void>;
69
71
  /** Clear all turns and start fresh */
70
72
  reset: () => void;
71
73
  }
package/dist/index.d.ts CHANGED
@@ -66,6 +66,8 @@ interface UseChatReturn {
66
66
  escalate: (reason?: string) => Promise<void>;
67
67
  /** Post a thumbs-up/down reaction for a turn by index */
68
68
  react: (turnIndex: number, reaction: "helpful" | "unhelpful") => Promise<void>;
69
+ /** Push page context to the active session (URL, title, content summary, etc.) */
70
+ setPageContext: (ctx: Record<string, unknown>) => Promise<void>;
69
71
  /** Clear all turns and start fresh */
70
72
  reset: () => void;
71
73
  }
package/dist/index.js CHANGED
@@ -99,23 +99,12 @@ function PanaceaProvider({
99
99
  isOpen,
100
100
  setIsOpen
101
101
  }),
102
- [
103
- config,
104
- apiBase,
105
- tokenMgr,
106
- turns,
107
- loading,
108
- streaming,
109
- liveEscalationId,
110
- liveMessages,
111
- isOpen
112
- ]
102
+ [config, apiBase, tokenMgr, turns, loading, streaming, liveEscalationId, liveMessages, isOpen]
113
103
  );
114
104
  return /* @__PURE__ */ jsx(PanaceaContext.Provider, { value, children });
115
105
  }
116
106
  function useChat() {
117
107
  const {
118
- config,
119
108
  apiBase,
120
109
  getToken,
121
110
  turns,
@@ -134,17 +123,14 @@ function useChat() {
134
123
  setTurns((prev) => [...prev, { role: "user", content: message }]);
135
124
  try {
136
125
  const token = await getToken();
137
- await fetch(
138
- `${apiBase}/api/v1/inbox/${liveEscalationId}/customer-message`,
139
- {
140
- method: "POST",
141
- headers: {
142
- "Content-Type": "application/json",
143
- Authorization: `Bearer ${token}`
144
- },
145
- body: JSON.stringify({ content: message })
146
- }
147
- );
126
+ await fetch(`${apiBase}/api/v1/inbox/${liveEscalationId}/customer-message`, {
127
+ method: "POST",
128
+ headers: {
129
+ "Content-Type": "application/json",
130
+ Authorization: `Bearer ${token}`
131
+ },
132
+ body: JSON.stringify({ content: message })
133
+ });
148
134
  } catch {
149
135
  }
150
136
  return;
@@ -230,32 +216,21 @@ function useChat() {
230
216
  setStreaming("");
231
217
  }
232
218
  },
233
- [
234
- apiBase,
235
- getToken,
236
- liveEscalationId,
237
- sessionId,
238
- setLoading,
239
- setStreaming,
240
- setTurns
241
- ]
219
+ [apiBase, getToken, liveEscalationId, sessionId, setLoading, setStreaming, setTurns]
242
220
  );
243
221
  const escalate = useCallback(
244
222
  async (reason = "Customer requested human support") => {
245
223
  if (!sessionId.current) return;
246
224
  try {
247
225
  const token = await getToken();
248
- const res = await fetch(
249
- `${apiBase}/api/v1/sessions/${sessionId.current}/escalate`,
250
- {
251
- method: "POST",
252
- headers: {
253
- "Content-Type": "application/json",
254
- Authorization: `Bearer ${token}`
255
- },
256
- body: JSON.stringify({ reason })
257
- }
258
- );
226
+ const res = await fetch(`${apiBase}/api/v1/sessions/${sessionId.current}/escalate`, {
227
+ method: "POST",
228
+ headers: {
229
+ "Content-Type": "application/json",
230
+ Authorization: `Bearer ${token}`
231
+ },
232
+ body: JSON.stringify({ reason })
233
+ });
259
234
  if (res.ok) {
260
235
  const data = await res.json();
261
236
  const id = data?.data?.escalationId ?? data?.escalationId;
@@ -269,22 +244,17 @@ function useChat() {
269
244
  const react = useCallback(
270
245
  async (turnIndex, reaction) => {
271
246
  if (!sessionId.current) return;
272
- setTurns(
273
- (prev) => prev.map((t, i) => i === turnIndex ? { ...t, reaction } : t)
274
- );
247
+ setTurns((prev) => prev.map((t, i) => i === turnIndex ? { ...t, reaction } : t));
275
248
  try {
276
249
  const token = await getToken();
277
- await fetch(
278
- `${apiBase}/api/v1/sessions/${sessionId.current}/reaction`,
279
- {
280
- method: "POST",
281
- headers: {
282
- "Content-Type": "application/json",
283
- Authorization: `Bearer ${token}`
284
- },
285
- body: JSON.stringify({ reaction, turnIndex })
286
- }
287
- );
250
+ await fetch(`${apiBase}/api/v1/sessions/${sessionId.current}/reaction`, {
251
+ method: "POST",
252
+ headers: {
253
+ "Content-Type": "application/json",
254
+ Authorization: `Bearer ${token}`
255
+ },
256
+ body: JSON.stringify({ reaction, turnIndex })
257
+ });
288
258
  } catch {
289
259
  }
290
260
  },
@@ -295,6 +265,24 @@ function useChat() {
295
265
  setStreaming("");
296
266
  sessionId.current = null;
297
267
  }, [sessionId, setStreaming, setTurns]);
268
+ const setPageContext = useCallback(
269
+ async (ctx) => {
270
+ if (!sessionId.current) return;
271
+ try {
272
+ const token = await getToken();
273
+ await fetch(`${apiBase}/api/v1/sessions/${sessionId.current}`, {
274
+ method: "PATCH",
275
+ headers: {
276
+ "Content-Type": "application/json",
277
+ Authorization: `Bearer ${token}`
278
+ },
279
+ body: JSON.stringify({ pageContext: ctx })
280
+ });
281
+ } catch {
282
+ }
283
+ },
284
+ [apiBase, getToken, sessionId]
285
+ );
298
286
  return {
299
287
  turns,
300
288
  loading,
@@ -304,27 +292,21 @@ function useChat() {
304
292
  send,
305
293
  escalate,
306
294
  react,
295
+ setPageContext,
307
296
  reset
308
297
  };
309
298
  }
310
299
  function useLiveSession() {
311
- const {
312
- apiBase,
313
- getToken,
314
- liveEscalationId,
315
- liveMessages,
316
- setLiveMessages
317
- } = usePanaceaContext();
300
+ const { apiBase, getToken, liveEscalationId, liveMessages, setLiveMessages } = usePanaceaContext();
318
301
  const seenIds = useRef(/* @__PURE__ */ new Set());
319
302
  useEffect(() => {
320
303
  if (!liveEscalationId) return;
321
304
  const poll = async () => {
322
305
  try {
323
306
  const token = await getToken();
324
- const res = await fetch(
325
- `${apiBase}/api/v1/inbox/${liveEscalationId}/messages`,
326
- { headers: { Authorization: `Bearer ${token}` } }
327
- );
307
+ const res = await fetch(`${apiBase}/api/v1/inbox/${liveEscalationId}/messages`, {
308
+ headers: { Authorization: `Bearer ${token}` }
309
+ });
328
310
  if (!res.ok) return;
329
311
  const data = await res.json();
330
312
  const all = data?.data?.messages ?? data?.messages ?? [];
@@ -345,17 +327,14 @@ function useLiveSession() {
345
327
  if (!liveEscalationId) return;
346
328
  try {
347
329
  const token = await getToken();
348
- await fetch(
349
- `${apiBase}/api/v1/inbox/${liveEscalationId}/customer-message`,
350
- {
351
- method: "POST",
352
- headers: {
353
- "Content-Type": "application/json",
354
- Authorization: `Bearer ${token}`
355
- },
356
- body: JSON.stringify({ content })
357
- }
358
- );
330
+ await fetch(`${apiBase}/api/v1/inbox/${liveEscalationId}/customer-message`, {
331
+ method: "POST",
332
+ headers: {
333
+ "Content-Type": "application/json",
334
+ Authorization: `Bearer ${token}`
335
+ },
336
+ body: JSON.stringify({ content })
337
+ });
359
338
  } catch {
360
339
  }
361
340
  },
@@ -415,6 +394,28 @@ function PanaceaFAB({ className }) {
415
394
  }
416
395
  );
417
396
  }
397
+ function renderContent(text) {
398
+ const parts = text.split(/(\[\[[^\]]+\]\])/g);
399
+ return parts.map((part, i) => {
400
+ const m = part.match(/^\[\[(?:([^|\]]+)\|)?([^\]]+)\]\]$/);
401
+ if (m) {
402
+ const label = (m[1] ?? m[2] ?? part).trim();
403
+ return /* @__PURE__ */ jsxs(
404
+ "span",
405
+ {
406
+ className: "inline-flex items-center gap-0.5 rounded bg-blue-50 px-1 py-0.5 text-xs font-medium text-blue-700",
407
+ children: [
408
+ /* @__PURE__ */ jsx("svg", { className: "inline size-3 shrink-0", viewBox: "0 0 16 16", fill: "currentColor", children: /* @__PURE__ */ jsx("path", { d: "M2 2h5v2H4v8h8v-3h2v5H2V2zm7 0h5v5h-2V4.414L6.707 9.707 5.293 8.293 10.586 3H9V2z" }) }),
409
+ label
410
+ ]
411
+ },
412
+ i
413
+ );
414
+ }
415
+ if (!part) return null;
416
+ return /* @__PURE__ */ jsx("span", { children: part }, i);
417
+ }).filter(Boolean);
418
+ }
418
419
  function Bubble({ turn }) {
419
420
  const isUser = turn.role === "user";
420
421
  const isAgent = turn.isLiveAgent;
@@ -427,7 +428,7 @@ function Bubble({ turn }) {
427
428
  "max-w-[82%] rounded-2xl px-3.5 py-2.5 text-sm leading-relaxed",
428
429
  isUser ? "rounded-tr-sm bg-primary text-primary-foreground" : isAgent ? "rounded-tl-sm bg-blue-100 text-blue-900" : "rounded-tl-sm bg-muted text-foreground"
429
430
  ),
430
- children: turn.content
431
+ children: isUser ? turn.content : renderContent(turn.content)
431
432
  }
432
433
  )
433
434
  ] });
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, {\n createContext,\n useContext,\n useMemo,\n useRef,\n useState,\n} from \"react\";\nimport type {\n LiveMessage,\n PanaceaConfig,\n PanaceaContextValue,\n Turn,\n} 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 =\n apiBaseProp ??\n (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 [\n config,\n apiBase,\n tokenMgr,\n turns,\n loading,\n streaming,\n liveEscalationId,\n liveMessages,\n isOpen,\n ]\n );\n\n return (\n <PanaceaContext.Provider value={value}>{children}</PanaceaContext.Provider>\n );\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 /** Clear all turns and start fresh */\n reset: () => void;\n}\n\nexport function useChat(): UseChatReturn {\n const {\n config,\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(\n `${apiBase}/api/v1/inbox/${liveEscalationId}/customer-message`,\n {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n Authorization: `Bearer ${token}`,\n },\n body: JSON.stringify({ content: message }),\n }\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 [\n apiBase,\n getToken,\n liveEscalationId,\n sessionId,\n setLoading,\n setStreaming,\n setTurns,\n ]\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(\n `${apiBase}/api/v1/sessions/${sessionId.current}/escalate`,\n {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n Authorization: `Bearer ${token}`,\n },\n body: JSON.stringify({ reason }),\n }\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) =>\n prev.map((t, i) => (i === turnIndex ? { ...t, reaction } : t))\n );\n try {\n const token = await getToken();\n await fetch(\n `${apiBase}/api/v1/sessions/${sessionId.current}/reaction`,\n {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n Authorization: `Bearer ${token}`,\n },\n body: JSON.stringify({ reaction, turnIndex }),\n }\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 return {\n turns,\n loading,\n streaming,\n sessionId: sessionId.current,\n isEscalated: !!liveEscalationId,\n send,\n escalate,\n react,\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 {\n apiBase,\n getToken,\n liveEscalationId,\n liveMessages,\n 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(\n `${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[] =\n 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(\n `${apiBase}/api/v1/inbox/${liveEscalationId}/customer-message`,\n {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n Authorization: `Bearer ${token}`,\n },\n body: JSON.stringify({ content }),\n }\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:\n \"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>,\n VariantProps<typeof buttonVariants> {}\n\nfunction Button({ className, variant, size, ...props }: ButtonProps) {\n return (\n <button className={cn(buttonVariants({ variant, size }), className)} {...props} />\n );\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\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 {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\">\n {panelTitle}\n </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/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"]}
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-100:oklch(93.2% .032 255.585);--color-blue-600:oklch(54.6% .245 262.881);--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}.fixed{position:fixed}.right-6{right:calc(var(--spacing) * 6)}.bottom-6{bottom:calc(var(--spacing) * 6)}.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-flex{display:inline-flex}.size-1\.5{width:calc(var(--spacing) * 1.5);height:calc(var(--spacing) * 1.5)}.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-\[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-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-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-100{background-color:var(--color-blue-100)}.p-3{padding:calc(var(--spacing) * 3)}.p-4{padding:calc(var(--spacing) * 4)}.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-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-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-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}}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@usepanacea/react",
3
- "version": "0.1.0",
3
+ "version": "0.1.2",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "description": "React hooks and components for embedding Panacea support chat",