tunio-agent-widget 0.1.0 → 0.1.1

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/README.md CHANGED
@@ -10,17 +10,6 @@ A Next.js demo app for the Tunio on‑air control widget. The widget is a compac
10
10
  - `src/app/page.tsx` — demo page that mounts the widget.
11
11
  - `src/app/fonts.ts` + `src/app/globals.css` — typography setup (Roboto / Russo One, etc.).
12
12
 
13
- ## Widget structure ("player")
14
-
15
- The widget is **not** an audio player. It’s a control surface that sends natural‑language commands to the Tunio agent and shows streaming responses.
16
-
17
- UI sections:
18
-
19
- - Header: title/subtitle + status pill (always Online/Онлайн).
20
- - Message list: system, user, and assistant bubbles (assistant supports Markdown).
21
- - Composer: quick prompt pills + textarea + send button.
22
- - Typing indicator: animated 3‑dot bounce while the agent streams.
23
-
24
13
  ## How streaming works
25
14
 
26
15
  The widget expects the agent API to respond as **Server‑Sent Events (SSE)** over a `POST` request.
@@ -48,7 +37,6 @@ event: message
48
37
  The widget accumulates `event: message` chunks and updates the last assistant bubble in real time.
49
38
 
50
39
  ## Props
51
-
52
40
  ```ts
53
41
  export type TunioWidgetProps = {
54
42
  apiUrl?: string;
package/dist/index.cjs CHANGED
@@ -62,7 +62,7 @@ function styleInject(css, { insertAt } = {}) {
62
62
  }
63
63
 
64
64
  // src/components/TunioWidget.module.css
65
- styleInject(':global(.tw-widget) {\n --panel: #f7f9fc;\n --ink: #1b2430;\n --muted: #6c7a90;\n --accent: #3f6df6;\n --accent-soft: rgba(63, 109, 246, 0.14);\n --teal: #21b3a8;\n --surface: #ffffff;\n --border: rgba(16, 24, 40, 0.12);\n --widget-bg:\n linear-gradient(\n 135deg,\n #f9fbff 0%,\n #eef2f8 60%,\n #e8edf6 100%);\n --header-bg:\n linear-gradient(\n \n 120deg,\n rgba(255, 255, 255, 0.92),\n rgba(243, 246, 252, 0.82) );\n --composer-bg:\n linear-gradient(\n \n 180deg,\n rgba(255, 255, 255, 0) 0%,\n rgba(244, 246, 252, 0.92) 80% );\n --shadow: 0 24px 70px rgba(18, 24, 40, 0.18);\n --glow:\n radial-gradient(\n circle,\n rgba(63, 109, 246, 0.18) 0%,\n rgba(63, 109, 246, 0) 70%);\n --accent-glow: rgba(63, 109, 246, 0.2);\n --bubble-user: #1b2430;\n --bubble-user-text: #f7f9ff;\n --bubble-assistant: #ffffff;\n --bubble-assistant-border: rgba(16, 24, 40, 0.08);\n --bubble-system: rgba(27, 36, 48, 0.08);\n --bubble-system-text: #6c7a90;\n --input-focus-border: rgba(63, 109, 246, 0.6);\n --input-focus-shadow: rgba(63, 109, 246, 0.2);\n --button-bg: #1b2430;\n --button-text: #f7f9ff;\n --button-shadow: rgba(27, 36, 48, 0.2);\n --pill-border: rgba(16, 24, 40, 0.2);\n display: grid;\n grid-template-rows: auto minmax(0, 1fr) auto;\n width: min(100%, 420px);\n height: min(80vh, 640px);\n min-height: 520px;\n border-radius: 12px;\n background: var(--widget-bg);\n border: 1px solid var(--border);\n box-shadow: var(--shadow);\n color: var(--ink);\n overflow: hidden;\n position: relative;\n}\n:global(.tw-light) {\n color-scheme: light;\n}\n:global(.tw-dark) {\n color-scheme: dark;\n --panel: #121826;\n --ink: #e6edf7;\n --muted: #a5b3c8;\n --accent: #4a7dff;\n --accent-soft: rgba(74, 125, 255, 0.18);\n --teal: #2db9c3;\n --surface: #1a2232;\n --border: rgba(230, 237, 247, 0.12);\n --widget-bg:\n linear-gradient(\n 135deg,\n #131a2a 0%,\n #101525 60%,\n #0d1220 100%);\n --header-bg:\n linear-gradient(\n \n 120deg,\n rgba(18, 24, 38, 0.95),\n rgba(23, 30, 48, 0.85) );\n --composer-bg:\n linear-gradient(\n \n 180deg,\n rgba(18, 24, 38, 0) 0%,\n rgba(18, 24, 38, 0.9) 80% );\n --shadow: 0 28px 90px rgba(2, 7, 14, 0.65);\n --glow:\n radial-gradient(\n circle,\n rgba(74, 125, 255, 0.2) 0%,\n rgba(74, 125, 255, 0) 70%);\n --accent-glow: rgba(74, 125, 255, 0.28);\n --bubble-user: #2f3e63;\n --bubble-user-text: #f4f7ff;\n --bubble-assistant: #1a2233;\n --bubble-assistant-border: rgba(230, 237, 247, 0.1);\n --bubble-system: rgba(230, 237, 247, 0.08);\n --bubble-system-text: #b7c3d7;\n --input-focus-border: rgba(74, 125, 255, 0.6);\n --input-focus-shadow: rgba(74, 125, 255, 0.25);\n --button-bg: #4a7dff;\n --button-text: #f4f7ff;\n --button-shadow: rgba(74, 125, 255, 0.35);\n --pill-border: rgba(230, 237, 247, 0.24);\n}\n:global(.tw-widget)::before {\n content: "";\n position: absolute;\n inset: -120px 40% auto -60px;\n height: 220px;\n background: var(--glow);\n pointer-events: none;\n}\n:global(.tw-header) {\n padding: 22px 26px 16px;\n display: flex;\n align-items: center;\n justify-content: space-between;\n background: var(--header-bg);\n backdrop-filter: blur(12px);\n}\n:global(.tw-brand) {\n display: flex;\n flex-direction: column;\n gap: 6px;\n}\n:global(.tw-brand-title) {\n font-family: var(--font-display);\n font-size: 24px;\n letter-spacing: -0.02em;\n}\n:global(.tw-brand-subtitle) {\n color: var(--muted);\n font-size: 13px;\n}\n:global(.tw-status) {\n display: inline-flex;\n align-items: center;\n gap: 8px;\n padding: 6px 12px;\n border-radius: 8px;\n background: var(--accent-soft);\n color: var(--ink);\n font-size: 12px;\n font-weight: 600;\n}\n:global(.tw-status-dot) {\n width: 8px;\n height: 8px;\n border-radius: 50%;\n background: var(--accent);\n box-shadow: 0 0 0 4px var(--accent-glow);\n}\n:global(.tw-messages) {\n padding: 16px 22px 8px;\n display: flex;\n flex-direction: column;\n gap: 14px;\n overflow-y: auto;\n min-height: 0;\n scroll-behavior: smooth;\n}\n:global(.tw-message) {\n max-width: 85%;\n padding: 14px 16px;\n border-radius: 8px;\n line-height: 1.45;\n font-size: 14px;\n animation: fadeUp 0.25s ease;\n}\n:global(.tw-message) p {\n margin: 0;\n}\n:global(.tw-message) p + p {\n margin-top: 8px;\n}\n:global(.tw-message) a {\n color: var(--accent);\n text-decoration: none;\n font-weight: 600;\n}\n:global(.tw-message) a:hover {\n text-decoration: underline;\n}\n:global(.tw-message) strong {\n font-weight: 700;\n}\n:global(.tw-message) ul,\n:global(.tw-message) ol {\n margin: 8px 0 0;\n padding-left: 18px;\n}\n:global(.tw-message) li {\n margin: 4px 0;\n}\n:global(.tw-typing) {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n min-height: 16px;\n color: var(--muted);\n}\n:global(.tw-typing-dot) {\n width: 6px;\n height: 6px;\n border-radius: 999px;\n background: currentColor;\n opacity: 0.6;\n animation: typingBounce 1.2s infinite ease-in-out;\n}\n:global(.tw-typing-dot):nth-child(2) {\n animation-delay: 0.2s;\n}\n:global(.tw-typing-dot):nth-child(3) {\n animation-delay: 0.4s;\n}\n:global(.tw-sr-only) {\n position: absolute;\n width: 1px;\n height: 1px;\n padding: 0;\n margin: -1px;\n overflow: hidden;\n clip: rect(0, 0, 0, 0);\n border: 0;\n}\n:global(.tw-user) {\n align-self: flex-end;\n background: var(--bubble-user);\n color: var(--bubble-user-text);\n border-bottom-right-radius: 8px;\n}\n:global(.tw-assistant) {\n align-self: flex-start;\n background: var(--bubble-assistant);\n border: 1px solid var(--bubble-assistant-border);\n border-bottom-left-radius: 8px;\n}\n:global(.tw-system) {\n align-self: center;\n max-width: 92%;\n text-align: center;\n background: var(--bubble-system);\n color: var(--bubble-system-text);\n}\n:global(.tw-composer) {\n padding: 16px 22px 22px;\n display: grid;\n gap: 10px;\n background: var(--composer-bg);\n}\n:global(.tw-input-wrap) {\n display: flex;\n gap: 10px;\n align-items: flex-end;\n}\n:global(.tw-textarea) {\n flex: 1;\n min-height: 54px;\n max-height: 140px;\n padding: 14px 16px;\n border-radius: 8px;\n border: 1px solid var(--border);\n background: var(--surface);\n color: var(--ink);\n resize: none;\n font-family: inherit;\n font-size: 14px;\n outline: none;\n transition: border 0.2s ease, box-shadow 0.2s ease;\n}\n:global(.tw-textarea)::placeholder {\n color: var(--muted);\n opacity: 0.85;\n}\n:global(.tw-textarea):focus {\n border-color: var(--input-focus-border);\n box-shadow: 0 0 0 3px var(--input-focus-shadow);\n}\n:global(.tw-send) {\n border: none;\n border-radius: 8px;\n padding: 12px 18px;\n background: var(--button-bg);\n color: var(--button-text);\n font-weight: 600;\n cursor: pointer;\n transition: transform 0.2s ease, box-shadow 0.2s ease;\n}\n:global(.tw-send):hover {\n transform: translateY(-1px);\n box-shadow: 0 12px 24px var(--button-shadow);\n}\n:global(.tw-send):disabled {\n opacity: 0.5;\n cursor: not-allowed;\n transform: none;\n box-shadow: none;\n}\n:global(.tw-meta) {\n display: flex;\n justify-content: space-between;\n color: var(--muted);\n font-size: 12px;\n}\n:global(.tw-pill-row) {\n display: flex;\n gap: 8px;\n flex-wrap: wrap;\n}\n:global(.tw-pill) {\n padding: 6px 10px;\n border-radius: 8px;\n border: 1px dashed var(--pill-border);\n color: var(--muted);\n font-size: 11px;\n}\n@keyframes fadeUp {\n from {\n opacity: 0;\n transform: translateY(8px);\n }\n to {\n opacity: 1;\n transform: translateY(0);\n }\n}\n@keyframes typingBounce {\n 0%, 80%, 100% {\n transform: translateY(0);\n opacity: 0.4;\n }\n 40% {\n transform: translateY(-4px);\n opacity: 0.9;\n }\n}\n@media (max-width: 720px) {\n :global(.tw-widget) {\n width: 100%;\n height: 100vh;\n border-radius: 12px;\n }\n}\n');
65
+ styleInject('.tw-widget {\n --panel: #f7f9fc;\n --ink: #1b2430;\n --muted: #6c7a90;\n --accent: #3f6df6;\n --accent-soft: rgba(63, 109, 246, 0.14);\n --teal: #21b3a8;\n --surface: #ffffff;\n --border: rgba(16, 24, 40, 0.12);\n --widget-bg:\n linear-gradient(\n 135deg,\n #f9fbff 0%,\n #eef2f8 60%,\n #e8edf6 100%);\n --header-bg:\n linear-gradient(\n \n 120deg,\n rgba(255, 255, 255, 0.92),\n rgba(243, 246, 252, 0.82) );\n --composer-bg:\n linear-gradient(\n \n 180deg,\n rgba(255, 255, 255, 0) 0%,\n rgba(244, 246, 252, 0.92) 80% );\n --shadow: 0 24px 70px rgba(18, 24, 40, 0.18);\n --glow:\n radial-gradient(\n circle,\n rgba(63, 109, 246, 0.18) 0%,\n rgba(63, 109, 246, 0) 70%);\n --accent-glow: rgba(63, 109, 246, 0.2);\n --bubble-user: #1b2430;\n --bubble-user-text: #f7f9ff;\n --bubble-assistant: #ffffff;\n --bubble-assistant-border: rgba(16, 24, 40, 0.08);\n --bubble-system: rgba(27, 36, 48, 0.08);\n --bubble-system-text: #6c7a90;\n --input-focus-border: rgba(63, 109, 246, 0.6);\n --input-focus-shadow: rgba(63, 109, 246, 0.2);\n --button-bg: #1b2430;\n --button-text: #f7f9ff;\n --button-shadow: rgba(27, 36, 48, 0.2);\n --pill-border: rgba(16, 24, 40, 0.2);\n display: grid;\n grid-template-rows: auto minmax(0, 1fr) auto;\n width: min(100%, 420px);\n height: min(80vh, 640px);\n min-height: 520px;\n border-radius: 12px;\n background: var(--widget-bg);\n border: 1px solid var(--border);\n box-shadow: var(--shadow);\n color: var(--ink);\n overflow: hidden;\n position: relative;\n}\n.tw-light {\n color-scheme: light;\n}\n.tw-dark {\n color-scheme: dark;\n --panel: #121826;\n --ink: #e6edf7;\n --muted: #a5b3c8;\n --accent: #4a7dff;\n --accent-soft: rgba(74, 125, 255, 0.18);\n --teal: #2db9c3;\n --surface: #1a2232;\n --border: rgba(230, 237, 247, 0.12);\n --widget-bg:\n linear-gradient(\n 135deg,\n #131a2a 0%,\n #101525 60%,\n #0d1220 100%);\n --header-bg:\n linear-gradient(\n \n 120deg,\n rgba(18, 24, 38, 0.95),\n rgba(23, 30, 48, 0.85) );\n --composer-bg:\n linear-gradient(\n \n 180deg,\n rgba(18, 24, 38, 0) 0%,\n rgba(18, 24, 38, 0.9) 80% );\n --shadow: 0 28px 90px rgba(2, 7, 14, 0.65);\n --glow:\n radial-gradient(\n circle,\n rgba(74, 125, 255, 0.2) 0%,\n rgba(74, 125, 255, 0) 70%);\n --accent-glow: rgba(74, 125, 255, 0.28);\n --bubble-user: #2f3e63;\n --bubble-user-text: #f4f7ff;\n --bubble-assistant: #1a2233;\n --bubble-assistant-border: rgba(230, 237, 247, 0.1);\n --bubble-system: rgba(230, 237, 247, 0.08);\n --bubble-system-text: #b7c3d7;\n --input-focus-border: rgba(74, 125, 255, 0.6);\n --input-focus-shadow: rgba(74, 125, 255, 0.25);\n --button-bg: #4a7dff;\n --button-text: #f4f7ff;\n --button-shadow: rgba(74, 125, 255, 0.35);\n --pill-border: rgba(230, 237, 247, 0.24);\n}\n.tw-widget::before {\n content: "";\n position: absolute;\n inset: -120px 40% auto -60px;\n height: 220px;\n background: var(--glow);\n pointer-events: none;\n}\n.tw-header {\n padding: 22px 26px 16px;\n display: flex;\n align-items: center;\n justify-content: space-between;\n background: var(--header-bg);\n backdrop-filter: blur(12px);\n}\n.tw-brand {\n display: flex;\n flex-direction: column;\n gap: 6px;\n}\n.tw-brand-title {\n font-family: var(--font-display);\n font-size: 24px;\n letter-spacing: -0.02em;\n}\n.tw-brand-subtitle {\n color: var(--muted);\n font-size: 13px;\n}\n.tw-status {\n display: inline-flex;\n align-items: center;\n gap: 8px;\n padding: 6px 12px;\n border-radius: 8px;\n background: var(--accent-soft);\n color: var(--ink);\n font-size: 12px;\n font-weight: 600;\n}\n.tw-status-dot {\n width: 8px;\n height: 8px;\n border-radius: 50%;\n background: var(--accent);\n box-shadow: 0 0 0 4px var(--accent-glow);\n}\n.tw-messages {\n padding: 16px 22px 8px;\n display: flex;\n flex-direction: column;\n gap: 14px;\n overflow-y: auto;\n min-height: 0;\n scroll-behavior: smooth;\n}\n.tw-message {\n max-width: 85%;\n padding: 14px 16px;\n border-radius: 8px;\n line-height: 1.45;\n font-size: 14px;\n animation: fadeUp 0.25s ease;\n}\n.tw-message p {\n margin: 0;\n}\n.tw-message p + p {\n margin-top: 8px;\n}\n.tw-message a {\n color: var(--accent);\n text-decoration: none;\n font-weight: 600;\n}\n.tw-message a:hover {\n text-decoration: underline;\n}\n.tw-message strong {\n font-weight: 700;\n}\n.tw-message ul,\n.tw-message ol {\n margin: 8px 0 0;\n padding-left: 18px;\n}\n.tw-message li {\n margin: 4px 0;\n}\n.tw-typing {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n min-height: 16px;\n color: var(--muted);\n}\n.tw-typing-dot {\n width: 6px;\n height: 6px;\n border-radius: 999px;\n background: currentColor;\n opacity: 0.6;\n animation: typingBounce 1.2s infinite ease-in-out;\n}\n.tw-typing-dot:nth-child(2) {\n animation-delay: 0.2s;\n}\n.tw-typing-dot:nth-child(3) {\n animation-delay: 0.4s;\n}\n.tw-sr-only {\n position: absolute;\n width: 1px;\n height: 1px;\n padding: 0;\n margin: -1px;\n overflow: hidden;\n clip: rect(0, 0, 0, 0);\n border: 0;\n}\n.tw-user {\n align-self: flex-end;\n background: var(--bubble-user);\n color: var(--bubble-user-text);\n border-bottom-right-radius: 8px;\n}\n.tw-assistant {\n align-self: flex-start;\n background: var(--bubble-assistant);\n border: 1px solid var(--bubble-assistant-border);\n border-bottom-left-radius: 8px;\n}\n.tw-system {\n align-self: center;\n max-width: 92%;\n text-align: center;\n background: var(--bubble-system);\n color: var(--bubble-system-text);\n}\n.tw-composer {\n padding: 16px 22px 22px;\n display: grid;\n gap: 10px;\n background: var(--composer-bg);\n}\n.tw-input-wrap {\n display: flex;\n gap: 10px;\n align-items: flex-end;\n}\n.tw-textarea {\n flex: 1;\n min-height: 54px;\n max-height: 140px;\n padding: 14px 16px;\n border-radius: 8px;\n border: 1px solid var(--border);\n background: var(--surface);\n color: var(--ink);\n resize: none;\n font-family: inherit;\n font-size: 14px;\n outline: none;\n transition: border 0.2s ease, box-shadow 0.2s ease;\n}\n.tw-textarea::placeholder {\n color: var(--muted);\n opacity: 0.85;\n}\n.tw-textarea:focus {\n border-color: var(--input-focus-border);\n box-shadow: 0 0 0 3px var(--input-focus-shadow);\n}\n.tw-send {\n border: none;\n border-radius: 8px;\n padding: 12px 18px;\n background: var(--button-bg);\n color: var(--button-text);\n font-weight: 600;\n cursor: pointer;\n transition: transform 0.2s ease, box-shadow 0.2s ease;\n}\n.tw-send:hover {\n transform: translateY(-1px);\n box-shadow: 0 12px 24px var(--button-shadow);\n}\n.tw-send:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n transform: none;\n box-shadow: none;\n}\n.tw-meta {\n display: flex;\n justify-content: space-between;\n color: var(--muted);\n font-size: 12px;\n}\n.tw-pill-row {\n display: flex;\n gap: 8px;\n flex-wrap: wrap;\n}\n.tw-pill {\n padding: 6px 10px;\n border-radius: 8px;\n border: 1px dashed var(--pill-border);\n color: var(--muted);\n font-size: 11px;\n}\n@keyframes fadeUp {\n from {\n opacity: 0;\n transform: translateY(8px);\n }\n to {\n opacity: 1;\n transform: translateY(0);\n }\n}\n@keyframes typingBounce {\n 0%, 80%, 100% {\n transform: translateY(0);\n opacity: 0.4;\n }\n 40% {\n transform: translateY(-4px);\n opacity: 0.9;\n }\n}\n@media (max-width: 720px) {\n .tw-widget {\n width: 100%;\n height: 100vh;\n border-radius: 12px;\n }\n}\n');
66
66
 
67
67
  // src/i18n/translations.ts
68
68
  var en = {
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/components/TunioWidget.tsx","#style-inject:#style-inject","../src/components/TunioWidget.module.css","../src/i18n/translations.ts"],"sourcesContent":["export { TunioWidget } from './components/TunioWidget';\nexport type { TunioWidgetProps } from './components/TunioWidget';\n","'use client';\n\nimport { useCallback, useEffect, useMemo, useRef, useState } from 'react';\nimport ReactMarkdown from 'react-markdown';\nimport remarkGfm from 'remark-gfm';\nimport './TunioWidget.module.css';\nimport { getTranslations } from '../i18n/translations';\n\ntype ChatMessage = {\n id: string;\n role: 'user' | 'assistant' | 'system';\n content: string;\n};\n\nexport type TunioWidgetProps = {\n apiUrl?: string;\n sessionTokenUrl?: string;\n lang?: string;\n getSessionToken?: () => Promise<string>;\n accessToken?: string;\n title?: string;\n subtitle?: string;\n theme?: 'light' | 'dark';\n className?: string;\n onNavigate?: (href: string) => void;\n};\n\nconst createId = () => Math.random().toString(36).slice(2);\n\nexport function TunioWidget({\n apiUrl,\n sessionTokenUrl,\n lang,\n getSessionToken,\n accessToken,\n title,\n subtitle,\n theme = 'light',\n className,\n onNavigate,\n}: TunioWidgetProps) {\n const [input, setInput] = useState('');\n const [isStreaming, setIsStreaming] = useState(false);\n const [error, setError] = useState<string | null>(null);\n const [sessionToken, setSessionToken] = useState<string | null>(null);\n const inputRef = useRef<HTMLTextAreaElement | null>(null);\n const messagesEndRef = useRef<HTMLDivElement | null>(null);\n\n const resolvedApiUrl = apiUrl ?? process.env.NEXT_PUBLIC_AGENT_API_URL ?? '';\n const resolvedTokenUrl =\n sessionTokenUrl ?? process.env.NEXT_PUBLIC_SESSION_TOKEN_URL ?? '';\n const resolvedUserLang = useMemo(() => {\n if (lang) return lang;\n if (typeof navigator !== 'undefined' && navigator.language) {\n return navigator.language.split('-')[0];\n }\n return undefined;\n }, [lang]);\n const i18n = useMemo(() => getTranslations(resolvedUserLang), [resolvedUserLang]);\n const [messages, setMessages] = useState<ChatMessage[]>(() => [\n {\n id: 'welcome',\n role: 'system',\n content: i18n.systemMessage,\n },\n ]);\n const hasUserMessage = useMemo(\n () => messages.some((message) => message.role === 'user'),\n [messages]\n );\n const displayTitle = title ?? i18n.titleDefault;\n const displaySubtitle = subtitle ?? i18n.subtitleDefault;\n\n const scrollToBottom = () => {\n messagesEndRef.current?.scrollIntoView({ behavior: 'smooth' });\n };\n\n useEffect(() => {\n scrollToBottom();\n }, [messages]);\n\n useEffect(() => {\n setMessages((prev) => {\n if (prev.length === 1 && prev[0].id === 'welcome' && prev[0].role === 'system') {\n return [{ ...prev[0], content: i18n.systemMessage }];\n }\n return prev;\n });\n }, [i18n.systemMessage]);\n\n const fetchSessionToken = useCallback(async () => {\n if (getSessionToken) {\n return getSessionToken();\n }\n\n if (accessToken) {\n return accessToken;\n }\n\n if (!resolvedTokenUrl) {\n throw new Error(i18n.errorMissingTokenUrl);\n }\n\n const response = await fetch(resolvedTokenUrl, {\n credentials: accessToken ? 'omit' : 'include',\n headers: accessToken ? { Authorization: `Bearer ${accessToken}` } : undefined,\n });\n\n if (!response.ok) {\n throw new Error(i18n.errorFailedTokenFetch);\n }\n\n const data = (await response.json()) as Record<string, unknown>;\n const token = data.session_token as string;\n\n if (!token) {\n throw new Error(i18n.errorMissingToken);\n }\n\n return token;\n }, [getSessionToken, i18n, resolvedTokenUrl]);\n\n useEffect(() => {\n fetchSessionToken()\n .then(setSessionToken)\n .catch((err) => {\n setError(err instanceof Error ? err.message : i18n.errorTokenLoad);\n });\n }, [fetchSessionToken, i18n.errorTokenLoad]);\n\n const statusLabel = useMemo(() => {\n if (isStreaming) return i18n.statusStreaming;\n if (error) return i18n.statusNeedsAttention;\n return i18n.statusReady;\n }, [error, i18n, isStreaming]);\n\n const handleLinkClick = useCallback(\n (href: string | undefined, event: React.MouseEvent<HTMLAnchorElement>) => {\n if (!href) return;\n const isInternal = href.startsWith('/') && !href.startsWith('//');\n if (isInternal && onNavigate) {\n event.preventDefault();\n onNavigate(href);\n }\n },\n [onNavigate]\n );\n\n const normalizeHref = useCallback((href: string | undefined) => {\n if (!href) return href;\n if (href.startsWith('/') || href.startsWith('#') || href.startsWith('?')) {\n return href;\n }\n if (href.startsWith('mailto:') || href.startsWith('tel:')) {\n return href;\n }\n if (typeof window === 'undefined') {\n return href;\n }\n try {\n const url = new URL(href);\n if (url.host === window.location.host) {\n return `${url.pathname}${url.search}${url.hash}`;\n }\n } catch {\n return href;\n }\n return href;\n }, []);\n\n const focusInput = () => {\n requestAnimationFrame(() => {\n inputRef.current?.focus();\n });\n };\n\n const sendMessage = async () => {\n if (isStreaming) {\n focusInput();\n return;\n }\n if (!input.trim() || !resolvedApiUrl) {\n focusInput();\n return;\n }\n if (!sessionToken) {\n setError(i18n.errorTokenUnavailable);\n focusInput();\n return;\n }\n\n setError(null);\n setIsStreaming(true);\n\n const userMessage: ChatMessage = {\n id: createId(),\n role: 'user',\n content: input.trim(),\n };\n\n const assistantMessage: ChatMessage = {\n id: createId(),\n role: 'assistant',\n content: '',\n };\n\n setMessages((prev) => [...prev, userMessage, assistantMessage]);\n setInput('');\n focusInput();\n\n try {\n const response = await fetch(resolvedApiUrl, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n message: userMessage.content,\n session_token: sessionToken,\n user_lang: resolvedUserLang,\n }),\n });\n\n if (!response.ok || !response.body) {\n throw new Error(i18n.errorServiceUnavailable);\n }\n\n const reader = response.body.getReader();\n const decoder = new TextDecoder();\n let buffer = '';\n\n while (true) {\n const { value, done } = await reader.read();\n if (done) break;\n buffer += decoder.decode(value, { stream: true });\n\n const parts = buffer.split('\\n\\n');\n buffer = parts.pop() ?? '';\n\n for (const part of parts) {\n const lines = part.split('\\n');\n let eventName = 'message';\n let data = '';\n\n for (const line of lines) {\n if (line.startsWith('event:')) {\n eventName = line.replace('event:', '').trim();\n }\n if (line.startsWith('data:')) {\n data += line.replace('data:', '').trim();\n }\n }\n\n if (!data) continue;\n\n if (eventName === 'message') {\n const payload = JSON.parse(data) as { content?: string };\n if (payload.content !== undefined) {\n setMessages((prev) => {\n const next = [...prev];\n const last = next[next.length - 1];\n if (last && last.role === 'assistant') {\n last.content = payload.content ?? '';\n }\n return next;\n });\n }\n }\n\n if (eventName === 'error') {\n const payload = JSON.parse(data) as { message?: string };\n setError(payload.message ?? i18n.errorUnknown);\n }\n }\n }\n } catch (err) {\n setError(err instanceof Error ? err.message : i18n.errorUnexpected);\n } finally {\n setIsStreaming(false);\n }\n };\n\n return (\n <section\n className={`tw-widget tw-${theme}${className ? ` ${className}` : ''}`}\n data-theme={theme}\n data-tunio-widget=\"root\"\n >\n <header className=\"tw-header\">\n <div className=\"tw-brand\">\n <div className=\"tw-brand-title\">{displayTitle}</div>\n <div className=\"tw-brand-subtitle\">{displaySubtitle}</div>\n </div>\n <div className=\"tw-status\">\n <span className=\"tw-status-dot\" />\n {statusLabel}\n </div>\n </header>\n\n <div className=\"tw-messages\">\n {messages.map((message) => (\n <div\n key={message.id}\n className={`tw-message tw-${message.role}`}\n >\n {message.content ? (\n <ReactMarkdown\n remarkPlugins={[remarkGfm]}\n components={{\n a: ({ href, children, ...props }) => {\n const normalizedHref = normalizeHref(href);\n const isInternal =\n typeof normalizedHref === 'string' &&\n normalizedHref.startsWith('/') &&\n !normalizedHref.startsWith('//');\n return (\n <a\n {...props}\n href={normalizedHref}\n onClick={(event) => handleLinkClick(normalizedHref, event)}\n target={isInternal ? undefined : '_blank'}\n rel={isInternal ? undefined : 'noreferrer'}\n >\n {children}\n </a>\n );\n },\n }}\n >\n {message.content}\n </ReactMarkdown>\n ) : message.role === 'assistant' ? (\n <span className=\"tw-typing\" role=\"status\" aria-label={i18n.thinking}>\n <span className=\"tw-typing-dot\" />\n <span className=\"tw-typing-dot\" />\n <span className=\"tw-typing-dot\" />\n <span className=\"tw-sr-only\">{i18n.thinking}</span>\n </span>\n ) : (\n ''\n )}\n </div>\n ))}\n <div ref={messagesEndRef} />\n </div>\n\n <div className=\"tw-composer\">\n {!hasUserMessage ? (\n <div className=\"tw-pill-row\">\n <span className=\"tw-pill\">{i18n.pillSynthwave}</span>\n <span className=\"tw-pill\">{i18n.pillSchedule}</span>\n <span className=\"tw-pill\">{i18n.pillPlayNow}</span>\n </div>\n ) : null}\n <div className=\"tw-input-wrap\">\n <textarea\n className=\"tw-textarea\"\n placeholder={i18n.inputPlaceholder}\n value={input}\n onChange={(event) => setInput(event.target.value)}\n onKeyDown={(event) => {\n if (event.nativeEvent.isComposing) return;\n if (event.key !== 'Enter') return;\n if (event.shiftKey) return;\n event.preventDefault();\n sendMessage();\n }}\n rows={2}\n ref={inputRef}\n />\n <button\n className=\"tw-send\"\n onClick={sendMessage}\n disabled={isStreaming || !input.trim()}\n >\n {isStreaming ? i18n.sending : i18n.send}\n </button>\n </div>\n {error ? (\n <div className=\"tw-meta\">\n {i18n.errorPrefix} {error}\n </div>\n ) : null}\n </div>\n </section>\n );\n}\n","\n export default function styleInject(css, { insertAt } = {}) {\n if (!css || typeof document === 'undefined') return\n \n const head = document.head || document.getElementsByTagName('head')[0]\n const style = document.createElement('style')\n style.type = 'text/css'\n \n if (insertAt === 'top') {\n if (head.firstChild) {\n head.insertBefore(style, head.firstChild)\n } else {\n head.appendChild(style)\n }\n } else {\n head.appendChild(style)\n }\n \n if (style.styleSheet) {\n style.styleSheet.cssText = css\n } else {\n style.appendChild(document.createTextNode(css))\n }\n }\n ","import styleInject from '#style-inject';styleInject(\":global(.tw-widget) {\\n --panel: #f7f9fc;\\n --ink: #1b2430;\\n --muted: #6c7a90;\\n --accent: #3f6df6;\\n --accent-soft: rgba(63, 109, 246, 0.14);\\n --teal: #21b3a8;\\n --surface: #ffffff;\\n --border: rgba(16, 24, 40, 0.12);\\n --widget-bg:\\n linear-gradient(\\n 135deg,\\n #f9fbff 0%,\\n #eef2f8 60%,\\n #e8edf6 100%);\\n --header-bg:\\n linear-gradient(\\n \\n 120deg,\\n rgba(255, 255, 255, 0.92),\\n rgba(243, 246, 252, 0.82) );\\n --composer-bg:\\n linear-gradient(\\n \\n 180deg,\\n rgba(255, 255, 255, 0) 0%,\\n rgba(244, 246, 252, 0.92) 80% );\\n --shadow: 0 24px 70px rgba(18, 24, 40, 0.18);\\n --glow:\\n radial-gradient(\\n circle,\\n rgba(63, 109, 246, 0.18) 0%,\\n rgba(63, 109, 246, 0) 70%);\\n --accent-glow: rgba(63, 109, 246, 0.2);\\n --bubble-user: #1b2430;\\n --bubble-user-text: #f7f9ff;\\n --bubble-assistant: #ffffff;\\n --bubble-assistant-border: rgba(16, 24, 40, 0.08);\\n --bubble-system: rgba(27, 36, 48, 0.08);\\n --bubble-system-text: #6c7a90;\\n --input-focus-border: rgba(63, 109, 246, 0.6);\\n --input-focus-shadow: rgba(63, 109, 246, 0.2);\\n --button-bg: #1b2430;\\n --button-text: #f7f9ff;\\n --button-shadow: rgba(27, 36, 48, 0.2);\\n --pill-border: rgba(16, 24, 40, 0.2);\\n display: grid;\\n grid-template-rows: auto minmax(0, 1fr) auto;\\n width: min(100%, 420px);\\n height: min(80vh, 640px);\\n min-height: 520px;\\n border-radius: 12px;\\n background: var(--widget-bg);\\n border: 1px solid var(--border);\\n box-shadow: var(--shadow);\\n color: var(--ink);\\n overflow: hidden;\\n position: relative;\\n}\\n:global(.tw-light) {\\n color-scheme: light;\\n}\\n:global(.tw-dark) {\\n color-scheme: dark;\\n --panel: #121826;\\n --ink: #e6edf7;\\n --muted: #a5b3c8;\\n --accent: #4a7dff;\\n --accent-soft: rgba(74, 125, 255, 0.18);\\n --teal: #2db9c3;\\n --surface: #1a2232;\\n --border: rgba(230, 237, 247, 0.12);\\n --widget-bg:\\n linear-gradient(\\n 135deg,\\n #131a2a 0%,\\n #101525 60%,\\n #0d1220 100%);\\n --header-bg:\\n linear-gradient(\\n \\n 120deg,\\n rgba(18, 24, 38, 0.95),\\n rgba(23, 30, 48, 0.85) );\\n --composer-bg:\\n linear-gradient(\\n \\n 180deg,\\n rgba(18, 24, 38, 0) 0%,\\n rgba(18, 24, 38, 0.9) 80% );\\n --shadow: 0 28px 90px rgba(2, 7, 14, 0.65);\\n --glow:\\n radial-gradient(\\n circle,\\n rgba(74, 125, 255, 0.2) 0%,\\n rgba(74, 125, 255, 0) 70%);\\n --accent-glow: rgba(74, 125, 255, 0.28);\\n --bubble-user: #2f3e63;\\n --bubble-user-text: #f4f7ff;\\n --bubble-assistant: #1a2233;\\n --bubble-assistant-border: rgba(230, 237, 247, 0.1);\\n --bubble-system: rgba(230, 237, 247, 0.08);\\n --bubble-system-text: #b7c3d7;\\n --input-focus-border: rgba(74, 125, 255, 0.6);\\n --input-focus-shadow: rgba(74, 125, 255, 0.25);\\n --button-bg: #4a7dff;\\n --button-text: #f4f7ff;\\n --button-shadow: rgba(74, 125, 255, 0.35);\\n --pill-border: rgba(230, 237, 247, 0.24);\\n}\\n:global(.tw-widget)::before {\\n content: \\\"\\\";\\n position: absolute;\\n inset: -120px 40% auto -60px;\\n height: 220px;\\n background: var(--glow);\\n pointer-events: none;\\n}\\n:global(.tw-header) {\\n padding: 22px 26px 16px;\\n display: flex;\\n align-items: center;\\n justify-content: space-between;\\n background: var(--header-bg);\\n backdrop-filter: blur(12px);\\n}\\n:global(.tw-brand) {\\n display: flex;\\n flex-direction: column;\\n gap: 6px;\\n}\\n:global(.tw-brand-title) {\\n font-family: var(--font-display);\\n font-size: 24px;\\n letter-spacing: -0.02em;\\n}\\n:global(.tw-brand-subtitle) {\\n color: var(--muted);\\n font-size: 13px;\\n}\\n:global(.tw-status) {\\n display: inline-flex;\\n align-items: center;\\n gap: 8px;\\n padding: 6px 12px;\\n border-radius: 8px;\\n background: var(--accent-soft);\\n color: var(--ink);\\n font-size: 12px;\\n font-weight: 600;\\n}\\n:global(.tw-status-dot) {\\n width: 8px;\\n height: 8px;\\n border-radius: 50%;\\n background: var(--accent);\\n box-shadow: 0 0 0 4px var(--accent-glow);\\n}\\n:global(.tw-messages) {\\n padding: 16px 22px 8px;\\n display: flex;\\n flex-direction: column;\\n gap: 14px;\\n overflow-y: auto;\\n min-height: 0;\\n scroll-behavior: smooth;\\n}\\n:global(.tw-message) {\\n max-width: 85%;\\n padding: 14px 16px;\\n border-radius: 8px;\\n line-height: 1.45;\\n font-size: 14px;\\n animation: fadeUp 0.25s ease;\\n}\\n:global(.tw-message) p {\\n margin: 0;\\n}\\n:global(.tw-message) p + p {\\n margin-top: 8px;\\n}\\n:global(.tw-message) a {\\n color: var(--accent);\\n text-decoration: none;\\n font-weight: 600;\\n}\\n:global(.tw-message) a:hover {\\n text-decoration: underline;\\n}\\n:global(.tw-message) strong {\\n font-weight: 700;\\n}\\n:global(.tw-message) ul,\\n:global(.tw-message) ol {\\n margin: 8px 0 0;\\n padding-left: 18px;\\n}\\n:global(.tw-message) li {\\n margin: 4px 0;\\n}\\n:global(.tw-typing) {\\n display: inline-flex;\\n align-items: center;\\n gap: 6px;\\n min-height: 16px;\\n color: var(--muted);\\n}\\n:global(.tw-typing-dot) {\\n width: 6px;\\n height: 6px;\\n border-radius: 999px;\\n background: currentColor;\\n opacity: 0.6;\\n animation: typingBounce 1.2s infinite ease-in-out;\\n}\\n:global(.tw-typing-dot):nth-child(2) {\\n animation-delay: 0.2s;\\n}\\n:global(.tw-typing-dot):nth-child(3) {\\n animation-delay: 0.4s;\\n}\\n:global(.tw-sr-only) {\\n position: absolute;\\n width: 1px;\\n height: 1px;\\n padding: 0;\\n margin: -1px;\\n overflow: hidden;\\n clip: rect(0, 0, 0, 0);\\n border: 0;\\n}\\n:global(.tw-user) {\\n align-self: flex-end;\\n background: var(--bubble-user);\\n color: var(--bubble-user-text);\\n border-bottom-right-radius: 8px;\\n}\\n:global(.tw-assistant) {\\n align-self: flex-start;\\n background: var(--bubble-assistant);\\n border: 1px solid var(--bubble-assistant-border);\\n border-bottom-left-radius: 8px;\\n}\\n:global(.tw-system) {\\n align-self: center;\\n max-width: 92%;\\n text-align: center;\\n background: var(--bubble-system);\\n color: var(--bubble-system-text);\\n}\\n:global(.tw-composer) {\\n padding: 16px 22px 22px;\\n display: grid;\\n gap: 10px;\\n background: var(--composer-bg);\\n}\\n:global(.tw-input-wrap) {\\n display: flex;\\n gap: 10px;\\n align-items: flex-end;\\n}\\n:global(.tw-textarea) {\\n flex: 1;\\n min-height: 54px;\\n max-height: 140px;\\n padding: 14px 16px;\\n border-radius: 8px;\\n border: 1px solid var(--border);\\n background: var(--surface);\\n color: var(--ink);\\n resize: none;\\n font-family: inherit;\\n font-size: 14px;\\n outline: none;\\n transition: border 0.2s ease, box-shadow 0.2s ease;\\n}\\n:global(.tw-textarea)::placeholder {\\n color: var(--muted);\\n opacity: 0.85;\\n}\\n:global(.tw-textarea):focus {\\n border-color: var(--input-focus-border);\\n box-shadow: 0 0 0 3px var(--input-focus-shadow);\\n}\\n:global(.tw-send) {\\n border: none;\\n border-radius: 8px;\\n padding: 12px 18px;\\n background: var(--button-bg);\\n color: var(--button-text);\\n font-weight: 600;\\n cursor: pointer;\\n transition: transform 0.2s ease, box-shadow 0.2s ease;\\n}\\n:global(.tw-send):hover {\\n transform: translateY(-1px);\\n box-shadow: 0 12px 24px var(--button-shadow);\\n}\\n:global(.tw-send):disabled {\\n opacity: 0.5;\\n cursor: not-allowed;\\n transform: none;\\n box-shadow: none;\\n}\\n:global(.tw-meta) {\\n display: flex;\\n justify-content: space-between;\\n color: var(--muted);\\n font-size: 12px;\\n}\\n:global(.tw-pill-row) {\\n display: flex;\\n gap: 8px;\\n flex-wrap: wrap;\\n}\\n:global(.tw-pill) {\\n padding: 6px 10px;\\n border-radius: 8px;\\n border: 1px dashed var(--pill-border);\\n color: var(--muted);\\n font-size: 11px;\\n}\\n@keyframes fadeUp {\\n from {\\n opacity: 0;\\n transform: translateY(8px);\\n }\\n to {\\n opacity: 1;\\n transform: translateY(0);\\n }\\n}\\n@keyframes typingBounce {\\n 0%, 80%, 100% {\\n transform: translateY(0);\\n opacity: 0.4;\\n }\\n 40% {\\n transform: translateY(-4px);\\n opacity: 0.9;\\n }\\n}\\n@media (max-width: 720px) {\\n :global(.tw-widget) {\\n width: 100%;\\n height: 100vh;\\n border-radius: 12px;\\n }\\n}\\n\")","export type Translations = {\n titleDefault: string;\n subtitleDefault: string;\n systemMessage: string;\n statusStreaming: string;\n statusNeedsAttention: string;\n statusReady: string;\n thinking: string;\n pillSynthwave: string;\n pillSchedule: string;\n pillPlayNow: string;\n inputPlaceholder: string;\n sending: string;\n send: string;\n sessionReady: string;\n sessionRequesting: string;\n missingApiUrl: string;\n errorPrefix: string;\n errorMissingTokenUrl: string;\n errorFailedTokenFetch: string;\n errorMissingToken: string;\n errorTokenLoad: string;\n errorTokenUnavailable: string;\n errorServiceUnavailable: string;\n errorUnknown: string;\n errorUnexpected: string;\n};\n\nexport const en: Translations = {\n titleDefault: 'Tunio Assistant',\n subtitleDefault: 'Live on-air assistant',\n systemMessage: 'Tell me what station or playlist you want and I will set it up.',\n statusStreaming: 'Online',\n statusNeedsAttention: 'Online',\n statusReady: 'Online',\n thinking: 'Thinking...',\n pillSynthwave: '\"Create a synthwave radio\"',\n pillSchedule: '\"Schedule a rock playlist at 6 PM\"',\n pillPlayNow: '\"Set playlist to play now\"',\n inputPlaceholder: 'Tell me what to do on air...',\n sending: 'Working...',\n send: 'Send',\n sessionReady: 'Session ready',\n sessionRequesting: 'Requesting session...',\n missingApiUrl: 'Missing API URL',\n errorPrefix: 'Error:',\n errorMissingTokenUrl: 'Missing session token URL',\n errorFailedTokenFetch: 'Failed to fetch session token',\n errorMissingToken: 'Session token missing in response',\n errorTokenLoad: 'Failed to load token',\n errorTokenUnavailable: 'Session token is not available',\n errorServiceUnavailable: 'Agent service unavailable',\n errorUnknown: 'Unknown error',\n errorUnexpected: 'Unexpected error',\n};\n\nexport const ru: Translations = {\n titleDefault: 'Tunio Ассистент',\n subtitleDefault: 'Ассистент прямого эфира',\n systemMessage: 'Скажите, какую станцию или плейлист нужно поставить, и я все настрою.',\n statusStreaming: 'Онлайн',\n statusNeedsAttention: 'Онлайн',\n statusReady: 'Онлайн',\n thinking: 'Думаю...',\n pillSynthwave: '\"Создай синтвейв-радио\"',\n pillSchedule: '\"Запланируй рок-плейлист на 18:00\"',\n pillPlayNow: '\"Включи плейлист сейчас\"',\n inputPlaceholder: 'Скажи, что сделать в эфире...',\n sending: 'Выполняю...',\n send: 'Отправить',\n sessionReady: 'Сессия готова',\n sessionRequesting: 'Запрашиваем сессию...',\n missingApiUrl: 'Не задан API URL',\n errorPrefix: 'Ошибка:',\n errorMissingTokenUrl: 'Не задан URL токена сессии',\n errorFailedTokenFetch: 'Не удалось получить токен сессии',\n errorMissingToken: 'Токен сессии отсутствует в ответе',\n errorTokenLoad: 'Не удалось загрузить токен',\n errorTokenUnavailable: 'Токен сессии недоступен',\n errorServiceUnavailable: 'Сервис агента недоступен',\n errorUnknown: 'Неизвестная ошибка',\n errorUnexpected: 'Непредвиденная ошибка',\n};\n\nconst translations: Record<string, Translations> = {\n en,\n ru,\n};\n\nexport const getTranslations = (lang?: string): Translations => {\n if (!lang) return en;\n const normalized = lang.toLowerCase();\n if (translations[normalized]) return translations[normalized];\n const base = normalized.split('-')[0];\n return translations[base] ?? en;\n};\n"],"mappings":"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","names":["_a","_b","ReactMarkdown","remarkGfm"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/components/TunioWidget.tsx","#style-inject:#style-inject","../src/components/TunioWidget.module.css","../src/i18n/translations.ts"],"sourcesContent":["export { TunioWidget } from './components/TunioWidget';\nexport type { TunioWidgetProps } from './components/TunioWidget';\n","'use client';\n\nimport { useCallback, useEffect, useMemo, useRef, useState } from 'react';\nimport ReactMarkdown from 'react-markdown';\nimport remarkGfm from 'remark-gfm';\nimport './TunioWidget.module.css';\nimport { getTranslations } from '../i18n/translations';\n\ntype ChatMessage = {\n id: string;\n role: 'user' | 'assistant' | 'system';\n content: string;\n};\n\nexport type TunioWidgetProps = {\n apiUrl?: string;\n sessionTokenUrl?: string;\n lang?: string;\n getSessionToken?: () => Promise<string>;\n accessToken?: string;\n title?: string;\n subtitle?: string;\n theme?: 'light' | 'dark';\n className?: string;\n onNavigate?: (href: string) => void;\n};\n\nconst createId = () => Math.random().toString(36).slice(2);\n\nexport function TunioWidget({\n apiUrl,\n sessionTokenUrl,\n lang,\n getSessionToken,\n accessToken,\n title,\n subtitle,\n theme = 'light',\n className,\n onNavigate,\n}: TunioWidgetProps) {\n const [input, setInput] = useState('');\n const [isStreaming, setIsStreaming] = useState(false);\n const [error, setError] = useState<string | null>(null);\n const [sessionToken, setSessionToken] = useState<string | null>(null);\n const inputRef = useRef<HTMLTextAreaElement | null>(null);\n const messagesEndRef = useRef<HTMLDivElement | null>(null);\n\n const resolvedApiUrl = apiUrl ?? process.env.NEXT_PUBLIC_AGENT_API_URL ?? '';\n const resolvedTokenUrl =\n sessionTokenUrl ?? process.env.NEXT_PUBLIC_SESSION_TOKEN_URL ?? '';\n const resolvedUserLang = useMemo(() => {\n if (lang) return lang;\n if (typeof navigator !== 'undefined' && navigator.language) {\n return navigator.language.split('-')[0];\n }\n return undefined;\n }, [lang]);\n const i18n = useMemo(() => getTranslations(resolvedUserLang), [resolvedUserLang]);\n const [messages, setMessages] = useState<ChatMessage[]>(() => [\n {\n id: 'welcome',\n role: 'system',\n content: i18n.systemMessage,\n },\n ]);\n const hasUserMessage = useMemo(\n () => messages.some((message) => message.role === 'user'),\n [messages]\n );\n const displayTitle = title ?? i18n.titleDefault;\n const displaySubtitle = subtitle ?? i18n.subtitleDefault;\n\n const scrollToBottom = () => {\n messagesEndRef.current?.scrollIntoView({ behavior: 'smooth' });\n };\n\n useEffect(() => {\n scrollToBottom();\n }, [messages]);\n\n useEffect(() => {\n setMessages((prev) => {\n if (prev.length === 1 && prev[0].id === 'welcome' && prev[0].role === 'system') {\n return [{ ...prev[0], content: i18n.systemMessage }];\n }\n return prev;\n });\n }, [i18n.systemMessage]);\n\n const fetchSessionToken = useCallback(async () => {\n if (getSessionToken) {\n return getSessionToken();\n }\n\n if (accessToken) {\n return accessToken;\n }\n\n if (!resolvedTokenUrl) {\n throw new Error(i18n.errorMissingTokenUrl);\n }\n\n const response = await fetch(resolvedTokenUrl, {\n credentials: accessToken ? 'omit' : 'include',\n headers: accessToken ? { Authorization: `Bearer ${accessToken}` } : undefined,\n });\n\n if (!response.ok) {\n throw new Error(i18n.errorFailedTokenFetch);\n }\n\n const data = (await response.json()) as Record<string, unknown>;\n const token = data.session_token as string;\n\n if (!token) {\n throw new Error(i18n.errorMissingToken);\n }\n\n return token;\n }, [getSessionToken, i18n, resolvedTokenUrl]);\n\n useEffect(() => {\n fetchSessionToken()\n .then(setSessionToken)\n .catch((err) => {\n setError(err instanceof Error ? err.message : i18n.errorTokenLoad);\n });\n }, [fetchSessionToken, i18n.errorTokenLoad]);\n\n const statusLabel = useMemo(() => {\n if (isStreaming) return i18n.statusStreaming;\n if (error) return i18n.statusNeedsAttention;\n return i18n.statusReady;\n }, [error, i18n, isStreaming]);\n\n const handleLinkClick = useCallback(\n (href: string | undefined, event: React.MouseEvent<HTMLAnchorElement>) => {\n if (!href) return;\n const isInternal = href.startsWith('/') && !href.startsWith('//');\n if (isInternal && onNavigate) {\n event.preventDefault();\n onNavigate(href);\n }\n },\n [onNavigate]\n );\n\n const normalizeHref = useCallback((href: string | undefined) => {\n if (!href) return href;\n if (href.startsWith('/') || href.startsWith('#') || href.startsWith('?')) {\n return href;\n }\n if (href.startsWith('mailto:') || href.startsWith('tel:')) {\n return href;\n }\n if (typeof window === 'undefined') {\n return href;\n }\n try {\n const url = new URL(href);\n if (url.host === window.location.host) {\n return `${url.pathname}${url.search}${url.hash}`;\n }\n } catch {\n return href;\n }\n return href;\n }, []);\n\n const focusInput = () => {\n requestAnimationFrame(() => {\n inputRef.current?.focus();\n });\n };\n\n const sendMessage = async () => {\n if (isStreaming) {\n focusInput();\n return;\n }\n if (!input.trim() || !resolvedApiUrl) {\n focusInput();\n return;\n }\n if (!sessionToken) {\n setError(i18n.errorTokenUnavailable);\n focusInput();\n return;\n }\n\n setError(null);\n setIsStreaming(true);\n\n const userMessage: ChatMessage = {\n id: createId(),\n role: 'user',\n content: input.trim(),\n };\n\n const assistantMessage: ChatMessage = {\n id: createId(),\n role: 'assistant',\n content: '',\n };\n\n setMessages((prev) => [...prev, userMessage, assistantMessage]);\n setInput('');\n focusInput();\n\n try {\n const response = await fetch(resolvedApiUrl, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n message: userMessage.content,\n session_token: sessionToken,\n user_lang: resolvedUserLang,\n }),\n });\n\n if (!response.ok || !response.body) {\n throw new Error(i18n.errorServiceUnavailable);\n }\n\n const reader = response.body.getReader();\n const decoder = new TextDecoder();\n let buffer = '';\n\n while (true) {\n const { value, done } = await reader.read();\n if (done) break;\n buffer += decoder.decode(value, { stream: true });\n\n const parts = buffer.split('\\n\\n');\n buffer = parts.pop() ?? '';\n\n for (const part of parts) {\n const lines = part.split('\\n');\n let eventName = 'message';\n let data = '';\n\n for (const line of lines) {\n if (line.startsWith('event:')) {\n eventName = line.replace('event:', '').trim();\n }\n if (line.startsWith('data:')) {\n data += line.replace('data:', '').trim();\n }\n }\n\n if (!data) continue;\n\n if (eventName === 'message') {\n const payload = JSON.parse(data) as { content?: string };\n if (payload.content !== undefined) {\n setMessages((prev) => {\n const next = [...prev];\n const last = next[next.length - 1];\n if (last && last.role === 'assistant') {\n last.content = payload.content ?? '';\n }\n return next;\n });\n }\n }\n\n if (eventName === 'error') {\n const payload = JSON.parse(data) as { message?: string };\n setError(payload.message ?? i18n.errorUnknown);\n }\n }\n }\n } catch (err) {\n setError(err instanceof Error ? err.message : i18n.errorUnexpected);\n } finally {\n setIsStreaming(false);\n }\n };\n\n return (\n <section\n className={`tw-widget tw-${theme}${className ? ` ${className}` : ''}`}\n data-theme={theme}\n data-tunio-widget=\"root\"\n >\n <header className=\"tw-header\">\n <div className=\"tw-brand\">\n <div className=\"tw-brand-title\">{displayTitle}</div>\n <div className=\"tw-brand-subtitle\">{displaySubtitle}</div>\n </div>\n <div className=\"tw-status\">\n <span className=\"tw-status-dot\" />\n {statusLabel}\n </div>\n </header>\n\n <div className=\"tw-messages\">\n {messages.map((message) => (\n <div\n key={message.id}\n className={`tw-message tw-${message.role}`}\n >\n {message.content ? (\n <ReactMarkdown\n remarkPlugins={[remarkGfm]}\n components={{\n a: ({ href, children, ...props }) => {\n const normalizedHref = normalizeHref(href);\n const isInternal =\n typeof normalizedHref === 'string' &&\n normalizedHref.startsWith('/') &&\n !normalizedHref.startsWith('//');\n return (\n <a\n {...props}\n href={normalizedHref}\n onClick={(event) => handleLinkClick(normalizedHref, event)}\n target={isInternal ? undefined : '_blank'}\n rel={isInternal ? undefined : 'noreferrer'}\n >\n {children}\n </a>\n );\n },\n }}\n >\n {message.content}\n </ReactMarkdown>\n ) : message.role === 'assistant' ? (\n <span className=\"tw-typing\" role=\"status\" aria-label={i18n.thinking}>\n <span className=\"tw-typing-dot\" />\n <span className=\"tw-typing-dot\" />\n <span className=\"tw-typing-dot\" />\n <span className=\"tw-sr-only\">{i18n.thinking}</span>\n </span>\n ) : (\n ''\n )}\n </div>\n ))}\n <div ref={messagesEndRef} />\n </div>\n\n <div className=\"tw-composer\">\n {!hasUserMessage ? (\n <div className=\"tw-pill-row\">\n <span className=\"tw-pill\">{i18n.pillSynthwave}</span>\n <span className=\"tw-pill\">{i18n.pillSchedule}</span>\n <span className=\"tw-pill\">{i18n.pillPlayNow}</span>\n </div>\n ) : null}\n <div className=\"tw-input-wrap\">\n <textarea\n className=\"tw-textarea\"\n placeholder={i18n.inputPlaceholder}\n value={input}\n onChange={(event) => setInput(event.target.value)}\n onKeyDown={(event) => {\n if (event.nativeEvent.isComposing) return;\n if (event.key !== 'Enter') return;\n if (event.shiftKey) return;\n event.preventDefault();\n sendMessage();\n }}\n rows={2}\n ref={inputRef}\n />\n <button\n className=\"tw-send\"\n onClick={sendMessage}\n disabled={isStreaming || !input.trim()}\n >\n {isStreaming ? i18n.sending : i18n.send}\n </button>\n </div>\n {error ? (\n <div className=\"tw-meta\">\n {i18n.errorPrefix} {error}\n </div>\n ) : null}\n </div>\n </section>\n );\n}\n","\n export default function styleInject(css, { insertAt } = {}) {\n if (!css || typeof document === 'undefined') return\n \n const head = document.head || document.getElementsByTagName('head')[0]\n const style = document.createElement('style')\n style.type = 'text/css'\n \n if (insertAt === 'top') {\n if (head.firstChild) {\n head.insertBefore(style, head.firstChild)\n } else {\n head.appendChild(style)\n }\n } else {\n head.appendChild(style)\n }\n \n if (style.styleSheet) {\n style.styleSheet.cssText = css\n } else {\n style.appendChild(document.createTextNode(css))\n }\n }\n ","import styleInject from '#style-inject';styleInject(\".tw-widget {\\n --panel: #f7f9fc;\\n --ink: #1b2430;\\n --muted: #6c7a90;\\n --accent: #3f6df6;\\n --accent-soft: rgba(63, 109, 246, 0.14);\\n --teal: #21b3a8;\\n --surface: #ffffff;\\n --border: rgba(16, 24, 40, 0.12);\\n --widget-bg:\\n linear-gradient(\\n 135deg,\\n #f9fbff 0%,\\n #eef2f8 60%,\\n #e8edf6 100%);\\n --header-bg:\\n linear-gradient(\\n \\n 120deg,\\n rgba(255, 255, 255, 0.92),\\n rgba(243, 246, 252, 0.82) );\\n --composer-bg:\\n linear-gradient(\\n \\n 180deg,\\n rgba(255, 255, 255, 0) 0%,\\n rgba(244, 246, 252, 0.92) 80% );\\n --shadow: 0 24px 70px rgba(18, 24, 40, 0.18);\\n --glow:\\n radial-gradient(\\n circle,\\n rgba(63, 109, 246, 0.18) 0%,\\n rgba(63, 109, 246, 0) 70%);\\n --accent-glow: rgba(63, 109, 246, 0.2);\\n --bubble-user: #1b2430;\\n --bubble-user-text: #f7f9ff;\\n --bubble-assistant: #ffffff;\\n --bubble-assistant-border: rgba(16, 24, 40, 0.08);\\n --bubble-system: rgba(27, 36, 48, 0.08);\\n --bubble-system-text: #6c7a90;\\n --input-focus-border: rgba(63, 109, 246, 0.6);\\n --input-focus-shadow: rgba(63, 109, 246, 0.2);\\n --button-bg: #1b2430;\\n --button-text: #f7f9ff;\\n --button-shadow: rgba(27, 36, 48, 0.2);\\n --pill-border: rgba(16, 24, 40, 0.2);\\n display: grid;\\n grid-template-rows: auto minmax(0, 1fr) auto;\\n width: min(100%, 420px);\\n height: min(80vh, 640px);\\n min-height: 520px;\\n border-radius: 12px;\\n background: var(--widget-bg);\\n border: 1px solid var(--border);\\n box-shadow: var(--shadow);\\n color: var(--ink);\\n overflow: hidden;\\n position: relative;\\n}\\n.tw-light {\\n color-scheme: light;\\n}\\n.tw-dark {\\n color-scheme: dark;\\n --panel: #121826;\\n --ink: #e6edf7;\\n --muted: #a5b3c8;\\n --accent: #4a7dff;\\n --accent-soft: rgba(74, 125, 255, 0.18);\\n --teal: #2db9c3;\\n --surface: #1a2232;\\n --border: rgba(230, 237, 247, 0.12);\\n --widget-bg:\\n linear-gradient(\\n 135deg,\\n #131a2a 0%,\\n #101525 60%,\\n #0d1220 100%);\\n --header-bg:\\n linear-gradient(\\n \\n 120deg,\\n rgba(18, 24, 38, 0.95),\\n rgba(23, 30, 48, 0.85) );\\n --composer-bg:\\n linear-gradient(\\n \\n 180deg,\\n rgba(18, 24, 38, 0) 0%,\\n rgba(18, 24, 38, 0.9) 80% );\\n --shadow: 0 28px 90px rgba(2, 7, 14, 0.65);\\n --glow:\\n radial-gradient(\\n circle,\\n rgba(74, 125, 255, 0.2) 0%,\\n rgba(74, 125, 255, 0) 70%);\\n --accent-glow: rgba(74, 125, 255, 0.28);\\n --bubble-user: #2f3e63;\\n --bubble-user-text: #f4f7ff;\\n --bubble-assistant: #1a2233;\\n --bubble-assistant-border: rgba(230, 237, 247, 0.1);\\n --bubble-system: rgba(230, 237, 247, 0.08);\\n --bubble-system-text: #b7c3d7;\\n --input-focus-border: rgba(74, 125, 255, 0.6);\\n --input-focus-shadow: rgba(74, 125, 255, 0.25);\\n --button-bg: #4a7dff;\\n --button-text: #f4f7ff;\\n --button-shadow: rgba(74, 125, 255, 0.35);\\n --pill-border: rgba(230, 237, 247, 0.24);\\n}\\n.tw-widget::before {\\n content: \\\"\\\";\\n position: absolute;\\n inset: -120px 40% auto -60px;\\n height: 220px;\\n background: var(--glow);\\n pointer-events: none;\\n}\\n.tw-header {\\n padding: 22px 26px 16px;\\n display: flex;\\n align-items: center;\\n justify-content: space-between;\\n background: var(--header-bg);\\n backdrop-filter: blur(12px);\\n}\\n.tw-brand {\\n display: flex;\\n flex-direction: column;\\n gap: 6px;\\n}\\n.tw-brand-title {\\n font-family: var(--font-display);\\n font-size: 24px;\\n letter-spacing: -0.02em;\\n}\\n.tw-brand-subtitle {\\n color: var(--muted);\\n font-size: 13px;\\n}\\n.tw-status {\\n display: inline-flex;\\n align-items: center;\\n gap: 8px;\\n padding: 6px 12px;\\n border-radius: 8px;\\n background: var(--accent-soft);\\n color: var(--ink);\\n font-size: 12px;\\n font-weight: 600;\\n}\\n.tw-status-dot {\\n width: 8px;\\n height: 8px;\\n border-radius: 50%;\\n background: var(--accent);\\n box-shadow: 0 0 0 4px var(--accent-glow);\\n}\\n.tw-messages {\\n padding: 16px 22px 8px;\\n display: flex;\\n flex-direction: column;\\n gap: 14px;\\n overflow-y: auto;\\n min-height: 0;\\n scroll-behavior: smooth;\\n}\\n.tw-message {\\n max-width: 85%;\\n padding: 14px 16px;\\n border-radius: 8px;\\n line-height: 1.45;\\n font-size: 14px;\\n animation: fadeUp 0.25s ease;\\n}\\n.tw-message p {\\n margin: 0;\\n}\\n.tw-message p + p {\\n margin-top: 8px;\\n}\\n.tw-message a {\\n color: var(--accent);\\n text-decoration: none;\\n font-weight: 600;\\n}\\n.tw-message a:hover {\\n text-decoration: underline;\\n}\\n.tw-message strong {\\n font-weight: 700;\\n}\\n.tw-message ul,\\n.tw-message ol {\\n margin: 8px 0 0;\\n padding-left: 18px;\\n}\\n.tw-message li {\\n margin: 4px 0;\\n}\\n.tw-typing {\\n display: inline-flex;\\n align-items: center;\\n gap: 6px;\\n min-height: 16px;\\n color: var(--muted);\\n}\\n.tw-typing-dot {\\n width: 6px;\\n height: 6px;\\n border-radius: 999px;\\n background: currentColor;\\n opacity: 0.6;\\n animation: typingBounce 1.2s infinite ease-in-out;\\n}\\n.tw-typing-dot:nth-child(2) {\\n animation-delay: 0.2s;\\n}\\n.tw-typing-dot:nth-child(3) {\\n animation-delay: 0.4s;\\n}\\n.tw-sr-only {\\n position: absolute;\\n width: 1px;\\n height: 1px;\\n padding: 0;\\n margin: -1px;\\n overflow: hidden;\\n clip: rect(0, 0, 0, 0);\\n border: 0;\\n}\\n.tw-user {\\n align-self: flex-end;\\n background: var(--bubble-user);\\n color: var(--bubble-user-text);\\n border-bottom-right-radius: 8px;\\n}\\n.tw-assistant {\\n align-self: flex-start;\\n background: var(--bubble-assistant);\\n border: 1px solid var(--bubble-assistant-border);\\n border-bottom-left-radius: 8px;\\n}\\n.tw-system {\\n align-self: center;\\n max-width: 92%;\\n text-align: center;\\n background: var(--bubble-system);\\n color: var(--bubble-system-text);\\n}\\n.tw-composer {\\n padding: 16px 22px 22px;\\n display: grid;\\n gap: 10px;\\n background: var(--composer-bg);\\n}\\n.tw-input-wrap {\\n display: flex;\\n gap: 10px;\\n align-items: flex-end;\\n}\\n.tw-textarea {\\n flex: 1;\\n min-height: 54px;\\n max-height: 140px;\\n padding: 14px 16px;\\n border-radius: 8px;\\n border: 1px solid var(--border);\\n background: var(--surface);\\n color: var(--ink);\\n resize: none;\\n font-family: inherit;\\n font-size: 14px;\\n outline: none;\\n transition: border 0.2s ease, box-shadow 0.2s ease;\\n}\\n.tw-textarea::placeholder {\\n color: var(--muted);\\n opacity: 0.85;\\n}\\n.tw-textarea:focus {\\n border-color: var(--input-focus-border);\\n box-shadow: 0 0 0 3px var(--input-focus-shadow);\\n}\\n.tw-send {\\n border: none;\\n border-radius: 8px;\\n padding: 12px 18px;\\n background: var(--button-bg);\\n color: var(--button-text);\\n font-weight: 600;\\n cursor: pointer;\\n transition: transform 0.2s ease, box-shadow 0.2s ease;\\n}\\n.tw-send:hover {\\n transform: translateY(-1px);\\n box-shadow: 0 12px 24px var(--button-shadow);\\n}\\n.tw-send:disabled {\\n opacity: 0.5;\\n cursor: not-allowed;\\n transform: none;\\n box-shadow: none;\\n}\\n.tw-meta {\\n display: flex;\\n justify-content: space-between;\\n color: var(--muted);\\n font-size: 12px;\\n}\\n.tw-pill-row {\\n display: flex;\\n gap: 8px;\\n flex-wrap: wrap;\\n}\\n.tw-pill {\\n padding: 6px 10px;\\n border-radius: 8px;\\n border: 1px dashed var(--pill-border);\\n color: var(--muted);\\n font-size: 11px;\\n}\\n@keyframes fadeUp {\\n from {\\n opacity: 0;\\n transform: translateY(8px);\\n }\\n to {\\n opacity: 1;\\n transform: translateY(0);\\n }\\n}\\n@keyframes typingBounce {\\n 0%, 80%, 100% {\\n transform: translateY(0);\\n opacity: 0.4;\\n }\\n 40% {\\n transform: translateY(-4px);\\n opacity: 0.9;\\n }\\n}\\n@media (max-width: 720px) {\\n .tw-widget {\\n width: 100%;\\n height: 100vh;\\n border-radius: 12px;\\n }\\n}\\n\")","export type Translations = {\n titleDefault: string;\n subtitleDefault: string;\n systemMessage: string;\n statusStreaming: string;\n statusNeedsAttention: string;\n statusReady: string;\n thinking: string;\n pillSynthwave: string;\n pillSchedule: string;\n pillPlayNow: string;\n inputPlaceholder: string;\n sending: string;\n send: string;\n sessionReady: string;\n sessionRequesting: string;\n missingApiUrl: string;\n errorPrefix: string;\n errorMissingTokenUrl: string;\n errorFailedTokenFetch: string;\n errorMissingToken: string;\n errorTokenLoad: string;\n errorTokenUnavailable: string;\n errorServiceUnavailable: string;\n errorUnknown: string;\n errorUnexpected: string;\n};\n\nexport const en: Translations = {\n titleDefault: 'Tunio Assistant',\n subtitleDefault: 'Live on-air assistant',\n systemMessage: 'Tell me what station or playlist you want and I will set it up.',\n statusStreaming: 'Online',\n statusNeedsAttention: 'Online',\n statusReady: 'Online',\n thinking: 'Thinking...',\n pillSynthwave: '\"Create a synthwave radio\"',\n pillSchedule: '\"Schedule a rock playlist at 6 PM\"',\n pillPlayNow: '\"Set playlist to play now\"',\n inputPlaceholder: 'Tell me what to do on air...',\n sending: 'Working...',\n send: 'Send',\n sessionReady: 'Session ready',\n sessionRequesting: 'Requesting session...',\n missingApiUrl: 'Missing API URL',\n errorPrefix: 'Error:',\n errorMissingTokenUrl: 'Missing session token URL',\n errorFailedTokenFetch: 'Failed to fetch session token',\n errorMissingToken: 'Session token missing in response',\n errorTokenLoad: 'Failed to load token',\n errorTokenUnavailable: 'Session token is not available',\n errorServiceUnavailable: 'Agent service unavailable',\n errorUnknown: 'Unknown error',\n errorUnexpected: 'Unexpected error',\n};\n\nexport const ru: Translations = {\n titleDefault: 'Tunio Ассистент',\n subtitleDefault: 'Ассистент прямого эфира',\n systemMessage: 'Скажите, какую станцию или плейлист нужно поставить, и я все настрою.',\n statusStreaming: 'Онлайн',\n statusNeedsAttention: 'Онлайн',\n statusReady: 'Онлайн',\n thinking: 'Думаю...',\n pillSynthwave: '\"Создай синтвейв-радио\"',\n pillSchedule: '\"Запланируй рок-плейлист на 18:00\"',\n pillPlayNow: '\"Включи плейлист сейчас\"',\n inputPlaceholder: 'Скажи, что сделать в эфире...',\n sending: 'Выполняю...',\n send: 'Отправить',\n sessionReady: 'Сессия готова',\n sessionRequesting: 'Запрашиваем сессию...',\n missingApiUrl: 'Не задан API URL',\n errorPrefix: 'Ошибка:',\n errorMissingTokenUrl: 'Не задан URL токена сессии',\n errorFailedTokenFetch: 'Не удалось получить токен сессии',\n errorMissingToken: 'Токен сессии отсутствует в ответе',\n errorTokenLoad: 'Не удалось загрузить токен',\n errorTokenUnavailable: 'Токен сессии недоступен',\n errorServiceUnavailable: 'Сервис агента недоступен',\n errorUnknown: 'Неизвестная ошибка',\n errorUnexpected: 'Непредвиденная ошибка',\n};\n\nconst translations: Record<string, Translations> = {\n en,\n ru,\n};\n\nexport const getTranslations = (lang?: string): Translations => {\n if (!lang) return en;\n const normalized = lang.toLowerCase();\n if (translations[normalized]) return translations[normalized];\n const base = normalized.split('-')[0];\n return translations[base] ?? en;\n};\n"],"mappings":"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","names":["_a","_b","ReactMarkdown","remarkGfm"]}
package/dist/index.mjs CHANGED
@@ -26,7 +26,7 @@ function styleInject(css, { insertAt } = {}) {
26
26
  }
27
27
 
28
28
  // src/components/TunioWidget.module.css
29
- styleInject(':global(.tw-widget) {\n --panel: #f7f9fc;\n --ink: #1b2430;\n --muted: #6c7a90;\n --accent: #3f6df6;\n --accent-soft: rgba(63, 109, 246, 0.14);\n --teal: #21b3a8;\n --surface: #ffffff;\n --border: rgba(16, 24, 40, 0.12);\n --widget-bg:\n linear-gradient(\n 135deg,\n #f9fbff 0%,\n #eef2f8 60%,\n #e8edf6 100%);\n --header-bg:\n linear-gradient(\n \n 120deg,\n rgba(255, 255, 255, 0.92),\n rgba(243, 246, 252, 0.82) );\n --composer-bg:\n linear-gradient(\n \n 180deg,\n rgba(255, 255, 255, 0) 0%,\n rgba(244, 246, 252, 0.92) 80% );\n --shadow: 0 24px 70px rgba(18, 24, 40, 0.18);\n --glow:\n radial-gradient(\n circle,\n rgba(63, 109, 246, 0.18) 0%,\n rgba(63, 109, 246, 0) 70%);\n --accent-glow: rgba(63, 109, 246, 0.2);\n --bubble-user: #1b2430;\n --bubble-user-text: #f7f9ff;\n --bubble-assistant: #ffffff;\n --bubble-assistant-border: rgba(16, 24, 40, 0.08);\n --bubble-system: rgba(27, 36, 48, 0.08);\n --bubble-system-text: #6c7a90;\n --input-focus-border: rgba(63, 109, 246, 0.6);\n --input-focus-shadow: rgba(63, 109, 246, 0.2);\n --button-bg: #1b2430;\n --button-text: #f7f9ff;\n --button-shadow: rgba(27, 36, 48, 0.2);\n --pill-border: rgba(16, 24, 40, 0.2);\n display: grid;\n grid-template-rows: auto minmax(0, 1fr) auto;\n width: min(100%, 420px);\n height: min(80vh, 640px);\n min-height: 520px;\n border-radius: 12px;\n background: var(--widget-bg);\n border: 1px solid var(--border);\n box-shadow: var(--shadow);\n color: var(--ink);\n overflow: hidden;\n position: relative;\n}\n:global(.tw-light) {\n color-scheme: light;\n}\n:global(.tw-dark) {\n color-scheme: dark;\n --panel: #121826;\n --ink: #e6edf7;\n --muted: #a5b3c8;\n --accent: #4a7dff;\n --accent-soft: rgba(74, 125, 255, 0.18);\n --teal: #2db9c3;\n --surface: #1a2232;\n --border: rgba(230, 237, 247, 0.12);\n --widget-bg:\n linear-gradient(\n 135deg,\n #131a2a 0%,\n #101525 60%,\n #0d1220 100%);\n --header-bg:\n linear-gradient(\n \n 120deg,\n rgba(18, 24, 38, 0.95),\n rgba(23, 30, 48, 0.85) );\n --composer-bg:\n linear-gradient(\n \n 180deg,\n rgba(18, 24, 38, 0) 0%,\n rgba(18, 24, 38, 0.9) 80% );\n --shadow: 0 28px 90px rgba(2, 7, 14, 0.65);\n --glow:\n radial-gradient(\n circle,\n rgba(74, 125, 255, 0.2) 0%,\n rgba(74, 125, 255, 0) 70%);\n --accent-glow: rgba(74, 125, 255, 0.28);\n --bubble-user: #2f3e63;\n --bubble-user-text: #f4f7ff;\n --bubble-assistant: #1a2233;\n --bubble-assistant-border: rgba(230, 237, 247, 0.1);\n --bubble-system: rgba(230, 237, 247, 0.08);\n --bubble-system-text: #b7c3d7;\n --input-focus-border: rgba(74, 125, 255, 0.6);\n --input-focus-shadow: rgba(74, 125, 255, 0.25);\n --button-bg: #4a7dff;\n --button-text: #f4f7ff;\n --button-shadow: rgba(74, 125, 255, 0.35);\n --pill-border: rgba(230, 237, 247, 0.24);\n}\n:global(.tw-widget)::before {\n content: "";\n position: absolute;\n inset: -120px 40% auto -60px;\n height: 220px;\n background: var(--glow);\n pointer-events: none;\n}\n:global(.tw-header) {\n padding: 22px 26px 16px;\n display: flex;\n align-items: center;\n justify-content: space-between;\n background: var(--header-bg);\n backdrop-filter: blur(12px);\n}\n:global(.tw-brand) {\n display: flex;\n flex-direction: column;\n gap: 6px;\n}\n:global(.tw-brand-title) {\n font-family: var(--font-display);\n font-size: 24px;\n letter-spacing: -0.02em;\n}\n:global(.tw-brand-subtitle) {\n color: var(--muted);\n font-size: 13px;\n}\n:global(.tw-status) {\n display: inline-flex;\n align-items: center;\n gap: 8px;\n padding: 6px 12px;\n border-radius: 8px;\n background: var(--accent-soft);\n color: var(--ink);\n font-size: 12px;\n font-weight: 600;\n}\n:global(.tw-status-dot) {\n width: 8px;\n height: 8px;\n border-radius: 50%;\n background: var(--accent);\n box-shadow: 0 0 0 4px var(--accent-glow);\n}\n:global(.tw-messages) {\n padding: 16px 22px 8px;\n display: flex;\n flex-direction: column;\n gap: 14px;\n overflow-y: auto;\n min-height: 0;\n scroll-behavior: smooth;\n}\n:global(.tw-message) {\n max-width: 85%;\n padding: 14px 16px;\n border-radius: 8px;\n line-height: 1.45;\n font-size: 14px;\n animation: fadeUp 0.25s ease;\n}\n:global(.tw-message) p {\n margin: 0;\n}\n:global(.tw-message) p + p {\n margin-top: 8px;\n}\n:global(.tw-message) a {\n color: var(--accent);\n text-decoration: none;\n font-weight: 600;\n}\n:global(.tw-message) a:hover {\n text-decoration: underline;\n}\n:global(.tw-message) strong {\n font-weight: 700;\n}\n:global(.tw-message) ul,\n:global(.tw-message) ol {\n margin: 8px 0 0;\n padding-left: 18px;\n}\n:global(.tw-message) li {\n margin: 4px 0;\n}\n:global(.tw-typing) {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n min-height: 16px;\n color: var(--muted);\n}\n:global(.tw-typing-dot) {\n width: 6px;\n height: 6px;\n border-radius: 999px;\n background: currentColor;\n opacity: 0.6;\n animation: typingBounce 1.2s infinite ease-in-out;\n}\n:global(.tw-typing-dot):nth-child(2) {\n animation-delay: 0.2s;\n}\n:global(.tw-typing-dot):nth-child(3) {\n animation-delay: 0.4s;\n}\n:global(.tw-sr-only) {\n position: absolute;\n width: 1px;\n height: 1px;\n padding: 0;\n margin: -1px;\n overflow: hidden;\n clip: rect(0, 0, 0, 0);\n border: 0;\n}\n:global(.tw-user) {\n align-self: flex-end;\n background: var(--bubble-user);\n color: var(--bubble-user-text);\n border-bottom-right-radius: 8px;\n}\n:global(.tw-assistant) {\n align-self: flex-start;\n background: var(--bubble-assistant);\n border: 1px solid var(--bubble-assistant-border);\n border-bottom-left-radius: 8px;\n}\n:global(.tw-system) {\n align-self: center;\n max-width: 92%;\n text-align: center;\n background: var(--bubble-system);\n color: var(--bubble-system-text);\n}\n:global(.tw-composer) {\n padding: 16px 22px 22px;\n display: grid;\n gap: 10px;\n background: var(--composer-bg);\n}\n:global(.tw-input-wrap) {\n display: flex;\n gap: 10px;\n align-items: flex-end;\n}\n:global(.tw-textarea) {\n flex: 1;\n min-height: 54px;\n max-height: 140px;\n padding: 14px 16px;\n border-radius: 8px;\n border: 1px solid var(--border);\n background: var(--surface);\n color: var(--ink);\n resize: none;\n font-family: inherit;\n font-size: 14px;\n outline: none;\n transition: border 0.2s ease, box-shadow 0.2s ease;\n}\n:global(.tw-textarea)::placeholder {\n color: var(--muted);\n opacity: 0.85;\n}\n:global(.tw-textarea):focus {\n border-color: var(--input-focus-border);\n box-shadow: 0 0 0 3px var(--input-focus-shadow);\n}\n:global(.tw-send) {\n border: none;\n border-radius: 8px;\n padding: 12px 18px;\n background: var(--button-bg);\n color: var(--button-text);\n font-weight: 600;\n cursor: pointer;\n transition: transform 0.2s ease, box-shadow 0.2s ease;\n}\n:global(.tw-send):hover {\n transform: translateY(-1px);\n box-shadow: 0 12px 24px var(--button-shadow);\n}\n:global(.tw-send):disabled {\n opacity: 0.5;\n cursor: not-allowed;\n transform: none;\n box-shadow: none;\n}\n:global(.tw-meta) {\n display: flex;\n justify-content: space-between;\n color: var(--muted);\n font-size: 12px;\n}\n:global(.tw-pill-row) {\n display: flex;\n gap: 8px;\n flex-wrap: wrap;\n}\n:global(.tw-pill) {\n padding: 6px 10px;\n border-radius: 8px;\n border: 1px dashed var(--pill-border);\n color: var(--muted);\n font-size: 11px;\n}\n@keyframes fadeUp {\n from {\n opacity: 0;\n transform: translateY(8px);\n }\n to {\n opacity: 1;\n transform: translateY(0);\n }\n}\n@keyframes typingBounce {\n 0%, 80%, 100% {\n transform: translateY(0);\n opacity: 0.4;\n }\n 40% {\n transform: translateY(-4px);\n opacity: 0.9;\n }\n}\n@media (max-width: 720px) {\n :global(.tw-widget) {\n width: 100%;\n height: 100vh;\n border-radius: 12px;\n }\n}\n');
29
+ styleInject('.tw-widget {\n --panel: #f7f9fc;\n --ink: #1b2430;\n --muted: #6c7a90;\n --accent: #3f6df6;\n --accent-soft: rgba(63, 109, 246, 0.14);\n --teal: #21b3a8;\n --surface: #ffffff;\n --border: rgba(16, 24, 40, 0.12);\n --widget-bg:\n linear-gradient(\n 135deg,\n #f9fbff 0%,\n #eef2f8 60%,\n #e8edf6 100%);\n --header-bg:\n linear-gradient(\n \n 120deg,\n rgba(255, 255, 255, 0.92),\n rgba(243, 246, 252, 0.82) );\n --composer-bg:\n linear-gradient(\n \n 180deg,\n rgba(255, 255, 255, 0) 0%,\n rgba(244, 246, 252, 0.92) 80% );\n --shadow: 0 24px 70px rgba(18, 24, 40, 0.18);\n --glow:\n radial-gradient(\n circle,\n rgba(63, 109, 246, 0.18) 0%,\n rgba(63, 109, 246, 0) 70%);\n --accent-glow: rgba(63, 109, 246, 0.2);\n --bubble-user: #1b2430;\n --bubble-user-text: #f7f9ff;\n --bubble-assistant: #ffffff;\n --bubble-assistant-border: rgba(16, 24, 40, 0.08);\n --bubble-system: rgba(27, 36, 48, 0.08);\n --bubble-system-text: #6c7a90;\n --input-focus-border: rgba(63, 109, 246, 0.6);\n --input-focus-shadow: rgba(63, 109, 246, 0.2);\n --button-bg: #1b2430;\n --button-text: #f7f9ff;\n --button-shadow: rgba(27, 36, 48, 0.2);\n --pill-border: rgba(16, 24, 40, 0.2);\n display: grid;\n grid-template-rows: auto minmax(0, 1fr) auto;\n width: min(100%, 420px);\n height: min(80vh, 640px);\n min-height: 520px;\n border-radius: 12px;\n background: var(--widget-bg);\n border: 1px solid var(--border);\n box-shadow: var(--shadow);\n color: var(--ink);\n overflow: hidden;\n position: relative;\n}\n.tw-light {\n color-scheme: light;\n}\n.tw-dark {\n color-scheme: dark;\n --panel: #121826;\n --ink: #e6edf7;\n --muted: #a5b3c8;\n --accent: #4a7dff;\n --accent-soft: rgba(74, 125, 255, 0.18);\n --teal: #2db9c3;\n --surface: #1a2232;\n --border: rgba(230, 237, 247, 0.12);\n --widget-bg:\n linear-gradient(\n 135deg,\n #131a2a 0%,\n #101525 60%,\n #0d1220 100%);\n --header-bg:\n linear-gradient(\n \n 120deg,\n rgba(18, 24, 38, 0.95),\n rgba(23, 30, 48, 0.85) );\n --composer-bg:\n linear-gradient(\n \n 180deg,\n rgba(18, 24, 38, 0) 0%,\n rgba(18, 24, 38, 0.9) 80% );\n --shadow: 0 28px 90px rgba(2, 7, 14, 0.65);\n --glow:\n radial-gradient(\n circle,\n rgba(74, 125, 255, 0.2) 0%,\n rgba(74, 125, 255, 0) 70%);\n --accent-glow: rgba(74, 125, 255, 0.28);\n --bubble-user: #2f3e63;\n --bubble-user-text: #f4f7ff;\n --bubble-assistant: #1a2233;\n --bubble-assistant-border: rgba(230, 237, 247, 0.1);\n --bubble-system: rgba(230, 237, 247, 0.08);\n --bubble-system-text: #b7c3d7;\n --input-focus-border: rgba(74, 125, 255, 0.6);\n --input-focus-shadow: rgba(74, 125, 255, 0.25);\n --button-bg: #4a7dff;\n --button-text: #f4f7ff;\n --button-shadow: rgba(74, 125, 255, 0.35);\n --pill-border: rgba(230, 237, 247, 0.24);\n}\n.tw-widget::before {\n content: "";\n position: absolute;\n inset: -120px 40% auto -60px;\n height: 220px;\n background: var(--glow);\n pointer-events: none;\n}\n.tw-header {\n padding: 22px 26px 16px;\n display: flex;\n align-items: center;\n justify-content: space-between;\n background: var(--header-bg);\n backdrop-filter: blur(12px);\n}\n.tw-brand {\n display: flex;\n flex-direction: column;\n gap: 6px;\n}\n.tw-brand-title {\n font-family: var(--font-display);\n font-size: 24px;\n letter-spacing: -0.02em;\n}\n.tw-brand-subtitle {\n color: var(--muted);\n font-size: 13px;\n}\n.tw-status {\n display: inline-flex;\n align-items: center;\n gap: 8px;\n padding: 6px 12px;\n border-radius: 8px;\n background: var(--accent-soft);\n color: var(--ink);\n font-size: 12px;\n font-weight: 600;\n}\n.tw-status-dot {\n width: 8px;\n height: 8px;\n border-radius: 50%;\n background: var(--accent);\n box-shadow: 0 0 0 4px var(--accent-glow);\n}\n.tw-messages {\n padding: 16px 22px 8px;\n display: flex;\n flex-direction: column;\n gap: 14px;\n overflow-y: auto;\n min-height: 0;\n scroll-behavior: smooth;\n}\n.tw-message {\n max-width: 85%;\n padding: 14px 16px;\n border-radius: 8px;\n line-height: 1.45;\n font-size: 14px;\n animation: fadeUp 0.25s ease;\n}\n.tw-message p {\n margin: 0;\n}\n.tw-message p + p {\n margin-top: 8px;\n}\n.tw-message a {\n color: var(--accent);\n text-decoration: none;\n font-weight: 600;\n}\n.tw-message a:hover {\n text-decoration: underline;\n}\n.tw-message strong {\n font-weight: 700;\n}\n.tw-message ul,\n.tw-message ol {\n margin: 8px 0 0;\n padding-left: 18px;\n}\n.tw-message li {\n margin: 4px 0;\n}\n.tw-typing {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n min-height: 16px;\n color: var(--muted);\n}\n.tw-typing-dot {\n width: 6px;\n height: 6px;\n border-radius: 999px;\n background: currentColor;\n opacity: 0.6;\n animation: typingBounce 1.2s infinite ease-in-out;\n}\n.tw-typing-dot:nth-child(2) {\n animation-delay: 0.2s;\n}\n.tw-typing-dot:nth-child(3) {\n animation-delay: 0.4s;\n}\n.tw-sr-only {\n position: absolute;\n width: 1px;\n height: 1px;\n padding: 0;\n margin: -1px;\n overflow: hidden;\n clip: rect(0, 0, 0, 0);\n border: 0;\n}\n.tw-user {\n align-self: flex-end;\n background: var(--bubble-user);\n color: var(--bubble-user-text);\n border-bottom-right-radius: 8px;\n}\n.tw-assistant {\n align-self: flex-start;\n background: var(--bubble-assistant);\n border: 1px solid var(--bubble-assistant-border);\n border-bottom-left-radius: 8px;\n}\n.tw-system {\n align-self: center;\n max-width: 92%;\n text-align: center;\n background: var(--bubble-system);\n color: var(--bubble-system-text);\n}\n.tw-composer {\n padding: 16px 22px 22px;\n display: grid;\n gap: 10px;\n background: var(--composer-bg);\n}\n.tw-input-wrap {\n display: flex;\n gap: 10px;\n align-items: flex-end;\n}\n.tw-textarea {\n flex: 1;\n min-height: 54px;\n max-height: 140px;\n padding: 14px 16px;\n border-radius: 8px;\n border: 1px solid var(--border);\n background: var(--surface);\n color: var(--ink);\n resize: none;\n font-family: inherit;\n font-size: 14px;\n outline: none;\n transition: border 0.2s ease, box-shadow 0.2s ease;\n}\n.tw-textarea::placeholder {\n color: var(--muted);\n opacity: 0.85;\n}\n.tw-textarea:focus {\n border-color: var(--input-focus-border);\n box-shadow: 0 0 0 3px var(--input-focus-shadow);\n}\n.tw-send {\n border: none;\n border-radius: 8px;\n padding: 12px 18px;\n background: var(--button-bg);\n color: var(--button-text);\n font-weight: 600;\n cursor: pointer;\n transition: transform 0.2s ease, box-shadow 0.2s ease;\n}\n.tw-send:hover {\n transform: translateY(-1px);\n box-shadow: 0 12px 24px var(--button-shadow);\n}\n.tw-send:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n transform: none;\n box-shadow: none;\n}\n.tw-meta {\n display: flex;\n justify-content: space-between;\n color: var(--muted);\n font-size: 12px;\n}\n.tw-pill-row {\n display: flex;\n gap: 8px;\n flex-wrap: wrap;\n}\n.tw-pill {\n padding: 6px 10px;\n border-radius: 8px;\n border: 1px dashed var(--pill-border);\n color: var(--muted);\n font-size: 11px;\n}\n@keyframes fadeUp {\n from {\n opacity: 0;\n transform: translateY(8px);\n }\n to {\n opacity: 1;\n transform: translateY(0);\n }\n}\n@keyframes typingBounce {\n 0%, 80%, 100% {\n transform: translateY(0);\n opacity: 0.4;\n }\n 40% {\n transform: translateY(-4px);\n opacity: 0.9;\n }\n}\n@media (max-width: 720px) {\n .tw-widget {\n width: 100%;\n height: 100vh;\n border-radius: 12px;\n }\n}\n');
30
30
 
31
31
  // src/i18n/translations.ts
32
32
  var en = {
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/components/TunioWidget.tsx","#style-inject:#style-inject","../src/components/TunioWidget.module.css","../src/i18n/translations.ts"],"sourcesContent":["'use client';\n\nimport { useCallback, useEffect, useMemo, useRef, useState } from 'react';\nimport ReactMarkdown from 'react-markdown';\nimport remarkGfm from 'remark-gfm';\nimport './TunioWidget.module.css';\nimport { getTranslations } from '../i18n/translations';\n\ntype ChatMessage = {\n id: string;\n role: 'user' | 'assistant' | 'system';\n content: string;\n};\n\nexport type TunioWidgetProps = {\n apiUrl?: string;\n sessionTokenUrl?: string;\n lang?: string;\n getSessionToken?: () => Promise<string>;\n accessToken?: string;\n title?: string;\n subtitle?: string;\n theme?: 'light' | 'dark';\n className?: string;\n onNavigate?: (href: string) => void;\n};\n\nconst createId = () => Math.random().toString(36).slice(2);\n\nexport function TunioWidget({\n apiUrl,\n sessionTokenUrl,\n lang,\n getSessionToken,\n accessToken,\n title,\n subtitle,\n theme = 'light',\n className,\n onNavigate,\n}: TunioWidgetProps) {\n const [input, setInput] = useState('');\n const [isStreaming, setIsStreaming] = useState(false);\n const [error, setError] = useState<string | null>(null);\n const [sessionToken, setSessionToken] = useState<string | null>(null);\n const inputRef = useRef<HTMLTextAreaElement | null>(null);\n const messagesEndRef = useRef<HTMLDivElement | null>(null);\n\n const resolvedApiUrl = apiUrl ?? process.env.NEXT_PUBLIC_AGENT_API_URL ?? '';\n const resolvedTokenUrl =\n sessionTokenUrl ?? process.env.NEXT_PUBLIC_SESSION_TOKEN_URL ?? '';\n const resolvedUserLang = useMemo(() => {\n if (lang) return lang;\n if (typeof navigator !== 'undefined' && navigator.language) {\n return navigator.language.split('-')[0];\n }\n return undefined;\n }, [lang]);\n const i18n = useMemo(() => getTranslations(resolvedUserLang), [resolvedUserLang]);\n const [messages, setMessages] = useState<ChatMessage[]>(() => [\n {\n id: 'welcome',\n role: 'system',\n content: i18n.systemMessage,\n },\n ]);\n const hasUserMessage = useMemo(\n () => messages.some((message) => message.role === 'user'),\n [messages]\n );\n const displayTitle = title ?? i18n.titleDefault;\n const displaySubtitle = subtitle ?? i18n.subtitleDefault;\n\n const scrollToBottom = () => {\n messagesEndRef.current?.scrollIntoView({ behavior: 'smooth' });\n };\n\n useEffect(() => {\n scrollToBottom();\n }, [messages]);\n\n useEffect(() => {\n setMessages((prev) => {\n if (prev.length === 1 && prev[0].id === 'welcome' && prev[0].role === 'system') {\n return [{ ...prev[0], content: i18n.systemMessage }];\n }\n return prev;\n });\n }, [i18n.systemMessage]);\n\n const fetchSessionToken = useCallback(async () => {\n if (getSessionToken) {\n return getSessionToken();\n }\n\n if (accessToken) {\n return accessToken;\n }\n\n if (!resolvedTokenUrl) {\n throw new Error(i18n.errorMissingTokenUrl);\n }\n\n const response = await fetch(resolvedTokenUrl, {\n credentials: accessToken ? 'omit' : 'include',\n headers: accessToken ? { Authorization: `Bearer ${accessToken}` } : undefined,\n });\n\n if (!response.ok) {\n throw new Error(i18n.errorFailedTokenFetch);\n }\n\n const data = (await response.json()) as Record<string, unknown>;\n const token = data.session_token as string;\n\n if (!token) {\n throw new Error(i18n.errorMissingToken);\n }\n\n return token;\n }, [getSessionToken, i18n, resolvedTokenUrl]);\n\n useEffect(() => {\n fetchSessionToken()\n .then(setSessionToken)\n .catch((err) => {\n setError(err instanceof Error ? err.message : i18n.errorTokenLoad);\n });\n }, [fetchSessionToken, i18n.errorTokenLoad]);\n\n const statusLabel = useMemo(() => {\n if (isStreaming) return i18n.statusStreaming;\n if (error) return i18n.statusNeedsAttention;\n return i18n.statusReady;\n }, [error, i18n, isStreaming]);\n\n const handleLinkClick = useCallback(\n (href: string | undefined, event: React.MouseEvent<HTMLAnchorElement>) => {\n if (!href) return;\n const isInternal = href.startsWith('/') && !href.startsWith('//');\n if (isInternal && onNavigate) {\n event.preventDefault();\n onNavigate(href);\n }\n },\n [onNavigate]\n );\n\n const normalizeHref = useCallback((href: string | undefined) => {\n if (!href) return href;\n if (href.startsWith('/') || href.startsWith('#') || href.startsWith('?')) {\n return href;\n }\n if (href.startsWith('mailto:') || href.startsWith('tel:')) {\n return href;\n }\n if (typeof window === 'undefined') {\n return href;\n }\n try {\n const url = new URL(href);\n if (url.host === window.location.host) {\n return `${url.pathname}${url.search}${url.hash}`;\n }\n } catch {\n return href;\n }\n return href;\n }, []);\n\n const focusInput = () => {\n requestAnimationFrame(() => {\n inputRef.current?.focus();\n });\n };\n\n const sendMessage = async () => {\n if (isStreaming) {\n focusInput();\n return;\n }\n if (!input.trim() || !resolvedApiUrl) {\n focusInput();\n return;\n }\n if (!sessionToken) {\n setError(i18n.errorTokenUnavailable);\n focusInput();\n return;\n }\n\n setError(null);\n setIsStreaming(true);\n\n const userMessage: ChatMessage = {\n id: createId(),\n role: 'user',\n content: input.trim(),\n };\n\n const assistantMessage: ChatMessage = {\n id: createId(),\n role: 'assistant',\n content: '',\n };\n\n setMessages((prev) => [...prev, userMessage, assistantMessage]);\n setInput('');\n focusInput();\n\n try {\n const response = await fetch(resolvedApiUrl, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n message: userMessage.content,\n session_token: sessionToken,\n user_lang: resolvedUserLang,\n }),\n });\n\n if (!response.ok || !response.body) {\n throw new Error(i18n.errorServiceUnavailable);\n }\n\n const reader = response.body.getReader();\n const decoder = new TextDecoder();\n let buffer = '';\n\n while (true) {\n const { value, done } = await reader.read();\n if (done) break;\n buffer += decoder.decode(value, { stream: true });\n\n const parts = buffer.split('\\n\\n');\n buffer = parts.pop() ?? '';\n\n for (const part of parts) {\n const lines = part.split('\\n');\n let eventName = 'message';\n let data = '';\n\n for (const line of lines) {\n if (line.startsWith('event:')) {\n eventName = line.replace('event:', '').trim();\n }\n if (line.startsWith('data:')) {\n data += line.replace('data:', '').trim();\n }\n }\n\n if (!data) continue;\n\n if (eventName === 'message') {\n const payload = JSON.parse(data) as { content?: string };\n if (payload.content !== undefined) {\n setMessages((prev) => {\n const next = [...prev];\n const last = next[next.length - 1];\n if (last && last.role === 'assistant') {\n last.content = payload.content ?? '';\n }\n return next;\n });\n }\n }\n\n if (eventName === 'error') {\n const payload = JSON.parse(data) as { message?: string };\n setError(payload.message ?? i18n.errorUnknown);\n }\n }\n }\n } catch (err) {\n setError(err instanceof Error ? err.message : i18n.errorUnexpected);\n } finally {\n setIsStreaming(false);\n }\n };\n\n return (\n <section\n className={`tw-widget tw-${theme}${className ? ` ${className}` : ''}`}\n data-theme={theme}\n data-tunio-widget=\"root\"\n >\n <header className=\"tw-header\">\n <div className=\"tw-brand\">\n <div className=\"tw-brand-title\">{displayTitle}</div>\n <div className=\"tw-brand-subtitle\">{displaySubtitle}</div>\n </div>\n <div className=\"tw-status\">\n <span className=\"tw-status-dot\" />\n {statusLabel}\n </div>\n </header>\n\n <div className=\"tw-messages\">\n {messages.map((message) => (\n <div\n key={message.id}\n className={`tw-message tw-${message.role}`}\n >\n {message.content ? (\n <ReactMarkdown\n remarkPlugins={[remarkGfm]}\n components={{\n a: ({ href, children, ...props }) => {\n const normalizedHref = normalizeHref(href);\n const isInternal =\n typeof normalizedHref === 'string' &&\n normalizedHref.startsWith('/') &&\n !normalizedHref.startsWith('//');\n return (\n <a\n {...props}\n href={normalizedHref}\n onClick={(event) => handleLinkClick(normalizedHref, event)}\n target={isInternal ? undefined : '_blank'}\n rel={isInternal ? undefined : 'noreferrer'}\n >\n {children}\n </a>\n );\n },\n }}\n >\n {message.content}\n </ReactMarkdown>\n ) : message.role === 'assistant' ? (\n <span className=\"tw-typing\" role=\"status\" aria-label={i18n.thinking}>\n <span className=\"tw-typing-dot\" />\n <span className=\"tw-typing-dot\" />\n <span className=\"tw-typing-dot\" />\n <span className=\"tw-sr-only\">{i18n.thinking}</span>\n </span>\n ) : (\n ''\n )}\n </div>\n ))}\n <div ref={messagesEndRef} />\n </div>\n\n <div className=\"tw-composer\">\n {!hasUserMessage ? (\n <div className=\"tw-pill-row\">\n <span className=\"tw-pill\">{i18n.pillSynthwave}</span>\n <span className=\"tw-pill\">{i18n.pillSchedule}</span>\n <span className=\"tw-pill\">{i18n.pillPlayNow}</span>\n </div>\n ) : null}\n <div className=\"tw-input-wrap\">\n <textarea\n className=\"tw-textarea\"\n placeholder={i18n.inputPlaceholder}\n value={input}\n onChange={(event) => setInput(event.target.value)}\n onKeyDown={(event) => {\n if (event.nativeEvent.isComposing) return;\n if (event.key !== 'Enter') return;\n if (event.shiftKey) return;\n event.preventDefault();\n sendMessage();\n }}\n rows={2}\n ref={inputRef}\n />\n <button\n className=\"tw-send\"\n onClick={sendMessage}\n disabled={isStreaming || !input.trim()}\n >\n {isStreaming ? i18n.sending : i18n.send}\n </button>\n </div>\n {error ? (\n <div className=\"tw-meta\">\n {i18n.errorPrefix} {error}\n </div>\n ) : null}\n </div>\n </section>\n );\n}\n","\n export default function styleInject(css, { insertAt } = {}) {\n if (!css || typeof document === 'undefined') return\n \n const head = document.head || document.getElementsByTagName('head')[0]\n const style = document.createElement('style')\n style.type = 'text/css'\n \n if (insertAt === 'top') {\n if (head.firstChild) {\n head.insertBefore(style, head.firstChild)\n } else {\n head.appendChild(style)\n }\n } else {\n head.appendChild(style)\n }\n \n if (style.styleSheet) {\n style.styleSheet.cssText = css\n } else {\n style.appendChild(document.createTextNode(css))\n }\n }\n ","import styleInject from '#style-inject';styleInject(\":global(.tw-widget) {\\n --panel: #f7f9fc;\\n --ink: #1b2430;\\n --muted: #6c7a90;\\n --accent: #3f6df6;\\n --accent-soft: rgba(63, 109, 246, 0.14);\\n --teal: #21b3a8;\\n --surface: #ffffff;\\n --border: rgba(16, 24, 40, 0.12);\\n --widget-bg:\\n linear-gradient(\\n 135deg,\\n #f9fbff 0%,\\n #eef2f8 60%,\\n #e8edf6 100%);\\n --header-bg:\\n linear-gradient(\\n \\n 120deg,\\n rgba(255, 255, 255, 0.92),\\n rgba(243, 246, 252, 0.82) );\\n --composer-bg:\\n linear-gradient(\\n \\n 180deg,\\n rgba(255, 255, 255, 0) 0%,\\n rgba(244, 246, 252, 0.92) 80% );\\n --shadow: 0 24px 70px rgba(18, 24, 40, 0.18);\\n --glow:\\n radial-gradient(\\n circle,\\n rgba(63, 109, 246, 0.18) 0%,\\n rgba(63, 109, 246, 0) 70%);\\n --accent-glow: rgba(63, 109, 246, 0.2);\\n --bubble-user: #1b2430;\\n --bubble-user-text: #f7f9ff;\\n --bubble-assistant: #ffffff;\\n --bubble-assistant-border: rgba(16, 24, 40, 0.08);\\n --bubble-system: rgba(27, 36, 48, 0.08);\\n --bubble-system-text: #6c7a90;\\n --input-focus-border: rgba(63, 109, 246, 0.6);\\n --input-focus-shadow: rgba(63, 109, 246, 0.2);\\n --button-bg: #1b2430;\\n --button-text: #f7f9ff;\\n --button-shadow: rgba(27, 36, 48, 0.2);\\n --pill-border: rgba(16, 24, 40, 0.2);\\n display: grid;\\n grid-template-rows: auto minmax(0, 1fr) auto;\\n width: min(100%, 420px);\\n height: min(80vh, 640px);\\n min-height: 520px;\\n border-radius: 12px;\\n background: var(--widget-bg);\\n border: 1px solid var(--border);\\n box-shadow: var(--shadow);\\n color: var(--ink);\\n overflow: hidden;\\n position: relative;\\n}\\n:global(.tw-light) {\\n color-scheme: light;\\n}\\n:global(.tw-dark) {\\n color-scheme: dark;\\n --panel: #121826;\\n --ink: #e6edf7;\\n --muted: #a5b3c8;\\n --accent: #4a7dff;\\n --accent-soft: rgba(74, 125, 255, 0.18);\\n --teal: #2db9c3;\\n --surface: #1a2232;\\n --border: rgba(230, 237, 247, 0.12);\\n --widget-bg:\\n linear-gradient(\\n 135deg,\\n #131a2a 0%,\\n #101525 60%,\\n #0d1220 100%);\\n --header-bg:\\n linear-gradient(\\n \\n 120deg,\\n rgba(18, 24, 38, 0.95),\\n rgba(23, 30, 48, 0.85) );\\n --composer-bg:\\n linear-gradient(\\n \\n 180deg,\\n rgba(18, 24, 38, 0) 0%,\\n rgba(18, 24, 38, 0.9) 80% );\\n --shadow: 0 28px 90px rgba(2, 7, 14, 0.65);\\n --glow:\\n radial-gradient(\\n circle,\\n rgba(74, 125, 255, 0.2) 0%,\\n rgba(74, 125, 255, 0) 70%);\\n --accent-glow: rgba(74, 125, 255, 0.28);\\n --bubble-user: #2f3e63;\\n --bubble-user-text: #f4f7ff;\\n --bubble-assistant: #1a2233;\\n --bubble-assistant-border: rgba(230, 237, 247, 0.1);\\n --bubble-system: rgba(230, 237, 247, 0.08);\\n --bubble-system-text: #b7c3d7;\\n --input-focus-border: rgba(74, 125, 255, 0.6);\\n --input-focus-shadow: rgba(74, 125, 255, 0.25);\\n --button-bg: #4a7dff;\\n --button-text: #f4f7ff;\\n --button-shadow: rgba(74, 125, 255, 0.35);\\n --pill-border: rgba(230, 237, 247, 0.24);\\n}\\n:global(.tw-widget)::before {\\n content: \\\"\\\";\\n position: absolute;\\n inset: -120px 40% auto -60px;\\n height: 220px;\\n background: var(--glow);\\n pointer-events: none;\\n}\\n:global(.tw-header) {\\n padding: 22px 26px 16px;\\n display: flex;\\n align-items: center;\\n justify-content: space-between;\\n background: var(--header-bg);\\n backdrop-filter: blur(12px);\\n}\\n:global(.tw-brand) {\\n display: flex;\\n flex-direction: column;\\n gap: 6px;\\n}\\n:global(.tw-brand-title) {\\n font-family: var(--font-display);\\n font-size: 24px;\\n letter-spacing: -0.02em;\\n}\\n:global(.tw-brand-subtitle) {\\n color: var(--muted);\\n font-size: 13px;\\n}\\n:global(.tw-status) {\\n display: inline-flex;\\n align-items: center;\\n gap: 8px;\\n padding: 6px 12px;\\n border-radius: 8px;\\n background: var(--accent-soft);\\n color: var(--ink);\\n font-size: 12px;\\n font-weight: 600;\\n}\\n:global(.tw-status-dot) {\\n width: 8px;\\n height: 8px;\\n border-radius: 50%;\\n background: var(--accent);\\n box-shadow: 0 0 0 4px var(--accent-glow);\\n}\\n:global(.tw-messages) {\\n padding: 16px 22px 8px;\\n display: flex;\\n flex-direction: column;\\n gap: 14px;\\n overflow-y: auto;\\n min-height: 0;\\n scroll-behavior: smooth;\\n}\\n:global(.tw-message) {\\n max-width: 85%;\\n padding: 14px 16px;\\n border-radius: 8px;\\n line-height: 1.45;\\n font-size: 14px;\\n animation: fadeUp 0.25s ease;\\n}\\n:global(.tw-message) p {\\n margin: 0;\\n}\\n:global(.tw-message) p + p {\\n margin-top: 8px;\\n}\\n:global(.tw-message) a {\\n color: var(--accent);\\n text-decoration: none;\\n font-weight: 600;\\n}\\n:global(.tw-message) a:hover {\\n text-decoration: underline;\\n}\\n:global(.tw-message) strong {\\n font-weight: 700;\\n}\\n:global(.tw-message) ul,\\n:global(.tw-message) ol {\\n margin: 8px 0 0;\\n padding-left: 18px;\\n}\\n:global(.tw-message) li {\\n margin: 4px 0;\\n}\\n:global(.tw-typing) {\\n display: inline-flex;\\n align-items: center;\\n gap: 6px;\\n min-height: 16px;\\n color: var(--muted);\\n}\\n:global(.tw-typing-dot) {\\n width: 6px;\\n height: 6px;\\n border-radius: 999px;\\n background: currentColor;\\n opacity: 0.6;\\n animation: typingBounce 1.2s infinite ease-in-out;\\n}\\n:global(.tw-typing-dot):nth-child(2) {\\n animation-delay: 0.2s;\\n}\\n:global(.tw-typing-dot):nth-child(3) {\\n animation-delay: 0.4s;\\n}\\n:global(.tw-sr-only) {\\n position: absolute;\\n width: 1px;\\n height: 1px;\\n padding: 0;\\n margin: -1px;\\n overflow: hidden;\\n clip: rect(0, 0, 0, 0);\\n border: 0;\\n}\\n:global(.tw-user) {\\n align-self: flex-end;\\n background: var(--bubble-user);\\n color: var(--bubble-user-text);\\n border-bottom-right-radius: 8px;\\n}\\n:global(.tw-assistant) {\\n align-self: flex-start;\\n background: var(--bubble-assistant);\\n border: 1px solid var(--bubble-assistant-border);\\n border-bottom-left-radius: 8px;\\n}\\n:global(.tw-system) {\\n align-self: center;\\n max-width: 92%;\\n text-align: center;\\n background: var(--bubble-system);\\n color: var(--bubble-system-text);\\n}\\n:global(.tw-composer) {\\n padding: 16px 22px 22px;\\n display: grid;\\n gap: 10px;\\n background: var(--composer-bg);\\n}\\n:global(.tw-input-wrap) {\\n display: flex;\\n gap: 10px;\\n align-items: flex-end;\\n}\\n:global(.tw-textarea) {\\n flex: 1;\\n min-height: 54px;\\n max-height: 140px;\\n padding: 14px 16px;\\n border-radius: 8px;\\n border: 1px solid var(--border);\\n background: var(--surface);\\n color: var(--ink);\\n resize: none;\\n font-family: inherit;\\n font-size: 14px;\\n outline: none;\\n transition: border 0.2s ease, box-shadow 0.2s ease;\\n}\\n:global(.tw-textarea)::placeholder {\\n color: var(--muted);\\n opacity: 0.85;\\n}\\n:global(.tw-textarea):focus {\\n border-color: var(--input-focus-border);\\n box-shadow: 0 0 0 3px var(--input-focus-shadow);\\n}\\n:global(.tw-send) {\\n border: none;\\n border-radius: 8px;\\n padding: 12px 18px;\\n background: var(--button-bg);\\n color: var(--button-text);\\n font-weight: 600;\\n cursor: pointer;\\n transition: transform 0.2s ease, box-shadow 0.2s ease;\\n}\\n:global(.tw-send):hover {\\n transform: translateY(-1px);\\n box-shadow: 0 12px 24px var(--button-shadow);\\n}\\n:global(.tw-send):disabled {\\n opacity: 0.5;\\n cursor: not-allowed;\\n transform: none;\\n box-shadow: none;\\n}\\n:global(.tw-meta) {\\n display: flex;\\n justify-content: space-between;\\n color: var(--muted);\\n font-size: 12px;\\n}\\n:global(.tw-pill-row) {\\n display: flex;\\n gap: 8px;\\n flex-wrap: wrap;\\n}\\n:global(.tw-pill) {\\n padding: 6px 10px;\\n border-radius: 8px;\\n border: 1px dashed var(--pill-border);\\n color: var(--muted);\\n font-size: 11px;\\n}\\n@keyframes fadeUp {\\n from {\\n opacity: 0;\\n transform: translateY(8px);\\n }\\n to {\\n opacity: 1;\\n transform: translateY(0);\\n }\\n}\\n@keyframes typingBounce {\\n 0%, 80%, 100% {\\n transform: translateY(0);\\n opacity: 0.4;\\n }\\n 40% {\\n transform: translateY(-4px);\\n opacity: 0.9;\\n }\\n}\\n@media (max-width: 720px) {\\n :global(.tw-widget) {\\n width: 100%;\\n height: 100vh;\\n border-radius: 12px;\\n }\\n}\\n\")","export type Translations = {\n titleDefault: string;\n subtitleDefault: string;\n systemMessage: string;\n statusStreaming: string;\n statusNeedsAttention: string;\n statusReady: string;\n thinking: string;\n pillSynthwave: string;\n pillSchedule: string;\n pillPlayNow: string;\n inputPlaceholder: string;\n sending: string;\n send: string;\n sessionReady: string;\n sessionRequesting: string;\n missingApiUrl: string;\n errorPrefix: string;\n errorMissingTokenUrl: string;\n errorFailedTokenFetch: string;\n errorMissingToken: string;\n errorTokenLoad: string;\n errorTokenUnavailable: string;\n errorServiceUnavailable: string;\n errorUnknown: string;\n errorUnexpected: string;\n};\n\nexport const en: Translations = {\n titleDefault: 'Tunio Assistant',\n subtitleDefault: 'Live on-air assistant',\n systemMessage: 'Tell me what station or playlist you want and I will set it up.',\n statusStreaming: 'Online',\n statusNeedsAttention: 'Online',\n statusReady: 'Online',\n thinking: 'Thinking...',\n pillSynthwave: '\"Create a synthwave radio\"',\n pillSchedule: '\"Schedule a rock playlist at 6 PM\"',\n pillPlayNow: '\"Set playlist to play now\"',\n inputPlaceholder: 'Tell me what to do on air...',\n sending: 'Working...',\n send: 'Send',\n sessionReady: 'Session ready',\n sessionRequesting: 'Requesting session...',\n missingApiUrl: 'Missing API URL',\n errorPrefix: 'Error:',\n errorMissingTokenUrl: 'Missing session token URL',\n errorFailedTokenFetch: 'Failed to fetch session token',\n errorMissingToken: 'Session token missing in response',\n errorTokenLoad: 'Failed to load token',\n errorTokenUnavailable: 'Session token is not available',\n errorServiceUnavailable: 'Agent service unavailable',\n errorUnknown: 'Unknown error',\n errorUnexpected: 'Unexpected error',\n};\n\nexport const ru: Translations = {\n titleDefault: 'Tunio Ассистент',\n subtitleDefault: 'Ассистент прямого эфира',\n systemMessage: 'Скажите, какую станцию или плейлист нужно поставить, и я все настрою.',\n statusStreaming: 'Онлайн',\n statusNeedsAttention: 'Онлайн',\n statusReady: 'Онлайн',\n thinking: 'Думаю...',\n pillSynthwave: '\"Создай синтвейв-радио\"',\n pillSchedule: '\"Запланируй рок-плейлист на 18:00\"',\n pillPlayNow: '\"Включи плейлист сейчас\"',\n inputPlaceholder: 'Скажи, что сделать в эфире...',\n sending: 'Выполняю...',\n send: 'Отправить',\n sessionReady: 'Сессия готова',\n sessionRequesting: 'Запрашиваем сессию...',\n missingApiUrl: 'Не задан API URL',\n errorPrefix: 'Ошибка:',\n errorMissingTokenUrl: 'Не задан URL токена сессии',\n errorFailedTokenFetch: 'Не удалось получить токен сессии',\n errorMissingToken: 'Токен сессии отсутствует в ответе',\n errorTokenLoad: 'Не удалось загрузить токен',\n errorTokenUnavailable: 'Токен сессии недоступен',\n errorServiceUnavailable: 'Сервис агента недоступен',\n errorUnknown: 'Неизвестная ошибка',\n errorUnexpected: 'Непредвиденная ошибка',\n};\n\nconst translations: Record<string, Translations> = {\n en,\n ru,\n};\n\nexport const getTranslations = (lang?: string): Translations => {\n if (!lang) return en;\n const normalized = lang.toLowerCase();\n if (translations[normalized]) return translations[normalized];\n const base = normalized.split('-')[0];\n return translations[base] ?? en;\n};\n"],"mappings":"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","names":["_a","_b"]}
1
+ {"version":3,"sources":["../src/components/TunioWidget.tsx","#style-inject:#style-inject","../src/components/TunioWidget.module.css","../src/i18n/translations.ts"],"sourcesContent":["'use client';\n\nimport { useCallback, useEffect, useMemo, useRef, useState } from 'react';\nimport ReactMarkdown from 'react-markdown';\nimport remarkGfm from 'remark-gfm';\nimport './TunioWidget.module.css';\nimport { getTranslations } from '../i18n/translations';\n\ntype ChatMessage = {\n id: string;\n role: 'user' | 'assistant' | 'system';\n content: string;\n};\n\nexport type TunioWidgetProps = {\n apiUrl?: string;\n sessionTokenUrl?: string;\n lang?: string;\n getSessionToken?: () => Promise<string>;\n accessToken?: string;\n title?: string;\n subtitle?: string;\n theme?: 'light' | 'dark';\n className?: string;\n onNavigate?: (href: string) => void;\n};\n\nconst createId = () => Math.random().toString(36).slice(2);\n\nexport function TunioWidget({\n apiUrl,\n sessionTokenUrl,\n lang,\n getSessionToken,\n accessToken,\n title,\n subtitle,\n theme = 'light',\n className,\n onNavigate,\n}: TunioWidgetProps) {\n const [input, setInput] = useState('');\n const [isStreaming, setIsStreaming] = useState(false);\n const [error, setError] = useState<string | null>(null);\n const [sessionToken, setSessionToken] = useState<string | null>(null);\n const inputRef = useRef<HTMLTextAreaElement | null>(null);\n const messagesEndRef = useRef<HTMLDivElement | null>(null);\n\n const resolvedApiUrl = apiUrl ?? process.env.NEXT_PUBLIC_AGENT_API_URL ?? '';\n const resolvedTokenUrl =\n sessionTokenUrl ?? process.env.NEXT_PUBLIC_SESSION_TOKEN_URL ?? '';\n const resolvedUserLang = useMemo(() => {\n if (lang) return lang;\n if (typeof navigator !== 'undefined' && navigator.language) {\n return navigator.language.split('-')[0];\n }\n return undefined;\n }, [lang]);\n const i18n = useMemo(() => getTranslations(resolvedUserLang), [resolvedUserLang]);\n const [messages, setMessages] = useState<ChatMessage[]>(() => [\n {\n id: 'welcome',\n role: 'system',\n content: i18n.systemMessage,\n },\n ]);\n const hasUserMessage = useMemo(\n () => messages.some((message) => message.role === 'user'),\n [messages]\n );\n const displayTitle = title ?? i18n.titleDefault;\n const displaySubtitle = subtitle ?? i18n.subtitleDefault;\n\n const scrollToBottom = () => {\n messagesEndRef.current?.scrollIntoView({ behavior: 'smooth' });\n };\n\n useEffect(() => {\n scrollToBottom();\n }, [messages]);\n\n useEffect(() => {\n setMessages((prev) => {\n if (prev.length === 1 && prev[0].id === 'welcome' && prev[0].role === 'system') {\n return [{ ...prev[0], content: i18n.systemMessage }];\n }\n return prev;\n });\n }, [i18n.systemMessage]);\n\n const fetchSessionToken = useCallback(async () => {\n if (getSessionToken) {\n return getSessionToken();\n }\n\n if (accessToken) {\n return accessToken;\n }\n\n if (!resolvedTokenUrl) {\n throw new Error(i18n.errorMissingTokenUrl);\n }\n\n const response = await fetch(resolvedTokenUrl, {\n credentials: accessToken ? 'omit' : 'include',\n headers: accessToken ? { Authorization: `Bearer ${accessToken}` } : undefined,\n });\n\n if (!response.ok) {\n throw new Error(i18n.errorFailedTokenFetch);\n }\n\n const data = (await response.json()) as Record<string, unknown>;\n const token = data.session_token as string;\n\n if (!token) {\n throw new Error(i18n.errorMissingToken);\n }\n\n return token;\n }, [getSessionToken, i18n, resolvedTokenUrl]);\n\n useEffect(() => {\n fetchSessionToken()\n .then(setSessionToken)\n .catch((err) => {\n setError(err instanceof Error ? err.message : i18n.errorTokenLoad);\n });\n }, [fetchSessionToken, i18n.errorTokenLoad]);\n\n const statusLabel = useMemo(() => {\n if (isStreaming) return i18n.statusStreaming;\n if (error) return i18n.statusNeedsAttention;\n return i18n.statusReady;\n }, [error, i18n, isStreaming]);\n\n const handleLinkClick = useCallback(\n (href: string | undefined, event: React.MouseEvent<HTMLAnchorElement>) => {\n if (!href) return;\n const isInternal = href.startsWith('/') && !href.startsWith('//');\n if (isInternal && onNavigate) {\n event.preventDefault();\n onNavigate(href);\n }\n },\n [onNavigate]\n );\n\n const normalizeHref = useCallback((href: string | undefined) => {\n if (!href) return href;\n if (href.startsWith('/') || href.startsWith('#') || href.startsWith('?')) {\n return href;\n }\n if (href.startsWith('mailto:') || href.startsWith('tel:')) {\n return href;\n }\n if (typeof window === 'undefined') {\n return href;\n }\n try {\n const url = new URL(href);\n if (url.host === window.location.host) {\n return `${url.pathname}${url.search}${url.hash}`;\n }\n } catch {\n return href;\n }\n return href;\n }, []);\n\n const focusInput = () => {\n requestAnimationFrame(() => {\n inputRef.current?.focus();\n });\n };\n\n const sendMessage = async () => {\n if (isStreaming) {\n focusInput();\n return;\n }\n if (!input.trim() || !resolvedApiUrl) {\n focusInput();\n return;\n }\n if (!sessionToken) {\n setError(i18n.errorTokenUnavailable);\n focusInput();\n return;\n }\n\n setError(null);\n setIsStreaming(true);\n\n const userMessage: ChatMessage = {\n id: createId(),\n role: 'user',\n content: input.trim(),\n };\n\n const assistantMessage: ChatMessage = {\n id: createId(),\n role: 'assistant',\n content: '',\n };\n\n setMessages((prev) => [...prev, userMessage, assistantMessage]);\n setInput('');\n focusInput();\n\n try {\n const response = await fetch(resolvedApiUrl, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n message: userMessage.content,\n session_token: sessionToken,\n user_lang: resolvedUserLang,\n }),\n });\n\n if (!response.ok || !response.body) {\n throw new Error(i18n.errorServiceUnavailable);\n }\n\n const reader = response.body.getReader();\n const decoder = new TextDecoder();\n let buffer = '';\n\n while (true) {\n const { value, done } = await reader.read();\n if (done) break;\n buffer += decoder.decode(value, { stream: true });\n\n const parts = buffer.split('\\n\\n');\n buffer = parts.pop() ?? '';\n\n for (const part of parts) {\n const lines = part.split('\\n');\n let eventName = 'message';\n let data = '';\n\n for (const line of lines) {\n if (line.startsWith('event:')) {\n eventName = line.replace('event:', '').trim();\n }\n if (line.startsWith('data:')) {\n data += line.replace('data:', '').trim();\n }\n }\n\n if (!data) continue;\n\n if (eventName === 'message') {\n const payload = JSON.parse(data) as { content?: string };\n if (payload.content !== undefined) {\n setMessages((prev) => {\n const next = [...prev];\n const last = next[next.length - 1];\n if (last && last.role === 'assistant') {\n last.content = payload.content ?? '';\n }\n return next;\n });\n }\n }\n\n if (eventName === 'error') {\n const payload = JSON.parse(data) as { message?: string };\n setError(payload.message ?? i18n.errorUnknown);\n }\n }\n }\n } catch (err) {\n setError(err instanceof Error ? err.message : i18n.errorUnexpected);\n } finally {\n setIsStreaming(false);\n }\n };\n\n return (\n <section\n className={`tw-widget tw-${theme}${className ? ` ${className}` : ''}`}\n data-theme={theme}\n data-tunio-widget=\"root\"\n >\n <header className=\"tw-header\">\n <div className=\"tw-brand\">\n <div className=\"tw-brand-title\">{displayTitle}</div>\n <div className=\"tw-brand-subtitle\">{displaySubtitle}</div>\n </div>\n <div className=\"tw-status\">\n <span className=\"tw-status-dot\" />\n {statusLabel}\n </div>\n </header>\n\n <div className=\"tw-messages\">\n {messages.map((message) => (\n <div\n key={message.id}\n className={`tw-message tw-${message.role}`}\n >\n {message.content ? (\n <ReactMarkdown\n remarkPlugins={[remarkGfm]}\n components={{\n a: ({ href, children, ...props }) => {\n const normalizedHref = normalizeHref(href);\n const isInternal =\n typeof normalizedHref === 'string' &&\n normalizedHref.startsWith('/') &&\n !normalizedHref.startsWith('//');\n return (\n <a\n {...props}\n href={normalizedHref}\n onClick={(event) => handleLinkClick(normalizedHref, event)}\n target={isInternal ? undefined : '_blank'}\n rel={isInternal ? undefined : 'noreferrer'}\n >\n {children}\n </a>\n );\n },\n }}\n >\n {message.content}\n </ReactMarkdown>\n ) : message.role === 'assistant' ? (\n <span className=\"tw-typing\" role=\"status\" aria-label={i18n.thinking}>\n <span className=\"tw-typing-dot\" />\n <span className=\"tw-typing-dot\" />\n <span className=\"tw-typing-dot\" />\n <span className=\"tw-sr-only\">{i18n.thinking}</span>\n </span>\n ) : (\n ''\n )}\n </div>\n ))}\n <div ref={messagesEndRef} />\n </div>\n\n <div className=\"tw-composer\">\n {!hasUserMessage ? (\n <div className=\"tw-pill-row\">\n <span className=\"tw-pill\">{i18n.pillSynthwave}</span>\n <span className=\"tw-pill\">{i18n.pillSchedule}</span>\n <span className=\"tw-pill\">{i18n.pillPlayNow}</span>\n </div>\n ) : null}\n <div className=\"tw-input-wrap\">\n <textarea\n className=\"tw-textarea\"\n placeholder={i18n.inputPlaceholder}\n value={input}\n onChange={(event) => setInput(event.target.value)}\n onKeyDown={(event) => {\n if (event.nativeEvent.isComposing) return;\n if (event.key !== 'Enter') return;\n if (event.shiftKey) return;\n event.preventDefault();\n sendMessage();\n }}\n rows={2}\n ref={inputRef}\n />\n <button\n className=\"tw-send\"\n onClick={sendMessage}\n disabled={isStreaming || !input.trim()}\n >\n {isStreaming ? i18n.sending : i18n.send}\n </button>\n </div>\n {error ? (\n <div className=\"tw-meta\">\n {i18n.errorPrefix} {error}\n </div>\n ) : null}\n </div>\n </section>\n );\n}\n","\n export default function styleInject(css, { insertAt } = {}) {\n if (!css || typeof document === 'undefined') return\n \n const head = document.head || document.getElementsByTagName('head')[0]\n const style = document.createElement('style')\n style.type = 'text/css'\n \n if (insertAt === 'top') {\n if (head.firstChild) {\n head.insertBefore(style, head.firstChild)\n } else {\n head.appendChild(style)\n }\n } else {\n head.appendChild(style)\n }\n \n if (style.styleSheet) {\n style.styleSheet.cssText = css\n } else {\n style.appendChild(document.createTextNode(css))\n }\n }\n ","import styleInject from '#style-inject';styleInject(\".tw-widget {\\n --panel: #f7f9fc;\\n --ink: #1b2430;\\n --muted: #6c7a90;\\n --accent: #3f6df6;\\n --accent-soft: rgba(63, 109, 246, 0.14);\\n --teal: #21b3a8;\\n --surface: #ffffff;\\n --border: rgba(16, 24, 40, 0.12);\\n --widget-bg:\\n linear-gradient(\\n 135deg,\\n #f9fbff 0%,\\n #eef2f8 60%,\\n #e8edf6 100%);\\n --header-bg:\\n linear-gradient(\\n \\n 120deg,\\n rgba(255, 255, 255, 0.92),\\n rgba(243, 246, 252, 0.82) );\\n --composer-bg:\\n linear-gradient(\\n \\n 180deg,\\n rgba(255, 255, 255, 0) 0%,\\n rgba(244, 246, 252, 0.92) 80% );\\n --shadow: 0 24px 70px rgba(18, 24, 40, 0.18);\\n --glow:\\n radial-gradient(\\n circle,\\n rgba(63, 109, 246, 0.18) 0%,\\n rgba(63, 109, 246, 0) 70%);\\n --accent-glow: rgba(63, 109, 246, 0.2);\\n --bubble-user: #1b2430;\\n --bubble-user-text: #f7f9ff;\\n --bubble-assistant: #ffffff;\\n --bubble-assistant-border: rgba(16, 24, 40, 0.08);\\n --bubble-system: rgba(27, 36, 48, 0.08);\\n --bubble-system-text: #6c7a90;\\n --input-focus-border: rgba(63, 109, 246, 0.6);\\n --input-focus-shadow: rgba(63, 109, 246, 0.2);\\n --button-bg: #1b2430;\\n --button-text: #f7f9ff;\\n --button-shadow: rgba(27, 36, 48, 0.2);\\n --pill-border: rgba(16, 24, 40, 0.2);\\n display: grid;\\n grid-template-rows: auto minmax(0, 1fr) auto;\\n width: min(100%, 420px);\\n height: min(80vh, 640px);\\n min-height: 520px;\\n border-radius: 12px;\\n background: var(--widget-bg);\\n border: 1px solid var(--border);\\n box-shadow: var(--shadow);\\n color: var(--ink);\\n overflow: hidden;\\n position: relative;\\n}\\n.tw-light {\\n color-scheme: light;\\n}\\n.tw-dark {\\n color-scheme: dark;\\n --panel: #121826;\\n --ink: #e6edf7;\\n --muted: #a5b3c8;\\n --accent: #4a7dff;\\n --accent-soft: rgba(74, 125, 255, 0.18);\\n --teal: #2db9c3;\\n --surface: #1a2232;\\n --border: rgba(230, 237, 247, 0.12);\\n --widget-bg:\\n linear-gradient(\\n 135deg,\\n #131a2a 0%,\\n #101525 60%,\\n #0d1220 100%);\\n --header-bg:\\n linear-gradient(\\n \\n 120deg,\\n rgba(18, 24, 38, 0.95),\\n rgba(23, 30, 48, 0.85) );\\n --composer-bg:\\n linear-gradient(\\n \\n 180deg,\\n rgba(18, 24, 38, 0) 0%,\\n rgba(18, 24, 38, 0.9) 80% );\\n --shadow: 0 28px 90px rgba(2, 7, 14, 0.65);\\n --glow:\\n radial-gradient(\\n circle,\\n rgba(74, 125, 255, 0.2) 0%,\\n rgba(74, 125, 255, 0) 70%);\\n --accent-glow: rgba(74, 125, 255, 0.28);\\n --bubble-user: #2f3e63;\\n --bubble-user-text: #f4f7ff;\\n --bubble-assistant: #1a2233;\\n --bubble-assistant-border: rgba(230, 237, 247, 0.1);\\n --bubble-system: rgba(230, 237, 247, 0.08);\\n --bubble-system-text: #b7c3d7;\\n --input-focus-border: rgba(74, 125, 255, 0.6);\\n --input-focus-shadow: rgba(74, 125, 255, 0.25);\\n --button-bg: #4a7dff;\\n --button-text: #f4f7ff;\\n --button-shadow: rgba(74, 125, 255, 0.35);\\n --pill-border: rgba(230, 237, 247, 0.24);\\n}\\n.tw-widget::before {\\n content: \\\"\\\";\\n position: absolute;\\n inset: -120px 40% auto -60px;\\n height: 220px;\\n background: var(--glow);\\n pointer-events: none;\\n}\\n.tw-header {\\n padding: 22px 26px 16px;\\n display: flex;\\n align-items: center;\\n justify-content: space-between;\\n background: var(--header-bg);\\n backdrop-filter: blur(12px);\\n}\\n.tw-brand {\\n display: flex;\\n flex-direction: column;\\n gap: 6px;\\n}\\n.tw-brand-title {\\n font-family: var(--font-display);\\n font-size: 24px;\\n letter-spacing: -0.02em;\\n}\\n.tw-brand-subtitle {\\n color: var(--muted);\\n font-size: 13px;\\n}\\n.tw-status {\\n display: inline-flex;\\n align-items: center;\\n gap: 8px;\\n padding: 6px 12px;\\n border-radius: 8px;\\n background: var(--accent-soft);\\n color: var(--ink);\\n font-size: 12px;\\n font-weight: 600;\\n}\\n.tw-status-dot {\\n width: 8px;\\n height: 8px;\\n border-radius: 50%;\\n background: var(--accent);\\n box-shadow: 0 0 0 4px var(--accent-glow);\\n}\\n.tw-messages {\\n padding: 16px 22px 8px;\\n display: flex;\\n flex-direction: column;\\n gap: 14px;\\n overflow-y: auto;\\n min-height: 0;\\n scroll-behavior: smooth;\\n}\\n.tw-message {\\n max-width: 85%;\\n padding: 14px 16px;\\n border-radius: 8px;\\n line-height: 1.45;\\n font-size: 14px;\\n animation: fadeUp 0.25s ease;\\n}\\n.tw-message p {\\n margin: 0;\\n}\\n.tw-message p + p {\\n margin-top: 8px;\\n}\\n.tw-message a {\\n color: var(--accent);\\n text-decoration: none;\\n font-weight: 600;\\n}\\n.tw-message a:hover {\\n text-decoration: underline;\\n}\\n.tw-message strong {\\n font-weight: 700;\\n}\\n.tw-message ul,\\n.tw-message ol {\\n margin: 8px 0 0;\\n padding-left: 18px;\\n}\\n.tw-message li {\\n margin: 4px 0;\\n}\\n.tw-typing {\\n display: inline-flex;\\n align-items: center;\\n gap: 6px;\\n min-height: 16px;\\n color: var(--muted);\\n}\\n.tw-typing-dot {\\n width: 6px;\\n height: 6px;\\n border-radius: 999px;\\n background: currentColor;\\n opacity: 0.6;\\n animation: typingBounce 1.2s infinite ease-in-out;\\n}\\n.tw-typing-dot:nth-child(2) {\\n animation-delay: 0.2s;\\n}\\n.tw-typing-dot:nth-child(3) {\\n animation-delay: 0.4s;\\n}\\n.tw-sr-only {\\n position: absolute;\\n width: 1px;\\n height: 1px;\\n padding: 0;\\n margin: -1px;\\n overflow: hidden;\\n clip: rect(0, 0, 0, 0);\\n border: 0;\\n}\\n.tw-user {\\n align-self: flex-end;\\n background: var(--bubble-user);\\n color: var(--bubble-user-text);\\n border-bottom-right-radius: 8px;\\n}\\n.tw-assistant {\\n align-self: flex-start;\\n background: var(--bubble-assistant);\\n border: 1px solid var(--bubble-assistant-border);\\n border-bottom-left-radius: 8px;\\n}\\n.tw-system {\\n align-self: center;\\n max-width: 92%;\\n text-align: center;\\n background: var(--bubble-system);\\n color: var(--bubble-system-text);\\n}\\n.tw-composer {\\n padding: 16px 22px 22px;\\n display: grid;\\n gap: 10px;\\n background: var(--composer-bg);\\n}\\n.tw-input-wrap {\\n display: flex;\\n gap: 10px;\\n align-items: flex-end;\\n}\\n.tw-textarea {\\n flex: 1;\\n min-height: 54px;\\n max-height: 140px;\\n padding: 14px 16px;\\n border-radius: 8px;\\n border: 1px solid var(--border);\\n background: var(--surface);\\n color: var(--ink);\\n resize: none;\\n font-family: inherit;\\n font-size: 14px;\\n outline: none;\\n transition: border 0.2s ease, box-shadow 0.2s ease;\\n}\\n.tw-textarea::placeholder {\\n color: var(--muted);\\n opacity: 0.85;\\n}\\n.tw-textarea:focus {\\n border-color: var(--input-focus-border);\\n box-shadow: 0 0 0 3px var(--input-focus-shadow);\\n}\\n.tw-send {\\n border: none;\\n border-radius: 8px;\\n padding: 12px 18px;\\n background: var(--button-bg);\\n color: var(--button-text);\\n font-weight: 600;\\n cursor: pointer;\\n transition: transform 0.2s ease, box-shadow 0.2s ease;\\n}\\n.tw-send:hover {\\n transform: translateY(-1px);\\n box-shadow: 0 12px 24px var(--button-shadow);\\n}\\n.tw-send:disabled {\\n opacity: 0.5;\\n cursor: not-allowed;\\n transform: none;\\n box-shadow: none;\\n}\\n.tw-meta {\\n display: flex;\\n justify-content: space-between;\\n color: var(--muted);\\n font-size: 12px;\\n}\\n.tw-pill-row {\\n display: flex;\\n gap: 8px;\\n flex-wrap: wrap;\\n}\\n.tw-pill {\\n padding: 6px 10px;\\n border-radius: 8px;\\n border: 1px dashed var(--pill-border);\\n color: var(--muted);\\n font-size: 11px;\\n}\\n@keyframes fadeUp {\\n from {\\n opacity: 0;\\n transform: translateY(8px);\\n }\\n to {\\n opacity: 1;\\n transform: translateY(0);\\n }\\n}\\n@keyframes typingBounce {\\n 0%, 80%, 100% {\\n transform: translateY(0);\\n opacity: 0.4;\\n }\\n 40% {\\n transform: translateY(-4px);\\n opacity: 0.9;\\n }\\n}\\n@media (max-width: 720px) {\\n .tw-widget {\\n width: 100%;\\n height: 100vh;\\n border-radius: 12px;\\n }\\n}\\n\")","export type Translations = {\n titleDefault: string;\n subtitleDefault: string;\n systemMessage: string;\n statusStreaming: string;\n statusNeedsAttention: string;\n statusReady: string;\n thinking: string;\n pillSynthwave: string;\n pillSchedule: string;\n pillPlayNow: string;\n inputPlaceholder: string;\n sending: string;\n send: string;\n sessionReady: string;\n sessionRequesting: string;\n missingApiUrl: string;\n errorPrefix: string;\n errorMissingTokenUrl: string;\n errorFailedTokenFetch: string;\n errorMissingToken: string;\n errorTokenLoad: string;\n errorTokenUnavailable: string;\n errorServiceUnavailable: string;\n errorUnknown: string;\n errorUnexpected: string;\n};\n\nexport const en: Translations = {\n titleDefault: 'Tunio Assistant',\n subtitleDefault: 'Live on-air assistant',\n systemMessage: 'Tell me what station or playlist you want and I will set it up.',\n statusStreaming: 'Online',\n statusNeedsAttention: 'Online',\n statusReady: 'Online',\n thinking: 'Thinking...',\n pillSynthwave: '\"Create a synthwave radio\"',\n pillSchedule: '\"Schedule a rock playlist at 6 PM\"',\n pillPlayNow: '\"Set playlist to play now\"',\n inputPlaceholder: 'Tell me what to do on air...',\n sending: 'Working...',\n send: 'Send',\n sessionReady: 'Session ready',\n sessionRequesting: 'Requesting session...',\n missingApiUrl: 'Missing API URL',\n errorPrefix: 'Error:',\n errorMissingTokenUrl: 'Missing session token URL',\n errorFailedTokenFetch: 'Failed to fetch session token',\n errorMissingToken: 'Session token missing in response',\n errorTokenLoad: 'Failed to load token',\n errorTokenUnavailable: 'Session token is not available',\n errorServiceUnavailable: 'Agent service unavailable',\n errorUnknown: 'Unknown error',\n errorUnexpected: 'Unexpected error',\n};\n\nexport const ru: Translations = {\n titleDefault: 'Tunio Ассистент',\n subtitleDefault: 'Ассистент прямого эфира',\n systemMessage: 'Скажите, какую станцию или плейлист нужно поставить, и я все настрою.',\n statusStreaming: 'Онлайн',\n statusNeedsAttention: 'Онлайн',\n statusReady: 'Онлайн',\n thinking: 'Думаю...',\n pillSynthwave: '\"Создай синтвейв-радио\"',\n pillSchedule: '\"Запланируй рок-плейлист на 18:00\"',\n pillPlayNow: '\"Включи плейлист сейчас\"',\n inputPlaceholder: 'Скажи, что сделать в эфире...',\n sending: 'Выполняю...',\n send: 'Отправить',\n sessionReady: 'Сессия готова',\n sessionRequesting: 'Запрашиваем сессию...',\n missingApiUrl: 'Не задан API URL',\n errorPrefix: 'Ошибка:',\n errorMissingTokenUrl: 'Не задан URL токена сессии',\n errorFailedTokenFetch: 'Не удалось получить токен сессии',\n errorMissingToken: 'Токен сессии отсутствует в ответе',\n errorTokenLoad: 'Не удалось загрузить токен',\n errorTokenUnavailable: 'Токен сессии недоступен',\n errorServiceUnavailable: 'Сервис агента недоступен',\n errorUnknown: 'Неизвестная ошибка',\n errorUnexpected: 'Непредвиденная ошибка',\n};\n\nconst translations: Record<string, Translations> = {\n en,\n ru,\n};\n\nexport const getTranslations = (lang?: string): Translations => {\n if (!lang) return en;\n const normalized = lang.toLowerCase();\n if (translations[normalized]) return translations[normalized];\n const base = normalized.split('-')[0];\n return translations[base] ?? en;\n};\n"],"mappings":"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","names":["_a","_b"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tunio-agent-widget",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "private": false,
5
5
  "main": "./dist/index.cjs",
6
6
  "module": "./dist/index.mjs",