@getnexorai/sdk 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/dist/chat.cjs CHANGED
@@ -895,6 +895,7 @@ function initChat(client, options) {
895
895
  }, 6e4);
896
896
  function appendNode(node) {
897
897
  panel.body.appendChild(node);
898
+ if (send.typing && send.typing !== node) panel.body.appendChild(send.typing);
898
899
  scrollToBottom();
899
900
  return node;
900
901
  }
package/dist/chat.cjs.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/chat/config.ts","../src/chat/session.ts","../src/chat/styles.ts","../src/chat/dom.ts","../src/chat/index.ts"],"names":[],"mappings":"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","file":"chat.cjs","sourcesContent":["/**\n * Chat widget configuration types + defaults.\n *\n * Kept separate from the widget's runtime code so other modules (and the\n * top-level `nexor.initChat()` re-export) can pull types without dragging in\n * the DOM construction code.\n */\nimport type { UUID } from \"../types\";\n\n// ─── Public option / handle types ──────────────────────────────────────────\n\nexport interface ChatLeadCapture {\n /** Which fields to ask for before chatting. Defaults to [\"first_name\", \"email\"]. */\n fields?: Array<\"first_name\" | \"last_name\" | \"email\" | \"phone\">;\n /** \"before\" gates chat behind the form; \"skip\" never asks. Default \"before\". */\n mode?: \"before\" | \"skip\";\n /** Label rendered above the form. */\n label?: string;\n /** Submit button label. */\n submitLabel?: string;\n}\n\nexport interface ChatInitOptions {\n /** Workflow that handles this chat conversation. Required. */\n workflowId: UUID;\n\n // ── Identity / branding ──\n title?: string;\n subtitle?: string;\n greeting?: string;\n /** Shown when a turn fails or the server returns no reply. */\n errorText?: string;\n /** BCP-47 locale for timestamps (e.g. \"es\", \"en-US\"). Defaults to the browser. */\n locale?: string;\n /** Hex colour for bubble + accents. Defaults to #111827. */\n accentColor?: string;\n /** Text colour rendered on top of the accent. Defaults to white. */\n accentTextColor?: string;\n /** Show the \"Powered by Nexor\" footer. Defaults to true. */\n showBranding?: boolean;\n\n // ── Behaviour ──\n position?: \"bottom-right\" | \"bottom-left\";\n /** Auto-open the panel on first load. Defaults to false. */\n openOnLoad?: boolean;\n /** Coalesce rapid-fire messages: wait this many ms of quiet, then send the\n * buffered messages as one combined turn. Defaults to 700. 0 = per message. */\n debounceMs?: number;\n /** Append the widget to a custom element. Defaults to document.body. */\n container?: HTMLElement;\n\n // ── Prompt overrides forwarded to the agent for THIS widget instance ──\n systemPrompt?: string;\n clientPrompt?: string;\n\n // ── Lead linking ──\n /** Pre-known lead info (e.g. a logged-in user). Skips capture if complete. */\n lead?: {\n first_name?: string;\n last_name?: string;\n email?: string;\n phone?: string;\n metadata?: Record<string, unknown>;\n };\n capture?: ChatLeadCapture;\n /** Arbitrary metadata passed with each turn (page URL, UTM, …). */\n metadata?: Record<string, unknown>;\n\n // ── Callbacks ──\n onOpen?: () => void;\n onClose?: () => void;\n onMessage?: (msg: { role: \"user\" | \"bot\"; text: string }) => void;\n onLeadCaptured?: (leadId: UUID) => void;\n onError?: (err: Error) => void;\n}\n\nexport interface ChatHandle {\n open(): void;\n close(): void;\n toggle(): void;\n /** Programmatically send a user message. */\n send(text: string): Promise<void>;\n /** Tear down the widget and remove all DOM. */\n destroy(): void;\n /** Read the current session id (auto-generated on first open). */\n getSessionId(): string;\n}\n\n// ─── Internal resolved-config type ─────────────────────────────────────────\n\nexport interface ResolvedCfg {\n workflowId: UUID;\n title: string;\n subtitle: string;\n greeting: string;\n errorText: string;\n locale?: string;\n accentColor: string;\n accentTextColor: string;\n showBranding: boolean;\n position: \"bottom-right\" | \"bottom-left\";\n openOnLoad: boolean;\n debounceMs: number;\n container?: HTMLElement;\n systemPrompt?: string;\n clientPrompt?: string;\n lead?: ChatInitOptions[\"lead\"];\n capture: Required<ChatLeadCapture>;\n metadata?: Record<string, unknown>;\n onOpen?: () => void;\n onClose?: () => void;\n onMessage?: (msg: { role: \"user\" | \"bot\"; text: string }) => void;\n onLeadCaptured?: (leadId: UUID) => void;\n onError?: (err: Error) => void;\n}\n\n/**\n * Normalize user-provided options into a complete config object with every\n * field set. Downstream code reads from ResolvedCfg and never has to deal\n * with `undefined` for branding / behaviour fields.\n */\nexport function applyDefaults(o: ChatInitOptions): ResolvedCfg {\n return {\n workflowId: o.workflowId,\n title: o.title ?? \"Chat with us\",\n subtitle: o.subtitle ?? \"We typically reply in a few minutes\",\n greeting: o.greeting ?? \"Hi there! 👋 How can we help?\",\n errorText:\n o.errorText ?? \"Sorry, something went wrong. Please try again in a moment.\",\n locale:\n o.locale ??\n (typeof navigator !== \"undefined\" ? navigator.language : undefined),\n accentColor: o.accentColor ?? \"#111827\",\n accentTextColor: o.accentTextColor ?? \"#ffffff\",\n showBranding: o.showBranding ?? true,\n position: o.position ?? \"bottom-right\",\n openOnLoad: o.openOnLoad ?? false,\n debounceMs: o.debounceMs ?? 700,\n container: o.container,\n systemPrompt: o.systemPrompt,\n clientPrompt: o.clientPrompt,\n lead: o.lead,\n capture: {\n fields: o.capture?.fields ?? [\"first_name\", \"email\"],\n mode: o.capture?.mode ?? \"before\",\n label: o.capture?.label ?? \"Tell us a bit about you to get started:\",\n submitLabel: o.capture?.submitLabel ?? \"Start chat\",\n },\n metadata: o.metadata,\n onOpen: o.onOpen,\n onClose: o.onClose,\n onMessage: o.onMessage,\n onLeadCaptured: o.onLeadCaptured,\n onError: o.onError,\n };\n}\n\n/**\n * Does this widget need to show a lead-capture form before chat?\n * - \"skip\" mode → no\n * - Pre-known lead already covers every required field → no\n * - Otherwise → yes\n */\nexport function needsCapture(cfg: ResolvedCfg): boolean {\n if (cfg.capture.mode === \"skip\") return false;\n if (cfg.lead) {\n const have = cfg.lead;\n return cfg.capture.fields.some((f) => !have[f]);\n }\n return true;\n}\n","/**\n * Browser-side session-id management for the chat widget.\n *\n * The session id links anonymous turns to the same lead across page reloads.\n * It's persisted in localStorage with a last-activity timestamp and a sliding\n * retention window: a conversation is kept for at least SESSION_RETENTION_MS\n * after the last activity, after which a fresh session (and transcript) starts.\n * If storage is unavailable (private mode, sandboxed iframe) we fall back to a\n * per-tab id and accept that a refresh starts a new conversation.\n */\n\nconst SESSION_KEY = \"nexor.chat.session_id\";\n\n/** Keep a conversation (session + transcript) this long after the last\n * activity, so a returning visitor can resume it. Reused by the transcript\n * cache in `./index`. The host (e.g. the landing widget) decides when to\n * auto-resume vs. prompt \"continue or start new\". */\nexport const SESSION_RETENTION_MS = 30 * 24 * 60 * 60 * 1000; // 30 days\n\n/**\n * Return the persisted session id, generating one on first use or once the\n * retention window has lapsed. Reading it slides the window forward.\n */\nexport function ensureSessionId(): string {\n const now = Date.now();\n try {\n const rec = readRecord();\n if (rec && now - rec.ts < SESSION_RETENTION_MS) {\n writeRecord(rec.id, now); // slide the window on activity\n return rec.id;\n }\n } catch {\n /* localStorage may be unavailable (private mode, sandboxed iframe). */\n }\n const id = `sess_${randomHex(16)}`;\n try {\n writeRecord(id, now);\n } catch {\n /* ignore — id is still valid for this page load. */\n }\n return id;\n}\n\n/** Bump the session's last-activity timestamp (slides the retention window). */\nexport function touchSession(): void {\n try {\n const rec = readRecord();\n if (rec) writeRecord(rec.id, Date.now());\n } catch {\n /* ignore */\n }\n}\n\nfunction readRecord(): { id: string; ts: number } | null {\n const raw = window.localStorage.getItem(SESSION_KEY);\n if (!raw) return null;\n try {\n const o = JSON.parse(raw);\n if (o && typeof o.id === \"string\" && typeof o.ts === \"number\") return o;\n } catch {\n /* legacy value was a plain \"sess_…\" string — adopt it below. */\n }\n if (raw.startsWith(\"sess_\")) return { id: raw, ts: Date.now() };\n return null;\n}\n\nfunction writeRecord(id: string, ts: number): void {\n window.localStorage.setItem(SESSION_KEY, JSON.stringify({ id, ts }));\n}\n\n/**\n * Hex string from cryptographically-strong randomness when available, with\n * a Math.random() fallback for very old browsers.\n */\nfunction randomHex(bytes: number): string {\n const arr = new Uint8Array(bytes);\n if (typeof crypto !== \"undefined\" && crypto.getRandomValues) {\n crypto.getRandomValues(arr);\n } else {\n for (let i = 0; i < bytes; i++) arr[i] = Math.floor(Math.random() * 256);\n }\n return Array.from(arr, (b) => b.toString(16).padStart(2, \"0\")).join(\"\");\n}\n","/**\n * Scoped CSS for the chat widget.\n *\n * Everything is namespaced under `.nexor-chat` so it cannot leak into the host\n * page, and properties that hosts commonly override (color, font, line-height)\n * are set explicitly here so the host's reset can't bleed in.\n *\n * Animations are GPU-friendly (transform + opacity only — no layout-trashing\n * properties like top/left) and use modest durations so the widget feels\n * responsive on low-end devices.\n */\nexport const widgetCss = (accent: string, accentText: string): string => `\n.nexor-chat,\n.nexor-chat * {\n box-sizing: border-box;\n font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, \"Helvetica Neue\", Arial, sans-serif;\n}\n\n.nexor-chat {\n position: fixed;\n z-index: 2147483640;\n bottom: 20px;\n right: 20px;\n font-size: 14px;\n line-height: 1.4;\n color: #111;\n}\n\n.nexor-chat[data-position=\"bottom-left\"] {\n right: auto;\n left: 20px;\n}\n\n/* ── Launcher bubble ─────────────────────────────────────────────── */\n.nexor-chat__launcher {\n width: 56px;\n height: 56px;\n border-radius: 9999px;\n background: ${accent};\n color: ${accentText};\n border: none;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n box-shadow: 0 6px 18px rgba(0, 0, 0, 0.18);\n transition: transform 160ms cubic-bezier(.2,.7,.2,1.1),\n box-shadow 160ms ease,\n background 200ms ease;\n padding: 0;\n position: relative;\n animation: nexor-launcher-in 360ms cubic-bezier(.2,.7,.2,1.1) both;\n}\n.nexor-chat__launcher:hover {\n transform: translateY(-2px) scale(1.04);\n box-shadow: 0 10px 24px rgba(0, 0, 0, 0.24);\n}\n.nexor-chat__launcher:active {\n transform: translateY(0) scale(0.97);\n transition-duration: 80ms;\n}\n.nexor-chat__launcher:focus-visible {\n outline: 2px solid ${accent};\n outline-offset: 2px;\n}\n.nexor-chat[data-open=\"true\"] .nexor-chat__launcher {\n transform: scale(0.85);\n opacity: 0.75;\n}\n.nexor-chat__launcher svg { width: 24px; height: 24px; transition: transform 200ms ease; }\n.nexor-chat[data-open=\"true\"] .nexor-chat__launcher svg { transform: rotate(8deg); }\n\n.nexor-chat__unread {\n position: absolute;\n top: -4px;\n right: -4px;\n min-width: 18px;\n height: 18px;\n background: #ef4444;\n color: #fff;\n border-radius: 9999px;\n font-size: 11px;\n font-weight: 600;\n padding: 0 5px;\n display: flex;\n align-items: center;\n justify-content: center;\n border: 2px solid #fff;\n animation: nexor-pop-in 300ms cubic-bezier(.2,.7,.2,1.1) both;\n}\n\n@keyframes nexor-launcher-in {\n from { transform: translateY(20px) scale(0.6); opacity: 0; }\n to { transform: translateY(0) scale(1); opacity: 1; }\n}\n@keyframes nexor-pop-in {\n from { transform: scale(0); }\n to { transform: scale(1); }\n}\n\n/* ── Panel ────────────────────────────────────────────────────────── */\n.nexor-chat__panel {\n position: absolute;\n bottom: 72px;\n right: 0;\n width: 360px;\n max-width: calc(100vw - 32px);\n height: 540px;\n max-height: calc(100vh - 120px);\n background: #fff;\n border-radius: 14px;\n box-shadow: 0 24px 60px rgba(0, 0, 0, 0.22);\n display: flex;\n flex-direction: column;\n overflow: hidden;\n transform: translateY(14px) scale(0.96);\n opacity: 0;\n pointer-events: none;\n transition: transform 220ms cubic-bezier(.2,.7,.2,1.1),\n opacity 220ms ease;\n border: 1px solid rgba(0, 0, 0, 0.06);\n /* Use visibility so screen readers don't read collapsed content */\n visibility: hidden;\n}\n.nexor-chat[data-position=\"bottom-left\"] .nexor-chat__panel {\n right: auto;\n left: 0;\n}\n.nexor-chat[data-open=\"true\"] .nexor-chat__panel {\n transform: translateY(0) scale(1);\n opacity: 1;\n pointer-events: auto;\n visibility: visible;\n}\n\n.nexor-chat__header {\n background: ${accent};\n color: ${accentText};\n padding: 14px 16px;\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 12px;\n}\n.nexor-chat__title {\n font-weight: 600;\n font-size: 15px;\n margin: 0;\n}\n.nexor-chat__subtitle {\n font-size: 12px;\n opacity: 0.85;\n margin: 2px 0 0;\n}\n.nexor-chat__status-dot {\n display: inline-block;\n width: 8px;\n height: 8px;\n border-radius: 9999px;\n background: #34d399;\n margin-right: 6px;\n vertical-align: 1px;\n animation: nexor-pulse 2.4s ease-in-out infinite;\n box-shadow: 0 0 0 0 rgba(52, 211, 153, 0.6);\n}\n@keyframes nexor-pulse {\n 0%, 100% { box-shadow: 0 0 0 0 rgba(52, 211, 153, 0.55); }\n 50% { box-shadow: 0 0 0 6px rgba(52, 211, 153, 0); }\n}\n.nexor-chat__close {\n background: transparent;\n border: none;\n color: inherit;\n cursor: pointer;\n padding: 4px;\n border-radius: 6px;\n opacity: 0.9;\n transition: background 140ms ease, transform 140ms ease;\n}\n.nexor-chat__close:hover { background: rgba(255,255,255,0.18); opacity: 1; }\n.nexor-chat__close:active { transform: scale(0.92); }\n.nexor-chat__close svg { width: 18px; height: 18px; display: block; }\n\n/* ── Body / messages ──────────────────────────────────────────────── */\n.nexor-chat__body {\n flex: 1;\n overflow-y: auto;\n padding: 14px;\n background: #f6f7f9;\n display: flex;\n flex-direction: column;\n gap: 8px;\n scroll-behavior: smooth;\n /* Prevent layout shift when scrollbar appears */\n scrollbar-gutter: stable;\n}\n.nexor-chat__body::-webkit-scrollbar { width: 6px; }\n.nexor-chat__body::-webkit-scrollbar-thumb {\n background: rgba(0,0,0,0.15);\n border-radius: 9999px;\n}\n\n.nexor-chat__msg {\n max-width: 80%;\n padding: 8px 12px;\n border-radius: 14px;\n white-space: pre-wrap;\n word-wrap: break-word;\n animation: nexor-msg-in 240ms cubic-bezier(.2,.7,.2,1.1) both;\n will-change: transform, opacity;\n}\n.nexor-chat__msg--bot {\n background: #fff;\n align-self: flex-start;\n border: 1px solid rgba(0,0,0,0.06);\n border-bottom-left-radius: 4px;\n box-shadow: 0 1px 2px rgba(0,0,0,0.04);\n}\n.nexor-chat__msg--user {\n background: ${accent};\n color: ${accentText};\n align-self: flex-end;\n border-bottom-right-radius: 4px;\n animation-name: nexor-msg-in-user;\n}\n.nexor-chat__msg--system {\n background: transparent;\n color: #6b7280;\n font-size: 12px;\n align-self: center;\n text-align: center;\n max-width: 100%;\n animation-name: nexor-fade-in;\n}\n.nexor-chat__msg-time {\n display: block;\n margin-top: 4px;\n font-size: 10px;\n line-height: 1;\n opacity: 0.55;\n text-align: right;\n}\n.nexor-chat__msg--bot .nexor-chat__msg-time { text-align: left; }\n\n@keyframes nexor-msg-in {\n from { transform: translateY(8px) scale(0.96); opacity: 0; }\n to { transform: translateY(0) scale(1); opacity: 1; }\n}\n@keyframes nexor-msg-in-user {\n from { transform: translateY(8px) translateX(8px) scale(0.96); opacity: 0; }\n to { transform: translateY(0) translateX(0) scale(1); opacity: 1; }\n}\n@keyframes nexor-fade-in {\n from { opacity: 0; }\n to { opacity: 1; }\n}\n\n.nexor-chat__typing {\n align-self: flex-start;\n background: #fff;\n border: 1px solid rgba(0,0,0,0.06);\n border-radius: 14px;\n border-bottom-left-radius: 4px;\n padding: 10px 14px;\n display: inline-flex;\n gap: 4px;\n animation: nexor-msg-in 240ms cubic-bezier(.2,.7,.2,1.1) both;\n}\n.nexor-chat__typing span {\n width: 6px; height: 6px; border-radius: 9999px;\n background: #9ca3af;\n display: inline-block;\n animation: nexor-blink 1.2s infinite ease-in-out;\n}\n.nexor-chat__typing span:nth-child(2) { animation-delay: 0.15s; }\n.nexor-chat__typing span:nth-child(3) { animation-delay: 0.30s; }\n@keyframes nexor-blink {\n 0%, 60%, 100% { opacity: 0.3; transform: translateY(0); }\n 30% { opacity: 1; transform: translateY(-3px); }\n}\n\n/* ── Lead capture form ────────────────────────────────────────────── */\n.nexor-chat__capture {\n background: #fff;\n border: 1px solid rgba(0,0,0,0.06);\n border-radius: 12px;\n padding: 12px;\n display: flex;\n flex-direction: column;\n gap: 8px;\n margin-top: 4px;\n animation: nexor-msg-in 280ms cubic-bezier(.2,.7,.2,1.1) both;\n box-shadow: 0 2px 8px rgba(0,0,0,0.05);\n}\n.nexor-chat__capture-label {\n font-size: 12px;\n color: #6b7280;\n margin: 0;\n}\n.nexor-chat__capture-row {\n display: flex;\n gap: 8px;\n}\n.nexor-chat__capture-row > * { flex: 1; }\n.nexor-chat__input,\n.nexor-chat__capture input {\n font: inherit;\n padding: 8px 10px;\n border: 1px solid #d1d5db;\n border-radius: 8px;\n background: #fff;\n color: #111;\n outline: none;\n width: 100%;\n transition: border-color 140ms ease, box-shadow 140ms ease;\n}\n.nexor-chat__input:focus,\n.nexor-chat__capture input:focus {\n border-color: ${accent};\n box-shadow: 0 0 0 3px ${accent}33;\n}\n.nexor-chat__capture-submit {\n background: ${accent};\n color: ${accentText};\n border: none;\n border-radius: 8px;\n padding: 8px 12px;\n font: inherit;\n font-weight: 600;\n cursor: pointer;\n transition: transform 140ms ease, filter 140ms ease;\n}\n.nexor-chat__capture-submit:hover { filter: brightness(1.08); }\n.nexor-chat__capture-submit:active { transform: scale(0.97); }\n.nexor-chat__capture-submit[disabled] { opacity: 0.6; cursor: not-allowed; }\n\n/* ── Composer ─────────────────────────────────────────────────────── */\n.nexor-chat__composer {\n display: flex;\n gap: 8px;\n padding: 10px;\n background: #fff;\n border-top: 1px solid rgba(0,0,0,0.06);\n align-items: stretch;\n}\n.nexor-chat__send {\n background: ${accent};\n color: ${accentText};\n border: none;\n border-radius: 8px;\n padding: 0 14px;\n font: inherit;\n font-weight: 600;\n cursor: pointer;\n min-width: 44px;\n display: flex;\n align-items: center;\n justify-content: center;\n transition: transform 140ms ease, filter 140ms ease;\n}\n.nexor-chat__send:hover { filter: brightness(1.08); }\n.nexor-chat__send:active { transform: scale(0.95); }\n.nexor-chat__send[disabled] {\n opacity: 0.6;\n cursor: not-allowed;\n transform: none;\n}\n.nexor-chat__send svg {\n width: 18px;\n height: 18px;\n transition: transform 200ms ease;\n}\n.nexor-chat__send:not([disabled]):hover svg { transform: translateX(2px); }\n\n/* Small spinner inside the send button while a turn is in flight */\n.nexor-chat__send--loading svg { display: none; }\n.nexor-chat__send--loading::after {\n content: \"\";\n width: 14px;\n height: 14px;\n border-radius: 9999px;\n border: 2px solid currentColor;\n border-top-color: transparent;\n animation: nexor-spin 700ms linear infinite;\n}\n@keyframes nexor-spin {\n to { transform: rotate(360deg); }\n}\n\n.nexor-chat__footer {\n text-align: center;\n font-size: 11px;\n color: #9ca3af;\n padding: 6px;\n background: #fff;\n border-top: 1px solid rgba(0,0,0,0.04);\n}\n.nexor-chat__footer a {\n color: inherit;\n text-decoration: none;\n font-weight: 600;\n}\n.nexor-chat__footer a:hover { text-decoration: underline; }\n\n/* Respect users who request reduced motion. */\n@media (prefers-reduced-motion: reduce) {\n .nexor-chat,\n .nexor-chat * {\n animation-duration: 0.001ms !important;\n transition-duration: 0.001ms !important;\n }\n .nexor-chat__status-dot { animation: none; }\n}\n`;\n","/**\n * Pure DOM construction for the chat widget.\n *\n * Each `build*` function returns a fully-formed sub-tree plus refs to the\n * inner nodes the orchestrator (initChat) wires events to. No side effects\n * here other than calling `injectStyles()` once per page.\n *\n * Why split this out from index.ts?\n * - The DOM layer doesn't depend on the NexorClient or sessionId — keeping\n * it pure makes the widget easy to reason about and easy to dry-run in\n * unit tests by mocking `document`.\n * - The orchestrator becomes a 150-line state machine instead of a\n * 600-line god-function.\n */\nimport { needsCapture, type ResolvedCfg } from \"./config\";\nimport { widgetCss } from \"./styles\";\n\nconst STYLE_ATTR = \"data-nexor-chat-styles\";\n\n// ─── Stylesheet (singleton per page) ───────────────────────────────────────\n\n/**\n * Inject the widget's stylesheet once per page. If multiple widgets mount,\n * they share styles and the first widget's accent colour wins. Two widgets\n * with different accents on one page is an unsupported use case.\n */\nexport function injectStyles(accent: string, accentText: string): void {\n if (document.querySelector(`style[${STYLE_ATTR}]`)) return;\n const style = document.createElement(\"style\");\n style.setAttribute(STYLE_ATTR, \"1\");\n style.textContent = widgetCss(accent, accentText);\n document.head.appendChild(style);\n}\n\n// ─── Launcher ──────────────────────────────────────────────────────────────\n\nexport interface LauncherRefs {\n el: HTMLButtonElement;\n badge: HTMLSpanElement;\n}\n\nexport function buildLauncher(): LauncherRefs {\n const el = document.createElement(\"button\");\n el.type = \"button\";\n el.className = \"nexor-chat__launcher\";\n el.setAttribute(\"aria-label\", \"Open chat\");\n // Speech-bubble icon — SVG rather than emoji for crisp rendering at any DPR.\n el.innerHTML = `\n <svg viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\" aria-hidden=\"true\">\n <path d=\"M4 5.5C4 4.67 4.67 4 5.5 4h13c.83 0 1.5.67 1.5 1.5v9c0 .83-.67 1.5-1.5 1.5H9l-4 4V5.5Z\"\n stroke=\"currentColor\" stroke-width=\"1.8\" stroke-linejoin=\"round\"/>\n </svg>\n `;\n const badge = document.createElement(\"span\");\n badge.className = \"nexor-chat__unread\";\n badge.style.display = \"none\";\n el.appendChild(badge);\n return { el, badge };\n}\n\n// ─── Panel ─────────────────────────────────────────────────────────────────\n\ntype CaptureField = \"first_name\" | \"last_name\" | \"email\" | \"phone\";\n\nexport interface PanelRefs {\n el: HTMLDivElement;\n closeBtn: HTMLButtonElement;\n body: HTMLDivElement;\n form: HTMLFormElement;\n input: HTMLInputElement;\n send: HTMLButtonElement;\n captureForm: HTMLFormElement | null;\n captureInputs: Partial<Record<CaptureField, HTMLInputElement>>;\n}\n\nexport function buildPanel(cfg: ResolvedCfg): PanelRefs {\n const el = document.createElement(\"div\");\n el.className = \"nexor-chat__panel\";\n el.setAttribute(\"role\", \"dialog\");\n el.setAttribute(\"aria-label\", cfg.title);\n\n const { header, closeBtn } = buildHeader(cfg);\n const { body, captureForm, captureInputs } = buildBody(cfg);\n const { form, input, send } = buildComposer();\n const footer = cfg.showBranding ? buildFooter() : null;\n\n el.appendChild(header);\n el.appendChild(body);\n el.appendChild(form);\n if (footer) el.appendChild(footer);\n\n return { el, closeBtn, body, form, input, send, captureForm, captureInputs };\n}\n\nfunction buildHeader(cfg: ResolvedCfg): {\n header: HTMLDivElement;\n closeBtn: HTMLButtonElement;\n} {\n const header = document.createElement(\"div\");\n header.className = \"nexor-chat__header\";\n\n // The status dot signals \"we're live and listening\" — purely cosmetic, but\n // a strong UX signal. Hidden from assistive tech because the title carries\n // the meaning already.\n const subtitleHtml = cfg.subtitle\n ? `<p class=\"nexor-chat__subtitle\">\n <span class=\"nexor-chat__status-dot\" aria-hidden=\"true\"></span>${escapeHtml(cfg.subtitle)}\n </p>`\n : \"\";\n\n header.innerHTML = `\n <div>\n <p class=\"nexor-chat__title\">${escapeHtml(cfg.title)}</p>\n ${subtitleHtml}\n </div>\n `;\n\n const closeBtn = document.createElement(\"button\");\n closeBtn.type = \"button\";\n closeBtn.className = \"nexor-chat__close\";\n closeBtn.setAttribute(\"aria-label\", \"Close chat\");\n closeBtn.innerHTML = `\n <svg viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\" aria-hidden=\"true\">\n <path d=\"M6 6l12 12M6 18L18 6\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\"/>\n </svg>\n `;\n header.appendChild(closeBtn);\n return { header, closeBtn };\n}\n\nfunction buildBody(cfg: ResolvedCfg): {\n body: HTMLDivElement;\n captureForm: HTMLFormElement | null;\n captureInputs: Partial<Record<CaptureField, HTMLInputElement>>;\n} {\n const body = document.createElement(\"div\");\n body.className = \"nexor-chat__body\";\n const captureInputs: Partial<Record<CaptureField, HTMLInputElement>> = {};\n let captureForm: HTMLFormElement | null = null;\n\n if (needsCapture(cfg)) {\n captureForm = buildCaptureForm(cfg, captureInputs);\n body.appendChild(captureForm);\n }\n return { body, captureForm, captureInputs };\n}\n\nfunction buildCaptureForm(\n cfg: ResolvedCfg,\n inputsOut: Partial<Record<CaptureField, HTMLInputElement>>,\n): HTMLFormElement {\n const form = document.createElement(\"form\");\n form.className = \"nexor-chat__capture\";\n form.noValidate = true;\n\n const label = document.createElement(\"p\");\n label.className = \"nexor-chat__capture-label\";\n label.textContent = cfg.capture.label;\n form.appendChild(label);\n\n const fields = cfg.capture.fields;\n\n // first_name + last_name share a row to feel like a single \"your name\" prompt.\n if (fields.includes(\"first_name\") || fields.includes(\"last_name\")) {\n const row = document.createElement(\"div\");\n row.className = \"nexor-chat__capture-row\";\n if (fields.includes(\"first_name\")) {\n inputsOut.first_name = makeInput(\"first_name\", \"First name\", \"text\", cfg.lead?.first_name);\n row.appendChild(inputsOut.first_name);\n }\n if (fields.includes(\"last_name\")) {\n inputsOut.last_name = makeInput(\"last_name\", \"Last name\", \"text\", cfg.lead?.last_name);\n row.appendChild(inputsOut.last_name);\n }\n if (row.childElementCount > 0) form.appendChild(row);\n }\n if (fields.includes(\"email\")) {\n inputsOut.email = makeInput(\"email\", \"Email\", \"email\", cfg.lead?.email);\n form.appendChild(inputsOut.email);\n }\n if (fields.includes(\"phone\")) {\n inputsOut.phone = makeInput(\"phone\", \"Phone\", \"tel\", cfg.lead?.phone);\n form.appendChild(inputsOut.phone);\n }\n\n const submit = document.createElement(\"button\");\n submit.type = \"submit\";\n submit.className = \"nexor-chat__capture-submit\";\n submit.textContent = cfg.capture.submitLabel;\n form.appendChild(submit);\n\n return form;\n}\n\nfunction buildComposer(): {\n form: HTMLFormElement;\n input: HTMLInputElement;\n send: HTMLButtonElement;\n} {\n const form = document.createElement(\"form\");\n form.className = \"nexor-chat__composer\";\n\n const input = document.createElement(\"input\");\n input.type = \"text\";\n input.className = \"nexor-chat__input\";\n input.placeholder = \"Type a message…\";\n input.autocomplete = \"off\";\n\n const send = document.createElement(\"button\");\n send.type = \"submit\";\n send.className = \"nexor-chat__send\";\n send.setAttribute(\"aria-label\", \"Send message\");\n // Paper-airplane icon — language-agnostic, recognisable, replaces \"Send\" text.\n send.innerHTML = `\n <svg viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\" aria-hidden=\"true\">\n <path d=\"M3.4 11.2 20.5 4.3c.7-.3 1.4.4 1.1 1.1l-6.9 17.1c-.3.8-1.4.8-1.8 0L10 14l-7.5-3c-.8-.3-.8-1.5 0-1.8Z\"\n stroke=\"currentColor\" stroke-width=\"1.6\" stroke-linejoin=\"round\" fill=\"currentColor\"/>\n </svg>\n `;\n\n form.appendChild(input);\n form.appendChild(send);\n return { form, input, send };\n}\n\nfunction buildFooter(): HTMLDivElement {\n const el = document.createElement(\"div\");\n el.className = \"nexor-chat__footer\";\n el.innerHTML = `Powered by <a href=\"https://www.getnexor.ai\" target=\"_blank\" rel=\"noopener noreferrer\">Nexor</a>`;\n return el;\n}\n\n// ─── Message bubbles ───────────────────────────────────────────────────────\n\nexport type MessageRole = \"user\" | \"bot\" | \"system\";\n\n/**\n * Build a chat bubble. `textContent` is used (never innerHTML) so user input\n * is rendered as plain text — no XSS surface from message payloads.\n */\nexport function buildMessage(\n role: MessageRole,\n text: string,\n ts?: number,\n locale?: string,\n): HTMLDivElement {\n const el = document.createElement(\"div\");\n el.className = `nexor-chat__msg nexor-chat__msg--${role}`;\n const body = document.createElement(\"span\");\n body.className = \"nexor-chat__msg-text\";\n body.textContent = text;\n el.appendChild(body);\n // Relative time under user/bot messages (not system notices). `data-ts` lets\n // the widget refresh the label as time passes (see index.ts).\n if (role !== \"system\" && ts) {\n const time = document.createElement(\"time\");\n time.className = \"nexor-chat__msg-time\";\n time.dataset.ts = String(ts);\n time.textContent = formatRelativeTime(ts, locale);\n el.appendChild(time);\n }\n return el;\n}\n\n/**\n * Relative within the last week (\"ahora\", \"hace 3 minutos\", \"hace 2 horas\",\n * \"ayer\"), then an absolute date (\"12 may\"). Localized via Intl; falls back to\n * a plain clock time if Intl.RelativeTimeFormat is unavailable.\n */\nexport function formatRelativeTime(\n ts: number,\n locale?: string,\n now: number = Date.now(),\n): string {\n try {\n const diff = Math.max(0, now - ts);\n const min = Math.round(diff / 60000);\n const hr = Math.round(diff / 3600000);\n const day = Math.round(diff / 86400000);\n const rtf = new Intl.RelativeTimeFormat(locale, { numeric: \"auto\" });\n if (diff < 45000) return rtf.format(0, \"second\"); // \"ahora\" / \"now\"\n if (min < 60) return rtf.format(-min, \"minute\");\n if (hr < 24) return rtf.format(-hr, \"hour\");\n if (day < 7) return rtf.format(-day, \"day\"); // includes \"ayer\"/\"yesterday\"\n return new Date(ts).toLocaleDateString(locale, {\n day: \"numeric\",\n month: \"short\",\n });\n } catch {\n try {\n return new Date(ts).toLocaleTimeString(locale, {\n hour: \"2-digit\",\n minute: \"2-digit\",\n });\n } catch {\n return \"\";\n }\n }\n}\n\n/** Three-dot typing indicator. Animation lives in styles.ts. */\nexport function buildTypingIndicator(): HTMLDivElement {\n const el = document.createElement(\"div\");\n el.className = \"nexor-chat__typing\";\n el.innerHTML = \"<span></span><span></span><span></span>\";\n return el;\n}\n\n// ─── Helpers ───────────────────────────────────────────────────────────────\n\nfunction makeInput(\n name: string,\n placeholder: string,\n type: string,\n value?: string,\n): HTMLInputElement {\n const i = document.createElement(\"input\");\n i.name = name;\n i.type = type;\n i.placeholder = placeholder;\n if (value) i.value = value;\n return i;\n}\n\n/**\n * Escape strings before interpolation into innerHTML. Used only for\n * SDK-controlled config values (title, subtitle) — user-typed messages\n * always go through textContent, which doesn't need escaping.\n */\nfunction escapeHtml(s: string): string {\n return s\n .replace(/&/g, \"&amp;\")\n .replace(/</g, \"&lt;\")\n .replace(/>/g, \"&gt;\")\n .replace(/\"/g, \"&quot;\")\n .replace(/'/g, \"&#039;\");\n}\n","/**\n * Chat widget orchestrator.\n *\n * Responsibilities (everything else lives in sibling files):\n * - apply defaults / validate options (`./config`)\n * - manage session id (`./session`)\n * - build DOM (`./dom`)\n * - inject CSS (`./dom`)\n *\n * What stays here:\n * - the open/close state machine\n * - wiring DOM events to the NexorClient.chat() call\n * - lead-capture submission flow\n * - the public ChatHandle returned to callers\n */\nimport type { NexorClient } from \"../client\";\nimport type { UUID } from \"../types\";\nimport {\n applyDefaults,\n needsCapture,\n type ChatInitOptions,\n type ChatHandle,\n type ResolvedCfg,\n} from \"./config\";\nimport { ensureSessionId, touchSession, SESSION_RETENTION_MS } from \"./session\";\nimport {\n buildLauncher,\n buildMessage,\n buildPanel,\n buildTypingIndicator,\n formatRelativeTime,\n injectStyles,\n type LauncherRefs,\n type MessageRole,\n type PanelRefs,\n} from \"./dom\";\n\n// Re-export the public types so consumers can `import type { ChatHandle } from \"@getnexorai/sdk\"`.\nexport type { ChatInitOptions, ChatHandle, ChatLeadCapture } from \"./config\";\n\n// Delay before showing the typing indicator. Short replies arrive before this\n// fires and never show the dots, which feels snappier than always flashing them.\nconst TYPING_DELAY_MS = 220;\n\n/**\n * Mount the chat widget and return a handle for programmatic control.\n *\n * @param client The NexorClient instance that will send turns.\n * @param options User-facing widget configuration. See ChatInitOptions.\n * @throws If called outside a browser, or without a workflowId.\n */\nexport function initChat(\n client: NexorClient,\n options: ChatInitOptions,\n): ChatHandle {\n ensureBrowser();\n if (!options || !options.workflowId) {\n throw new Error(\"Nexor SDK: initChat() requires `workflowId`.\");\n }\n\n const cfg = applyDefaults(options);\n injectStyles(cfg.accentColor, cfg.accentTextColor);\n\n const sessionId = ensureSessionId();\n const historyKey = `nexor.chat.history.${sessionId}`;\n const root = buildRoot(cfg);\n const launcher = buildLauncher();\n const panel = buildPanel(cfg);\n root.appendChild(launcher.el);\n root.appendChild(panel.el);\n (cfg.container ?? document.body).appendChild(root);\n\n // ─── State (closure-private — no external observers needed) ─────────────\n const state = {\n isOpen: false,\n unread: 0,\n leadId: undefined as UUID | undefined,\n captured: !needsCapture(cfg),\n pendingLead: { ...(cfg.lead ?? {}) },\n history: [] as Array<{ role: \"user\" | \"bot\"; text: string; ts?: number }>,\n };\n\n // ─── DOM event wiring ───────────────────────────────────────────────────\n launcher.el.addEventListener(\"click\", toggle);\n panel.closeBtn.addEventListener(\"click\", close);\n panel.form.addEventListener(\"submit\", onComposerSubmit);\n panel.captureForm?.addEventListener(\"submit\", onCaptureSubmit);\n\n syncComposerLock();\n\n // Restore a prior transcript (persisted up to SESSION_RETENTION_MS) so a\n // page reload keeps the conversation. Rendered into the (possibly closed)\n // panel; the greeting is then skipped because history is non-empty.\n const restored = loadHistory();\n if (restored.length) {\n state.history = restored;\n for (const m of restored) appendBubble(m.role === \"user\" ? \"user\" : \"bot\", m.text, m.ts);\n scrollToBottom();\n }\n\n if (cfg.openOnLoad) open();\n\n // ─── State machine ──────────────────────────────────────────────────────\n\n function open(): void {\n if (state.isOpen) return;\n state.isOpen = true;\n root.setAttribute(\"data-open\", \"true\");\n clearUnread();\n // Lazy-greet: first time the panel opens, drop the greeting message.\n if (state.history.length === 0 && cfg.greeting && state.captured) {\n appendBot(cfg.greeting);\n }\n panel.input.focus();\n cfg.onOpen?.();\n }\n\n function close(): void {\n if (!state.isOpen) return;\n state.isOpen = false;\n root.setAttribute(\"data-open\", \"false\");\n cfg.onClose?.();\n }\n\n function toggle(): void {\n state.isOpen ? close() : open();\n }\n\n // ─── Capture flow ───────────────────────────────────────────────────────\n\n function onCaptureSubmit(e: Event): void {\n e.preventDefault();\n const collected = readCaptureFields(panel);\n // Validate that all required fields are filled before unlocking the chat.\n const required = cfg.capture.fields;\n for (const f of required) {\n if (!collected[f]) {\n panel.captureInputs[f]?.focus();\n return;\n }\n }\n state.pendingLead = { ...state.pendingLead, ...collected };\n state.captured = true;\n panel.captureForm?.remove();\n syncComposerLock();\n panel.input.focus();\n // Greet once capture clears, so the greeting feels like a response to \"I'm ready\".\n if (cfg.greeting && state.history.length === 0) appendBot(cfg.greeting);\n }\n\n // ─── Composer / send (debounced + coalesced) ────────────────────────────\n //\n // Visitors fire several short messages in a row (WhatsApp-style). We mirror\n // the WhatsApp contract — batch at the source, one LLM call per batch — by\n // buffering rapid messages in the browser and POSTing them as a SINGLE\n // combined turn after a short quiet window. The composer never locks, so the\n // user can keep typing and sending freely; messages that land mid-request are\n // sent in the next batch.\n\n const send = {\n pending: [] as string[],\n timer: 0,\n typingTimer: 0,\n inFlight: false,\n typing: null as HTMLElement | null,\n };\n\n function onComposerSubmit(e: Event): void {\n e.preventDefault();\n const text = panel.input.value.trim();\n if (!text) return;\n panel.input.value = \"\";\n queueMessage(text);\n }\n\n function queueMessage(text: string): void {\n if (!state.captured) {\n panel.captureInputs.first_name?.focus();\n return;\n }\n appendUser(text);\n send.pending.push(text);\n scheduleFlush();\n }\n\n function scheduleFlush(): void {\n if (send.timer) window.clearTimeout(send.timer);\n send.timer = window.setTimeout(() => void flush(), cfg.debounceMs);\n }\n\n async function flush(): Promise<void> {\n if (send.inFlight || send.pending.length === 0) return;\n const batch = send.pending.splice(0, send.pending.length);\n const message = batch.join(\"\\n\");\n send.inFlight = true;\n\n // Delay the typing dots so fast replies don't flash them.\n send.typingTimer = window.setTimeout(() => {\n send.typing = appendNode(buildTypingIndicator());\n }, TYPING_DELAY_MS);\n\n try {\n const res = await client.chat({\n workflow_id: cfg.workflowId,\n session_id: sessionId,\n message,\n system_prompt: cfg.systemPrompt,\n client_prompt: cfg.clientPrompt,\n lead: Object.keys(state.pendingLead).length ? state.pendingLead : undefined,\n metadata: cfg.metadata,\n });\n if (res.lead_id && !state.leadId) {\n state.leadId = res.lead_id;\n cfg.onLeadCaptured?.(state.leadId);\n }\n const reply = (res.reply ?? \"\").trim();\n if (reply) {\n appendBot(reply);\n } else {\n // No text came back (empty completion / tool-only turn). Never render a\n // blank bubble — show the fallback and surface it to the host.\n appendSystem(cfg.errorText);\n cfg.onError?.(new Error(\"Nexor SDK: empty reply from server\"));\n }\n } catch (err) {\n appendSystem(cfg.errorText);\n cfg.onError?.(err as Error);\n } finally {\n window.clearTimeout(send.typingTimer);\n send.typing?.remove();\n send.typing = null;\n send.inFlight = false;\n panel.input.focus();\n // Anything queued while the request was in flight goes out next.\n if (send.pending.length) scheduleFlush();\n }\n }\n\n // ─── Message rendering ──────────────────────────────────────────────────\n\n function appendUser(text: string): void {\n const ts = Date.now();\n appendBubble(\"user\", text, ts);\n state.history.push({ role: \"user\", text, ts });\n saveHistory();\n cfg.onMessage?.({ role: \"user\", text });\n }\n\n function appendBot(text: string): void {\n const ts = Date.now();\n appendBubble(\"bot\", text, ts);\n state.history.push({ role: \"bot\", text, ts });\n saveHistory();\n if (!state.isOpen) bumpUnread();\n cfg.onMessage?.({ role: \"bot\", text });\n }\n\n // ─── Transcript persistence (survives reloads up to SESSION_RETENTION_MS) ──\n\n function saveHistory(): void {\n try {\n window.localStorage.setItem(\n historyKey,\n JSON.stringify({ ts: Date.now(), history: state.history }),\n );\n touchSession(); // keep the session alive in step with the transcript\n } catch {\n /* storage unavailable — in-memory history still works for this load. */\n }\n }\n\n function loadHistory(): Array<{ role: \"user\" | \"bot\"; text: string; ts?: number }> {\n try {\n const raw = window.localStorage.getItem(historyKey);\n if (!raw) return [];\n const o = JSON.parse(raw);\n if (!o || !Array.isArray(o.history)) return [];\n if (Date.now() - (o.ts || 0) > SESSION_RETENTION_MS) {\n window.localStorage.removeItem(historyKey);\n return [];\n }\n return o.history;\n } catch {\n return [];\n }\n }\n\n function appendSystem(text: string): void {\n appendBubble(\"system\", text);\n }\n\n function appendBubble(\n role: MessageRole,\n text: string,\n ts?: number,\n ): HTMLDivElement {\n return appendNode(buildMessage(role, text, ts, cfg.locale));\n }\n\n // Keep relative timestamps (\"hace 3 minutos\") fresh while the panel is open.\n const refreshTimer = window.setInterval(() => {\n panel.body\n .querySelectorAll<HTMLTimeElement>(\".nexor-chat__msg-time[data-ts]\")\n .forEach((el) => {\n const ts = Number(el.dataset.ts);\n if (ts) el.textContent = formatRelativeTime(ts, cfg.locale);\n });\n }, 60_000);\n\n function appendNode<T extends HTMLElement>(node: T): T {\n panel.body.appendChild(node);\n scrollToBottom();\n return node;\n }\n\n function scrollToBottom(): void {\n panel.body.scrollTop = panel.body.scrollHeight;\n }\n\n // ─── Unread badge ───────────────────────────────────────────────────────\n\n function bumpUnread(): void {\n state.unread++;\n launcher.badge.textContent = String(state.unread);\n launcher.badge.style.display = \"flex\";\n }\n function clearUnread(): void {\n state.unread = 0;\n launcher.badge.style.display = \"none\";\n }\n\n // ─── Composer lock (used while capture form is visible) ─────────────────\n\n function syncComposerLock(): void {\n const lock = !state.captured;\n panel.input.disabled = lock;\n panel.send.disabled = lock;\n panel.input.placeholder = lock\n ? \"Complete the form above to start…\"\n : \"Type a message…\";\n }\n\n // ─── Public handle ──────────────────────────────────────────────────────\n\n return {\n open,\n close,\n toggle,\n // Programmatic send goes through the same debounce/coalesce path. Resolves\n // immediately — the message is queued, not necessarily sent yet.\n send: (text: string) => {\n queueMessage(text);\n return Promise.resolve();\n },\n destroy: () => {\n if (send.timer) window.clearTimeout(send.timer);\n if (send.typingTimer) window.clearTimeout(send.typingTimer);\n window.clearInterval(refreshTimer);\n root.remove();\n },\n getSessionId: () => sessionId,\n };\n}\n\n// ─── Module-scoped helpers ────────────────────────────────────────────────\n\nfunction ensureBrowser(): void {\n if (typeof window === \"undefined\" || typeof document === \"undefined\") {\n throw new Error(\"Nexor SDK: initChat() requires a browser environment.\");\n }\n}\n\nfunction buildRoot(cfg: ResolvedCfg): HTMLDivElement {\n const root = document.createElement(\"div\");\n root.className = \"nexor-chat\";\n root.setAttribute(\"data-position\", cfg.position);\n root.setAttribute(\"data-open\", \"false\");\n return root;\n}\n\nfunction readCaptureFields(panel: PanelRefs): Record<string, string> {\n const out: Record<string, string> = {};\n const inputs = panel.captureInputs;\n if (inputs.first_name) out.first_name = inputs.first_name.value.trim();\n if (inputs.last_name) out.last_name = inputs.last_name.value.trim();\n if (inputs.email) out.email = inputs.email.value.trim();\n if (inputs.phone) out.phone = inputs.phone.value.trim();\n return out;\n}\n\n// Used by initChat's launcher → keeps the ref objects in scope for TS.\ntype _Refs = LauncherRefs & PanelRefs;\nvoid (null as unknown as _Refs);\n"]}
1
+ {"version":3,"sources":["../src/chat/config.ts","../src/chat/session.ts","../src/chat/styles.ts","../src/chat/dom.ts","../src/chat/index.ts"],"names":[],"mappings":"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","file":"chat.cjs","sourcesContent":["/**\n * Chat widget configuration types + defaults.\n *\n * Kept separate from the widget's runtime code so other modules (and the\n * top-level `nexor.initChat()` re-export) can pull types without dragging in\n * the DOM construction code.\n */\nimport type { UUID } from \"../types\";\n\n// ─── Public option / handle types ──────────────────────────────────────────\n\nexport interface ChatLeadCapture {\n /** Which fields to ask for before chatting. Defaults to [\"first_name\", \"email\"]. */\n fields?: Array<\"first_name\" | \"last_name\" | \"email\" | \"phone\">;\n /** \"before\" gates chat behind the form; \"skip\" never asks. Default \"before\". */\n mode?: \"before\" | \"skip\";\n /** Label rendered above the form. */\n label?: string;\n /** Submit button label. */\n submitLabel?: string;\n}\n\nexport interface ChatInitOptions {\n /** Workflow that handles this chat conversation. Required. */\n workflowId: UUID;\n\n // ── Identity / branding ──\n title?: string;\n subtitle?: string;\n greeting?: string;\n /** Shown when a turn fails or the server returns no reply. */\n errorText?: string;\n /** BCP-47 locale for timestamps (e.g. \"es\", \"en-US\"). Defaults to the browser. */\n locale?: string;\n /** Hex colour for bubble + accents. Defaults to #111827. */\n accentColor?: string;\n /** Text colour rendered on top of the accent. Defaults to white. */\n accentTextColor?: string;\n /** Show the \"Powered by Nexor\" footer. Defaults to true. */\n showBranding?: boolean;\n\n // ── Behaviour ──\n position?: \"bottom-right\" | \"bottom-left\";\n /** Auto-open the panel on first load. Defaults to false. */\n openOnLoad?: boolean;\n /** Coalesce rapid-fire messages: wait this many ms of quiet, then send the\n * buffered messages as one combined turn. Defaults to 700. 0 = per message. */\n debounceMs?: number;\n /** Append the widget to a custom element. Defaults to document.body. */\n container?: HTMLElement;\n\n // ── Prompt overrides forwarded to the agent for THIS widget instance ──\n systemPrompt?: string;\n clientPrompt?: string;\n\n // ── Lead linking ──\n /** Pre-known lead info (e.g. a logged-in user). Skips capture if complete. */\n lead?: {\n first_name?: string;\n last_name?: string;\n email?: string;\n phone?: string;\n metadata?: Record<string, unknown>;\n };\n capture?: ChatLeadCapture;\n /** Arbitrary metadata passed with each turn (page URL, UTM, …). */\n metadata?: Record<string, unknown>;\n\n // ── Callbacks ──\n onOpen?: () => void;\n onClose?: () => void;\n onMessage?: (msg: { role: \"user\" | \"bot\"; text: string }) => void;\n onLeadCaptured?: (leadId: UUID) => void;\n onError?: (err: Error) => void;\n}\n\nexport interface ChatHandle {\n open(): void;\n close(): void;\n toggle(): void;\n /** Programmatically send a user message. */\n send(text: string): Promise<void>;\n /** Tear down the widget and remove all DOM. */\n destroy(): void;\n /** Read the current session id (auto-generated on first open). */\n getSessionId(): string;\n}\n\n// ─── Internal resolved-config type ─────────────────────────────────────────\n\nexport interface ResolvedCfg {\n workflowId: UUID;\n title: string;\n subtitle: string;\n greeting: string;\n errorText: string;\n locale?: string;\n accentColor: string;\n accentTextColor: string;\n showBranding: boolean;\n position: \"bottom-right\" | \"bottom-left\";\n openOnLoad: boolean;\n debounceMs: number;\n container?: HTMLElement;\n systemPrompt?: string;\n clientPrompt?: string;\n lead?: ChatInitOptions[\"lead\"];\n capture: Required<ChatLeadCapture>;\n metadata?: Record<string, unknown>;\n onOpen?: () => void;\n onClose?: () => void;\n onMessage?: (msg: { role: \"user\" | \"bot\"; text: string }) => void;\n onLeadCaptured?: (leadId: UUID) => void;\n onError?: (err: Error) => void;\n}\n\n/**\n * Normalize user-provided options into a complete config object with every\n * field set. Downstream code reads from ResolvedCfg and never has to deal\n * with `undefined` for branding / behaviour fields.\n */\nexport function applyDefaults(o: ChatInitOptions): ResolvedCfg {\n return {\n workflowId: o.workflowId,\n title: o.title ?? \"Chat with us\",\n subtitle: o.subtitle ?? \"We typically reply in a few minutes\",\n greeting: o.greeting ?? \"Hi there! 👋 How can we help?\",\n errorText:\n o.errorText ?? \"Sorry, something went wrong. Please try again in a moment.\",\n locale:\n o.locale ??\n (typeof navigator !== \"undefined\" ? navigator.language : undefined),\n accentColor: o.accentColor ?? \"#111827\",\n accentTextColor: o.accentTextColor ?? \"#ffffff\",\n showBranding: o.showBranding ?? true,\n position: o.position ?? \"bottom-right\",\n openOnLoad: o.openOnLoad ?? false,\n debounceMs: o.debounceMs ?? 700,\n container: o.container,\n systemPrompt: o.systemPrompt,\n clientPrompt: o.clientPrompt,\n lead: o.lead,\n capture: {\n fields: o.capture?.fields ?? [\"first_name\", \"email\"],\n mode: o.capture?.mode ?? \"before\",\n label: o.capture?.label ?? \"Tell us a bit about you to get started:\",\n submitLabel: o.capture?.submitLabel ?? \"Start chat\",\n },\n metadata: o.metadata,\n onOpen: o.onOpen,\n onClose: o.onClose,\n onMessage: o.onMessage,\n onLeadCaptured: o.onLeadCaptured,\n onError: o.onError,\n };\n}\n\n/**\n * Does this widget need to show a lead-capture form before chat?\n * - \"skip\" mode → no\n * - Pre-known lead already covers every required field → no\n * - Otherwise → yes\n */\nexport function needsCapture(cfg: ResolvedCfg): boolean {\n if (cfg.capture.mode === \"skip\") return false;\n if (cfg.lead) {\n const have = cfg.lead;\n return cfg.capture.fields.some((f) => !have[f]);\n }\n return true;\n}\n","/**\n * Browser-side session-id management for the chat widget.\n *\n * The session id links anonymous turns to the same lead across page reloads.\n * It's persisted in localStorage with a last-activity timestamp and a sliding\n * retention window: a conversation is kept for at least SESSION_RETENTION_MS\n * after the last activity, after which a fresh session (and transcript) starts.\n * If storage is unavailable (private mode, sandboxed iframe) we fall back to a\n * per-tab id and accept that a refresh starts a new conversation.\n */\n\nconst SESSION_KEY = \"nexor.chat.session_id\";\n\n/** Keep a conversation (session + transcript) this long after the last\n * activity, so a returning visitor can resume it. Reused by the transcript\n * cache in `./index`. The host (e.g. the landing widget) decides when to\n * auto-resume vs. prompt \"continue or start new\". */\nexport const SESSION_RETENTION_MS = 30 * 24 * 60 * 60 * 1000; // 30 days\n\n/**\n * Return the persisted session id, generating one on first use or once the\n * retention window has lapsed. Reading it slides the window forward.\n */\nexport function ensureSessionId(): string {\n const now = Date.now();\n try {\n const rec = readRecord();\n if (rec && now - rec.ts < SESSION_RETENTION_MS) {\n writeRecord(rec.id, now); // slide the window on activity\n return rec.id;\n }\n } catch {\n /* localStorage may be unavailable (private mode, sandboxed iframe). */\n }\n const id = `sess_${randomHex(16)}`;\n try {\n writeRecord(id, now);\n } catch {\n /* ignore — id is still valid for this page load. */\n }\n return id;\n}\n\n/** Bump the session's last-activity timestamp (slides the retention window). */\nexport function touchSession(): void {\n try {\n const rec = readRecord();\n if (rec) writeRecord(rec.id, Date.now());\n } catch {\n /* ignore */\n }\n}\n\nfunction readRecord(): { id: string; ts: number } | null {\n const raw = window.localStorage.getItem(SESSION_KEY);\n if (!raw) return null;\n try {\n const o = JSON.parse(raw);\n if (o && typeof o.id === \"string\" && typeof o.ts === \"number\") return o;\n } catch {\n /* legacy value was a plain \"sess_…\" string — adopt it below. */\n }\n if (raw.startsWith(\"sess_\")) return { id: raw, ts: Date.now() };\n return null;\n}\n\nfunction writeRecord(id: string, ts: number): void {\n window.localStorage.setItem(SESSION_KEY, JSON.stringify({ id, ts }));\n}\n\n/**\n * Hex string from cryptographically-strong randomness when available, with\n * a Math.random() fallback for very old browsers.\n */\nfunction randomHex(bytes: number): string {\n const arr = new Uint8Array(bytes);\n if (typeof crypto !== \"undefined\" && crypto.getRandomValues) {\n crypto.getRandomValues(arr);\n } else {\n for (let i = 0; i < bytes; i++) arr[i] = Math.floor(Math.random() * 256);\n }\n return Array.from(arr, (b) => b.toString(16).padStart(2, \"0\")).join(\"\");\n}\n","/**\n * Scoped CSS for the chat widget.\n *\n * Everything is namespaced under `.nexor-chat` so it cannot leak into the host\n * page, and properties that hosts commonly override (color, font, line-height)\n * are set explicitly here so the host's reset can't bleed in.\n *\n * Animations are GPU-friendly (transform + opacity only — no layout-trashing\n * properties like top/left) and use modest durations so the widget feels\n * responsive on low-end devices.\n */\nexport const widgetCss = (accent: string, accentText: string): string => `\n.nexor-chat,\n.nexor-chat * {\n box-sizing: border-box;\n font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, \"Helvetica Neue\", Arial, sans-serif;\n}\n\n.nexor-chat {\n position: fixed;\n z-index: 2147483640;\n bottom: 20px;\n right: 20px;\n font-size: 14px;\n line-height: 1.4;\n color: #111;\n}\n\n.nexor-chat[data-position=\"bottom-left\"] {\n right: auto;\n left: 20px;\n}\n\n/* ── Launcher bubble ─────────────────────────────────────────────── */\n.nexor-chat__launcher {\n width: 56px;\n height: 56px;\n border-radius: 9999px;\n background: ${accent};\n color: ${accentText};\n border: none;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n box-shadow: 0 6px 18px rgba(0, 0, 0, 0.18);\n transition: transform 160ms cubic-bezier(.2,.7,.2,1.1),\n box-shadow 160ms ease,\n background 200ms ease;\n padding: 0;\n position: relative;\n animation: nexor-launcher-in 360ms cubic-bezier(.2,.7,.2,1.1) both;\n}\n.nexor-chat__launcher:hover {\n transform: translateY(-2px) scale(1.04);\n box-shadow: 0 10px 24px rgba(0, 0, 0, 0.24);\n}\n.nexor-chat__launcher:active {\n transform: translateY(0) scale(0.97);\n transition-duration: 80ms;\n}\n.nexor-chat__launcher:focus-visible {\n outline: 2px solid ${accent};\n outline-offset: 2px;\n}\n.nexor-chat[data-open=\"true\"] .nexor-chat__launcher {\n transform: scale(0.85);\n opacity: 0.75;\n}\n.nexor-chat__launcher svg { width: 24px; height: 24px; transition: transform 200ms ease; }\n.nexor-chat[data-open=\"true\"] .nexor-chat__launcher svg { transform: rotate(8deg); }\n\n.nexor-chat__unread {\n position: absolute;\n top: -4px;\n right: -4px;\n min-width: 18px;\n height: 18px;\n background: #ef4444;\n color: #fff;\n border-radius: 9999px;\n font-size: 11px;\n font-weight: 600;\n padding: 0 5px;\n display: flex;\n align-items: center;\n justify-content: center;\n border: 2px solid #fff;\n animation: nexor-pop-in 300ms cubic-bezier(.2,.7,.2,1.1) both;\n}\n\n@keyframes nexor-launcher-in {\n from { transform: translateY(20px) scale(0.6); opacity: 0; }\n to { transform: translateY(0) scale(1); opacity: 1; }\n}\n@keyframes nexor-pop-in {\n from { transform: scale(0); }\n to { transform: scale(1); }\n}\n\n/* ── Panel ────────────────────────────────────────────────────────── */\n.nexor-chat__panel {\n position: absolute;\n bottom: 72px;\n right: 0;\n width: 360px;\n max-width: calc(100vw - 32px);\n height: 540px;\n max-height: calc(100vh - 120px);\n background: #fff;\n border-radius: 14px;\n box-shadow: 0 24px 60px rgba(0, 0, 0, 0.22);\n display: flex;\n flex-direction: column;\n overflow: hidden;\n transform: translateY(14px) scale(0.96);\n opacity: 0;\n pointer-events: none;\n transition: transform 220ms cubic-bezier(.2,.7,.2,1.1),\n opacity 220ms ease;\n border: 1px solid rgba(0, 0, 0, 0.06);\n /* Use visibility so screen readers don't read collapsed content */\n visibility: hidden;\n}\n.nexor-chat[data-position=\"bottom-left\"] .nexor-chat__panel {\n right: auto;\n left: 0;\n}\n.nexor-chat[data-open=\"true\"] .nexor-chat__panel {\n transform: translateY(0) scale(1);\n opacity: 1;\n pointer-events: auto;\n visibility: visible;\n}\n\n.nexor-chat__header {\n background: ${accent};\n color: ${accentText};\n padding: 14px 16px;\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 12px;\n}\n.nexor-chat__title {\n font-weight: 600;\n font-size: 15px;\n margin: 0;\n}\n.nexor-chat__subtitle {\n font-size: 12px;\n opacity: 0.85;\n margin: 2px 0 0;\n}\n.nexor-chat__status-dot {\n display: inline-block;\n width: 8px;\n height: 8px;\n border-radius: 9999px;\n background: #34d399;\n margin-right: 6px;\n vertical-align: 1px;\n animation: nexor-pulse 2.4s ease-in-out infinite;\n box-shadow: 0 0 0 0 rgba(52, 211, 153, 0.6);\n}\n@keyframes nexor-pulse {\n 0%, 100% { box-shadow: 0 0 0 0 rgba(52, 211, 153, 0.55); }\n 50% { box-shadow: 0 0 0 6px rgba(52, 211, 153, 0); }\n}\n.nexor-chat__close {\n background: transparent;\n border: none;\n color: inherit;\n cursor: pointer;\n padding: 4px;\n border-radius: 6px;\n opacity: 0.9;\n transition: background 140ms ease, transform 140ms ease;\n}\n.nexor-chat__close:hover { background: rgba(255,255,255,0.18); opacity: 1; }\n.nexor-chat__close:active { transform: scale(0.92); }\n.nexor-chat__close svg { width: 18px; height: 18px; display: block; }\n\n/* ── Body / messages ──────────────────────────────────────────────── */\n.nexor-chat__body {\n flex: 1;\n overflow-y: auto;\n padding: 14px;\n background: #f6f7f9;\n display: flex;\n flex-direction: column;\n gap: 8px;\n scroll-behavior: smooth;\n /* Prevent layout shift when scrollbar appears */\n scrollbar-gutter: stable;\n}\n.nexor-chat__body::-webkit-scrollbar { width: 6px; }\n.nexor-chat__body::-webkit-scrollbar-thumb {\n background: rgba(0,0,0,0.15);\n border-radius: 9999px;\n}\n\n.nexor-chat__msg {\n max-width: 80%;\n padding: 8px 12px;\n border-radius: 14px;\n white-space: pre-wrap;\n word-wrap: break-word;\n animation: nexor-msg-in 240ms cubic-bezier(.2,.7,.2,1.1) both;\n will-change: transform, opacity;\n}\n.nexor-chat__msg--bot {\n background: #fff;\n align-self: flex-start;\n border: 1px solid rgba(0,0,0,0.06);\n border-bottom-left-radius: 4px;\n box-shadow: 0 1px 2px rgba(0,0,0,0.04);\n}\n.nexor-chat__msg--user {\n background: ${accent};\n color: ${accentText};\n align-self: flex-end;\n border-bottom-right-radius: 4px;\n animation-name: nexor-msg-in-user;\n}\n.nexor-chat__msg--system {\n background: transparent;\n color: #6b7280;\n font-size: 12px;\n align-self: center;\n text-align: center;\n max-width: 100%;\n animation-name: nexor-fade-in;\n}\n.nexor-chat__msg-time {\n display: block;\n margin-top: 4px;\n font-size: 10px;\n line-height: 1;\n opacity: 0.55;\n text-align: right;\n}\n.nexor-chat__msg--bot .nexor-chat__msg-time { text-align: left; }\n\n@keyframes nexor-msg-in {\n from { transform: translateY(8px) scale(0.96); opacity: 0; }\n to { transform: translateY(0) scale(1); opacity: 1; }\n}\n@keyframes nexor-msg-in-user {\n from { transform: translateY(8px) translateX(8px) scale(0.96); opacity: 0; }\n to { transform: translateY(0) translateX(0) scale(1); opacity: 1; }\n}\n@keyframes nexor-fade-in {\n from { opacity: 0; }\n to { opacity: 1; }\n}\n\n.nexor-chat__typing {\n align-self: flex-start;\n background: #fff;\n border: 1px solid rgba(0,0,0,0.06);\n border-radius: 14px;\n border-bottom-left-radius: 4px;\n padding: 10px 14px;\n display: inline-flex;\n gap: 4px;\n animation: nexor-msg-in 240ms cubic-bezier(.2,.7,.2,1.1) both;\n}\n.nexor-chat__typing span {\n width: 6px; height: 6px; border-radius: 9999px;\n background: #9ca3af;\n display: inline-block;\n animation: nexor-blink 1.2s infinite ease-in-out;\n}\n.nexor-chat__typing span:nth-child(2) { animation-delay: 0.15s; }\n.nexor-chat__typing span:nth-child(3) { animation-delay: 0.30s; }\n@keyframes nexor-blink {\n 0%, 60%, 100% { opacity: 0.3; transform: translateY(0); }\n 30% { opacity: 1; transform: translateY(-3px); }\n}\n\n/* ── Lead capture form ────────────────────────────────────────────── */\n.nexor-chat__capture {\n background: #fff;\n border: 1px solid rgba(0,0,0,0.06);\n border-radius: 12px;\n padding: 12px;\n display: flex;\n flex-direction: column;\n gap: 8px;\n margin-top: 4px;\n animation: nexor-msg-in 280ms cubic-bezier(.2,.7,.2,1.1) both;\n box-shadow: 0 2px 8px rgba(0,0,0,0.05);\n}\n.nexor-chat__capture-label {\n font-size: 12px;\n color: #6b7280;\n margin: 0;\n}\n.nexor-chat__capture-row {\n display: flex;\n gap: 8px;\n}\n.nexor-chat__capture-row > * { flex: 1; }\n.nexor-chat__input,\n.nexor-chat__capture input {\n font: inherit;\n padding: 8px 10px;\n border: 1px solid #d1d5db;\n border-radius: 8px;\n background: #fff;\n color: #111;\n outline: none;\n width: 100%;\n transition: border-color 140ms ease, box-shadow 140ms ease;\n}\n.nexor-chat__input:focus,\n.nexor-chat__capture input:focus {\n border-color: ${accent};\n box-shadow: 0 0 0 3px ${accent}33;\n}\n.nexor-chat__capture-submit {\n background: ${accent};\n color: ${accentText};\n border: none;\n border-radius: 8px;\n padding: 8px 12px;\n font: inherit;\n font-weight: 600;\n cursor: pointer;\n transition: transform 140ms ease, filter 140ms ease;\n}\n.nexor-chat__capture-submit:hover { filter: brightness(1.08); }\n.nexor-chat__capture-submit:active { transform: scale(0.97); }\n.nexor-chat__capture-submit[disabled] { opacity: 0.6; cursor: not-allowed; }\n\n/* ── Composer ─────────────────────────────────────────────────────── */\n.nexor-chat__composer {\n display: flex;\n gap: 8px;\n padding: 10px;\n background: #fff;\n border-top: 1px solid rgba(0,0,0,0.06);\n align-items: stretch;\n}\n.nexor-chat__send {\n background: ${accent};\n color: ${accentText};\n border: none;\n border-radius: 8px;\n padding: 0 14px;\n font: inherit;\n font-weight: 600;\n cursor: pointer;\n min-width: 44px;\n display: flex;\n align-items: center;\n justify-content: center;\n transition: transform 140ms ease, filter 140ms ease;\n}\n.nexor-chat__send:hover { filter: brightness(1.08); }\n.nexor-chat__send:active { transform: scale(0.95); }\n.nexor-chat__send[disabled] {\n opacity: 0.6;\n cursor: not-allowed;\n transform: none;\n}\n.nexor-chat__send svg {\n width: 18px;\n height: 18px;\n transition: transform 200ms ease;\n}\n.nexor-chat__send:not([disabled]):hover svg { transform: translateX(2px); }\n\n/* Small spinner inside the send button while a turn is in flight */\n.nexor-chat__send--loading svg { display: none; }\n.nexor-chat__send--loading::after {\n content: \"\";\n width: 14px;\n height: 14px;\n border-radius: 9999px;\n border: 2px solid currentColor;\n border-top-color: transparent;\n animation: nexor-spin 700ms linear infinite;\n}\n@keyframes nexor-spin {\n to { transform: rotate(360deg); }\n}\n\n.nexor-chat__footer {\n text-align: center;\n font-size: 11px;\n color: #9ca3af;\n padding: 6px;\n background: #fff;\n border-top: 1px solid rgba(0,0,0,0.04);\n}\n.nexor-chat__footer a {\n color: inherit;\n text-decoration: none;\n font-weight: 600;\n}\n.nexor-chat__footer a:hover { text-decoration: underline; }\n\n/* Respect users who request reduced motion. */\n@media (prefers-reduced-motion: reduce) {\n .nexor-chat,\n .nexor-chat * {\n animation-duration: 0.001ms !important;\n transition-duration: 0.001ms !important;\n }\n .nexor-chat__status-dot { animation: none; }\n}\n`;\n","/**\n * Pure DOM construction for the chat widget.\n *\n * Each `build*` function returns a fully-formed sub-tree plus refs to the\n * inner nodes the orchestrator (initChat) wires events to. No side effects\n * here other than calling `injectStyles()` once per page.\n *\n * Why split this out from index.ts?\n * - The DOM layer doesn't depend on the NexorClient or sessionId — keeping\n * it pure makes the widget easy to reason about and easy to dry-run in\n * unit tests by mocking `document`.\n * - The orchestrator becomes a 150-line state machine instead of a\n * 600-line god-function.\n */\nimport { needsCapture, type ResolvedCfg } from \"./config\";\nimport { widgetCss } from \"./styles\";\n\nconst STYLE_ATTR = \"data-nexor-chat-styles\";\n\n// ─── Stylesheet (singleton per page) ───────────────────────────────────────\n\n/**\n * Inject the widget's stylesheet once per page. If multiple widgets mount,\n * they share styles and the first widget's accent colour wins. Two widgets\n * with different accents on one page is an unsupported use case.\n */\nexport function injectStyles(accent: string, accentText: string): void {\n if (document.querySelector(`style[${STYLE_ATTR}]`)) return;\n const style = document.createElement(\"style\");\n style.setAttribute(STYLE_ATTR, \"1\");\n style.textContent = widgetCss(accent, accentText);\n document.head.appendChild(style);\n}\n\n// ─── Launcher ──────────────────────────────────────────────────────────────\n\nexport interface LauncherRefs {\n el: HTMLButtonElement;\n badge: HTMLSpanElement;\n}\n\nexport function buildLauncher(): LauncherRefs {\n const el = document.createElement(\"button\");\n el.type = \"button\";\n el.className = \"nexor-chat__launcher\";\n el.setAttribute(\"aria-label\", \"Open chat\");\n // Speech-bubble icon — SVG rather than emoji for crisp rendering at any DPR.\n el.innerHTML = `\n <svg viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\" aria-hidden=\"true\">\n <path d=\"M4 5.5C4 4.67 4.67 4 5.5 4h13c.83 0 1.5.67 1.5 1.5v9c0 .83-.67 1.5-1.5 1.5H9l-4 4V5.5Z\"\n stroke=\"currentColor\" stroke-width=\"1.8\" stroke-linejoin=\"round\"/>\n </svg>\n `;\n const badge = document.createElement(\"span\");\n badge.className = \"nexor-chat__unread\";\n badge.style.display = \"none\";\n el.appendChild(badge);\n return { el, badge };\n}\n\n// ─── Panel ─────────────────────────────────────────────────────────────────\n\ntype CaptureField = \"first_name\" | \"last_name\" | \"email\" | \"phone\";\n\nexport interface PanelRefs {\n el: HTMLDivElement;\n closeBtn: HTMLButtonElement;\n body: HTMLDivElement;\n form: HTMLFormElement;\n input: HTMLInputElement;\n send: HTMLButtonElement;\n captureForm: HTMLFormElement | null;\n captureInputs: Partial<Record<CaptureField, HTMLInputElement>>;\n}\n\nexport function buildPanel(cfg: ResolvedCfg): PanelRefs {\n const el = document.createElement(\"div\");\n el.className = \"nexor-chat__panel\";\n el.setAttribute(\"role\", \"dialog\");\n el.setAttribute(\"aria-label\", cfg.title);\n\n const { header, closeBtn } = buildHeader(cfg);\n const { body, captureForm, captureInputs } = buildBody(cfg);\n const { form, input, send } = buildComposer();\n const footer = cfg.showBranding ? buildFooter() : null;\n\n el.appendChild(header);\n el.appendChild(body);\n el.appendChild(form);\n if (footer) el.appendChild(footer);\n\n return { el, closeBtn, body, form, input, send, captureForm, captureInputs };\n}\n\nfunction buildHeader(cfg: ResolvedCfg): {\n header: HTMLDivElement;\n closeBtn: HTMLButtonElement;\n} {\n const header = document.createElement(\"div\");\n header.className = \"nexor-chat__header\";\n\n // The status dot signals \"we're live and listening\" — purely cosmetic, but\n // a strong UX signal. Hidden from assistive tech because the title carries\n // the meaning already.\n const subtitleHtml = cfg.subtitle\n ? `<p class=\"nexor-chat__subtitle\">\n <span class=\"nexor-chat__status-dot\" aria-hidden=\"true\"></span>${escapeHtml(cfg.subtitle)}\n </p>`\n : \"\";\n\n header.innerHTML = `\n <div>\n <p class=\"nexor-chat__title\">${escapeHtml(cfg.title)}</p>\n ${subtitleHtml}\n </div>\n `;\n\n const closeBtn = document.createElement(\"button\");\n closeBtn.type = \"button\";\n closeBtn.className = \"nexor-chat__close\";\n closeBtn.setAttribute(\"aria-label\", \"Close chat\");\n closeBtn.innerHTML = `\n <svg viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\" aria-hidden=\"true\">\n <path d=\"M6 6l12 12M6 18L18 6\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\"/>\n </svg>\n `;\n header.appendChild(closeBtn);\n return { header, closeBtn };\n}\n\nfunction buildBody(cfg: ResolvedCfg): {\n body: HTMLDivElement;\n captureForm: HTMLFormElement | null;\n captureInputs: Partial<Record<CaptureField, HTMLInputElement>>;\n} {\n const body = document.createElement(\"div\");\n body.className = \"nexor-chat__body\";\n const captureInputs: Partial<Record<CaptureField, HTMLInputElement>> = {};\n let captureForm: HTMLFormElement | null = null;\n\n if (needsCapture(cfg)) {\n captureForm = buildCaptureForm(cfg, captureInputs);\n body.appendChild(captureForm);\n }\n return { body, captureForm, captureInputs };\n}\n\nfunction buildCaptureForm(\n cfg: ResolvedCfg,\n inputsOut: Partial<Record<CaptureField, HTMLInputElement>>,\n): HTMLFormElement {\n const form = document.createElement(\"form\");\n form.className = \"nexor-chat__capture\";\n form.noValidate = true;\n\n const label = document.createElement(\"p\");\n label.className = \"nexor-chat__capture-label\";\n label.textContent = cfg.capture.label;\n form.appendChild(label);\n\n const fields = cfg.capture.fields;\n\n // first_name + last_name share a row to feel like a single \"your name\" prompt.\n if (fields.includes(\"first_name\") || fields.includes(\"last_name\")) {\n const row = document.createElement(\"div\");\n row.className = \"nexor-chat__capture-row\";\n if (fields.includes(\"first_name\")) {\n inputsOut.first_name = makeInput(\"first_name\", \"First name\", \"text\", cfg.lead?.first_name);\n row.appendChild(inputsOut.first_name);\n }\n if (fields.includes(\"last_name\")) {\n inputsOut.last_name = makeInput(\"last_name\", \"Last name\", \"text\", cfg.lead?.last_name);\n row.appendChild(inputsOut.last_name);\n }\n if (row.childElementCount > 0) form.appendChild(row);\n }\n if (fields.includes(\"email\")) {\n inputsOut.email = makeInput(\"email\", \"Email\", \"email\", cfg.lead?.email);\n form.appendChild(inputsOut.email);\n }\n if (fields.includes(\"phone\")) {\n inputsOut.phone = makeInput(\"phone\", \"Phone\", \"tel\", cfg.lead?.phone);\n form.appendChild(inputsOut.phone);\n }\n\n const submit = document.createElement(\"button\");\n submit.type = \"submit\";\n submit.className = \"nexor-chat__capture-submit\";\n submit.textContent = cfg.capture.submitLabel;\n form.appendChild(submit);\n\n return form;\n}\n\nfunction buildComposer(): {\n form: HTMLFormElement;\n input: HTMLInputElement;\n send: HTMLButtonElement;\n} {\n const form = document.createElement(\"form\");\n form.className = \"nexor-chat__composer\";\n\n const input = document.createElement(\"input\");\n input.type = \"text\";\n input.className = \"nexor-chat__input\";\n input.placeholder = \"Type a message…\";\n input.autocomplete = \"off\";\n\n const send = document.createElement(\"button\");\n send.type = \"submit\";\n send.className = \"nexor-chat__send\";\n send.setAttribute(\"aria-label\", \"Send message\");\n // Paper-airplane icon — language-agnostic, recognisable, replaces \"Send\" text.\n send.innerHTML = `\n <svg viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\" aria-hidden=\"true\">\n <path d=\"M3.4 11.2 20.5 4.3c.7-.3 1.4.4 1.1 1.1l-6.9 17.1c-.3.8-1.4.8-1.8 0L10 14l-7.5-3c-.8-.3-.8-1.5 0-1.8Z\"\n stroke=\"currentColor\" stroke-width=\"1.6\" stroke-linejoin=\"round\" fill=\"currentColor\"/>\n </svg>\n `;\n\n form.appendChild(input);\n form.appendChild(send);\n return { form, input, send };\n}\n\nfunction buildFooter(): HTMLDivElement {\n const el = document.createElement(\"div\");\n el.className = \"nexor-chat__footer\";\n el.innerHTML = `Powered by <a href=\"https://www.getnexor.ai\" target=\"_blank\" rel=\"noopener noreferrer\">Nexor</a>`;\n return el;\n}\n\n// ─── Message bubbles ───────────────────────────────────────────────────────\n\nexport type MessageRole = \"user\" | \"bot\" | \"system\";\n\n/**\n * Build a chat bubble. `textContent` is used (never innerHTML) so user input\n * is rendered as plain text — no XSS surface from message payloads.\n */\nexport function buildMessage(\n role: MessageRole,\n text: string,\n ts?: number,\n locale?: string,\n): HTMLDivElement {\n const el = document.createElement(\"div\");\n el.className = `nexor-chat__msg nexor-chat__msg--${role}`;\n const body = document.createElement(\"span\");\n body.className = \"nexor-chat__msg-text\";\n body.textContent = text;\n el.appendChild(body);\n // Relative time under user/bot messages (not system notices). `data-ts` lets\n // the widget refresh the label as time passes (see index.ts).\n if (role !== \"system\" && ts) {\n const time = document.createElement(\"time\");\n time.className = \"nexor-chat__msg-time\";\n time.dataset.ts = String(ts);\n time.textContent = formatRelativeTime(ts, locale);\n el.appendChild(time);\n }\n return el;\n}\n\n/**\n * Relative within the last week (\"ahora\", \"hace 3 minutos\", \"hace 2 horas\",\n * \"ayer\"), then an absolute date (\"12 may\"). Localized via Intl; falls back to\n * a plain clock time if Intl.RelativeTimeFormat is unavailable.\n */\nexport function formatRelativeTime(\n ts: number,\n locale?: string,\n now: number = Date.now(),\n): string {\n try {\n const diff = Math.max(0, now - ts);\n const min = Math.round(diff / 60000);\n const hr = Math.round(diff / 3600000);\n const day = Math.round(diff / 86400000);\n const rtf = new Intl.RelativeTimeFormat(locale, { numeric: \"auto\" });\n if (diff < 45000) return rtf.format(0, \"second\"); // \"ahora\" / \"now\"\n if (min < 60) return rtf.format(-min, \"minute\");\n if (hr < 24) return rtf.format(-hr, \"hour\");\n if (day < 7) return rtf.format(-day, \"day\"); // includes \"ayer\"/\"yesterday\"\n return new Date(ts).toLocaleDateString(locale, {\n day: \"numeric\",\n month: \"short\",\n });\n } catch {\n try {\n return new Date(ts).toLocaleTimeString(locale, {\n hour: \"2-digit\",\n minute: \"2-digit\",\n });\n } catch {\n return \"\";\n }\n }\n}\n\n/** Three-dot typing indicator. Animation lives in styles.ts. */\nexport function buildTypingIndicator(): HTMLDivElement {\n const el = document.createElement(\"div\");\n el.className = \"nexor-chat__typing\";\n el.innerHTML = \"<span></span><span></span><span></span>\";\n return el;\n}\n\n// ─── Helpers ───────────────────────────────────────────────────────────────\n\nfunction makeInput(\n name: string,\n placeholder: string,\n type: string,\n value?: string,\n): HTMLInputElement {\n const i = document.createElement(\"input\");\n i.name = name;\n i.type = type;\n i.placeholder = placeholder;\n if (value) i.value = value;\n return i;\n}\n\n/**\n * Escape strings before interpolation into innerHTML. Used only for\n * SDK-controlled config values (title, subtitle) — user-typed messages\n * always go through textContent, which doesn't need escaping.\n */\nfunction escapeHtml(s: string): string {\n return s\n .replace(/&/g, \"&amp;\")\n .replace(/</g, \"&lt;\")\n .replace(/>/g, \"&gt;\")\n .replace(/\"/g, \"&quot;\")\n .replace(/'/g, \"&#039;\");\n}\n","/**\n * Chat widget orchestrator.\n *\n * Responsibilities (everything else lives in sibling files):\n * - apply defaults / validate options (`./config`)\n * - manage session id (`./session`)\n * - build DOM (`./dom`)\n * - inject CSS (`./dom`)\n *\n * What stays here:\n * - the open/close state machine\n * - wiring DOM events to the NexorClient.chat() call\n * - lead-capture submission flow\n * - the public ChatHandle returned to callers\n */\nimport type { NexorClient } from \"../client\";\nimport type { UUID } from \"../types\";\nimport {\n applyDefaults,\n needsCapture,\n type ChatInitOptions,\n type ChatHandle,\n type ResolvedCfg,\n} from \"./config\";\nimport { ensureSessionId, touchSession, SESSION_RETENTION_MS } from \"./session\";\nimport {\n buildLauncher,\n buildMessage,\n buildPanel,\n buildTypingIndicator,\n formatRelativeTime,\n injectStyles,\n type LauncherRefs,\n type MessageRole,\n type PanelRefs,\n} from \"./dom\";\n\n// Re-export the public types so consumers can `import type { ChatHandle } from \"@getnexorai/sdk\"`.\nexport type { ChatInitOptions, ChatHandle, ChatLeadCapture } from \"./config\";\n\n// Delay before showing the typing indicator. Short replies arrive before this\n// fires and never show the dots, which feels snappier than always flashing them.\nconst TYPING_DELAY_MS = 220;\n\n/**\n * Mount the chat widget and return a handle for programmatic control.\n *\n * @param client The NexorClient instance that will send turns.\n * @param options User-facing widget configuration. See ChatInitOptions.\n * @throws If called outside a browser, or without a workflowId.\n */\nexport function initChat(\n client: NexorClient,\n options: ChatInitOptions,\n): ChatHandle {\n ensureBrowser();\n if (!options || !options.workflowId) {\n throw new Error(\"Nexor SDK: initChat() requires `workflowId`.\");\n }\n\n const cfg = applyDefaults(options);\n injectStyles(cfg.accentColor, cfg.accentTextColor);\n\n const sessionId = ensureSessionId();\n const historyKey = `nexor.chat.history.${sessionId}`;\n const root = buildRoot(cfg);\n const launcher = buildLauncher();\n const panel = buildPanel(cfg);\n root.appendChild(launcher.el);\n root.appendChild(panel.el);\n (cfg.container ?? document.body).appendChild(root);\n\n // ─── State (closure-private — no external observers needed) ─────────────\n const state = {\n isOpen: false,\n unread: 0,\n leadId: undefined as UUID | undefined,\n captured: !needsCapture(cfg),\n pendingLead: { ...(cfg.lead ?? {}) },\n history: [] as Array<{ role: \"user\" | \"bot\"; text: string; ts?: number }>,\n };\n\n // ─── DOM event wiring ───────────────────────────────────────────────────\n launcher.el.addEventListener(\"click\", toggle);\n panel.closeBtn.addEventListener(\"click\", close);\n panel.form.addEventListener(\"submit\", onComposerSubmit);\n panel.captureForm?.addEventListener(\"submit\", onCaptureSubmit);\n\n syncComposerLock();\n\n // Restore a prior transcript (persisted up to SESSION_RETENTION_MS) so a\n // page reload keeps the conversation. Rendered into the (possibly closed)\n // panel; the greeting is then skipped because history is non-empty.\n const restored = loadHistory();\n if (restored.length) {\n state.history = restored;\n for (const m of restored) appendBubble(m.role === \"user\" ? \"user\" : \"bot\", m.text, m.ts);\n scrollToBottom();\n }\n\n if (cfg.openOnLoad) open();\n\n // ─── State machine ──────────────────────────────────────────────────────\n\n function open(): void {\n if (state.isOpen) return;\n state.isOpen = true;\n root.setAttribute(\"data-open\", \"true\");\n clearUnread();\n // Lazy-greet: first time the panel opens, drop the greeting message.\n if (state.history.length === 0 && cfg.greeting && state.captured) {\n appendBot(cfg.greeting);\n }\n panel.input.focus();\n cfg.onOpen?.();\n }\n\n function close(): void {\n if (!state.isOpen) return;\n state.isOpen = false;\n root.setAttribute(\"data-open\", \"false\");\n cfg.onClose?.();\n }\n\n function toggle(): void {\n state.isOpen ? close() : open();\n }\n\n // ─── Capture flow ───────────────────────────────────────────────────────\n\n function onCaptureSubmit(e: Event): void {\n e.preventDefault();\n const collected = readCaptureFields(panel);\n // Validate that all required fields are filled before unlocking the chat.\n const required = cfg.capture.fields;\n for (const f of required) {\n if (!collected[f]) {\n panel.captureInputs[f]?.focus();\n return;\n }\n }\n state.pendingLead = { ...state.pendingLead, ...collected };\n state.captured = true;\n panel.captureForm?.remove();\n syncComposerLock();\n panel.input.focus();\n // Greet once capture clears, so the greeting feels like a response to \"I'm ready\".\n if (cfg.greeting && state.history.length === 0) appendBot(cfg.greeting);\n }\n\n // ─── Composer / send (debounced + coalesced) ────────────────────────────\n //\n // Visitors fire several short messages in a row (WhatsApp-style). We mirror\n // the WhatsApp contract — batch at the source, one LLM call per batch — by\n // buffering rapid messages in the browser and POSTing them as a SINGLE\n // combined turn after a short quiet window. The composer never locks, so the\n // user can keep typing and sending freely; messages that land mid-request are\n // sent in the next batch.\n\n const send = {\n pending: [] as string[],\n timer: 0,\n typingTimer: 0,\n inFlight: false,\n typing: null as HTMLElement | null,\n };\n\n function onComposerSubmit(e: Event): void {\n e.preventDefault();\n const text = panel.input.value.trim();\n if (!text) return;\n panel.input.value = \"\";\n queueMessage(text);\n }\n\n function queueMessage(text: string): void {\n if (!state.captured) {\n panel.captureInputs.first_name?.focus();\n return;\n }\n appendUser(text);\n send.pending.push(text);\n scheduleFlush();\n }\n\n function scheduleFlush(): void {\n if (send.timer) window.clearTimeout(send.timer);\n send.timer = window.setTimeout(() => void flush(), cfg.debounceMs);\n }\n\n async function flush(): Promise<void> {\n if (send.inFlight || send.pending.length === 0) return;\n const batch = send.pending.splice(0, send.pending.length);\n const message = batch.join(\"\\n\");\n send.inFlight = true;\n\n // Delay the typing dots so fast replies don't flash them.\n send.typingTimer = window.setTimeout(() => {\n send.typing = appendNode(buildTypingIndicator());\n }, TYPING_DELAY_MS);\n\n try {\n const res = await client.chat({\n workflow_id: cfg.workflowId,\n session_id: sessionId,\n message,\n system_prompt: cfg.systemPrompt,\n client_prompt: cfg.clientPrompt,\n lead: Object.keys(state.pendingLead).length ? state.pendingLead : undefined,\n metadata: cfg.metadata,\n });\n if (res.lead_id && !state.leadId) {\n state.leadId = res.lead_id;\n cfg.onLeadCaptured?.(state.leadId);\n }\n const reply = (res.reply ?? \"\").trim();\n if (reply) {\n appendBot(reply);\n } else {\n // No text came back (empty completion / tool-only turn). Never render a\n // blank bubble — show the fallback and surface it to the host.\n appendSystem(cfg.errorText);\n cfg.onError?.(new Error(\"Nexor SDK: empty reply from server\"));\n }\n } catch (err) {\n appendSystem(cfg.errorText);\n cfg.onError?.(err as Error);\n } finally {\n window.clearTimeout(send.typingTimer);\n send.typing?.remove();\n send.typing = null;\n send.inFlight = false;\n panel.input.focus();\n // Anything queued while the request was in flight goes out next.\n if (send.pending.length) scheduleFlush();\n }\n }\n\n // ─── Message rendering ──────────────────────────────────────────────────\n\n function appendUser(text: string): void {\n const ts = Date.now();\n appendBubble(\"user\", text, ts);\n state.history.push({ role: \"user\", text, ts });\n saveHistory();\n cfg.onMessage?.({ role: \"user\", text });\n }\n\n function appendBot(text: string): void {\n const ts = Date.now();\n appendBubble(\"bot\", text, ts);\n state.history.push({ role: \"bot\", text, ts });\n saveHistory();\n if (!state.isOpen) bumpUnread();\n cfg.onMessage?.({ role: \"bot\", text });\n }\n\n // ─── Transcript persistence (survives reloads up to SESSION_RETENTION_MS) ──\n\n function saveHistory(): void {\n try {\n window.localStorage.setItem(\n historyKey,\n JSON.stringify({ ts: Date.now(), history: state.history }),\n );\n touchSession(); // keep the session alive in step with the transcript\n } catch {\n /* storage unavailable — in-memory history still works for this load. */\n }\n }\n\n function loadHistory(): Array<{ role: \"user\" | \"bot\"; text: string; ts?: number }> {\n try {\n const raw = window.localStorage.getItem(historyKey);\n if (!raw) return [];\n const o = JSON.parse(raw);\n if (!o || !Array.isArray(o.history)) return [];\n if (Date.now() - (o.ts || 0) > SESSION_RETENTION_MS) {\n window.localStorage.removeItem(historyKey);\n return [];\n }\n return o.history;\n } catch {\n return [];\n }\n }\n\n function appendSystem(text: string): void {\n appendBubble(\"system\", text);\n }\n\n function appendBubble(\n role: MessageRole,\n text: string,\n ts?: number,\n ): HTMLDivElement {\n return appendNode(buildMessage(role, text, ts, cfg.locale));\n }\n\n // Keep relative timestamps (\"hace 3 minutos\") fresh while the panel is open.\n const refreshTimer = window.setInterval(() => {\n panel.body\n .querySelectorAll<HTMLTimeElement>(\".nexor-chat__msg-time[data-ts]\")\n .forEach((el) => {\n const ts = Number(el.dataset.ts);\n if (ts) el.textContent = formatRelativeTime(ts, cfg.locale);\n });\n }, 60_000);\n\n function appendNode<T extends HTMLElement>(node: T): T {\n panel.body.appendChild(node);\n // Keep the typing indicator pinned to the bottom: if the visitor fires\n // another message while we're awaiting a reply, the dots must stay BELOW\n // it (the bot hasn't \"typed\" yet), not stranded between messages.\n if (send.typing && send.typing !== node) panel.body.appendChild(send.typing);\n scrollToBottom();\n return node;\n }\n\n function scrollToBottom(): void {\n panel.body.scrollTop = panel.body.scrollHeight;\n }\n\n // ─── Unread badge ───────────────────────────────────────────────────────\n\n function bumpUnread(): void {\n state.unread++;\n launcher.badge.textContent = String(state.unread);\n launcher.badge.style.display = \"flex\";\n }\n function clearUnread(): void {\n state.unread = 0;\n launcher.badge.style.display = \"none\";\n }\n\n // ─── Composer lock (used while capture form is visible) ─────────────────\n\n function syncComposerLock(): void {\n const lock = !state.captured;\n panel.input.disabled = lock;\n panel.send.disabled = lock;\n panel.input.placeholder = lock\n ? \"Complete the form above to start…\"\n : \"Type a message…\";\n }\n\n // ─── Public handle ──────────────────────────────────────────────────────\n\n return {\n open,\n close,\n toggle,\n // Programmatic send goes through the same debounce/coalesce path. Resolves\n // immediately — the message is queued, not necessarily sent yet.\n send: (text: string) => {\n queueMessage(text);\n return Promise.resolve();\n },\n destroy: () => {\n if (send.timer) window.clearTimeout(send.timer);\n if (send.typingTimer) window.clearTimeout(send.typingTimer);\n window.clearInterval(refreshTimer);\n root.remove();\n },\n getSessionId: () => sessionId,\n };\n}\n\n// ─── Module-scoped helpers ────────────────────────────────────────────────\n\nfunction ensureBrowser(): void {\n if (typeof window === \"undefined\" || typeof document === \"undefined\") {\n throw new Error(\"Nexor SDK: initChat() requires a browser environment.\");\n }\n}\n\nfunction buildRoot(cfg: ResolvedCfg): HTMLDivElement {\n const root = document.createElement(\"div\");\n root.className = \"nexor-chat\";\n root.setAttribute(\"data-position\", cfg.position);\n root.setAttribute(\"data-open\", \"false\");\n return root;\n}\n\nfunction readCaptureFields(panel: PanelRefs): Record<string, string> {\n const out: Record<string, string> = {};\n const inputs = panel.captureInputs;\n if (inputs.first_name) out.first_name = inputs.first_name.value.trim();\n if (inputs.last_name) out.last_name = inputs.last_name.value.trim();\n if (inputs.email) out.email = inputs.email.value.trim();\n if (inputs.phone) out.phone = inputs.phone.value.trim();\n return out;\n}\n\n// Used by initChat's launcher → keeps the ref objects in scope for TS.\ntype _Refs = LauncherRefs & PanelRefs;\nvoid (null as unknown as _Refs);\n"]}
package/dist/chat.js CHANGED
@@ -1,3 +1,3 @@
1
- export { initChat } from './chunk-ZQT7QEXV.js';
1
+ export { initChat } from './chunk-YDWD2Q5S.js';
2
2
  //# sourceMappingURL=chat.js.map
3
3
  //# sourceMappingURL=chat.js.map
@@ -893,6 +893,7 @@ function initChat(client, options) {
893
893
  }, 6e4);
894
894
  function appendNode(node) {
895
895
  panel.body.appendChild(node);
896
+ if (send.typing && send.typing !== node) panel.body.appendChild(send.typing);
896
897
  scrollToBottom();
897
898
  return node;
898
899
  }
@@ -956,5 +957,5 @@ function readCaptureFields(panel) {
956
957
  }
957
958
 
958
959
  export { initChat };
959
- //# sourceMappingURL=chunk-ZQT7QEXV.js.map
960
- //# sourceMappingURL=chunk-ZQT7QEXV.js.map
960
+ //# sourceMappingURL=chunk-YDWD2Q5S.js.map
961
+ //# sourceMappingURL=chunk-YDWD2Q5S.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/chat/config.ts","../src/chat/session.ts","../src/chat/styles.ts","../src/chat/dom.ts","../src/chat/index.ts"],"names":[],"mappings":"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","file":"chunk-YDWD2Q5S.js","sourcesContent":["/**\n * Chat widget configuration types + defaults.\n *\n * Kept separate from the widget's runtime code so other modules (and the\n * top-level `nexor.initChat()` re-export) can pull types without dragging in\n * the DOM construction code.\n */\nimport type { UUID } from \"../types\";\n\n// ─── Public option / handle types ──────────────────────────────────────────\n\nexport interface ChatLeadCapture {\n /** Which fields to ask for before chatting. Defaults to [\"first_name\", \"email\"]. */\n fields?: Array<\"first_name\" | \"last_name\" | \"email\" | \"phone\">;\n /** \"before\" gates chat behind the form; \"skip\" never asks. Default \"before\". */\n mode?: \"before\" | \"skip\";\n /** Label rendered above the form. */\n label?: string;\n /** Submit button label. */\n submitLabel?: string;\n}\n\nexport interface ChatInitOptions {\n /** Workflow that handles this chat conversation. Required. */\n workflowId: UUID;\n\n // ── Identity / branding ──\n title?: string;\n subtitle?: string;\n greeting?: string;\n /** Shown when a turn fails or the server returns no reply. */\n errorText?: string;\n /** BCP-47 locale for timestamps (e.g. \"es\", \"en-US\"). Defaults to the browser. */\n locale?: string;\n /** Hex colour for bubble + accents. Defaults to #111827. */\n accentColor?: string;\n /** Text colour rendered on top of the accent. Defaults to white. */\n accentTextColor?: string;\n /** Show the \"Powered by Nexor\" footer. Defaults to true. */\n showBranding?: boolean;\n\n // ── Behaviour ──\n position?: \"bottom-right\" | \"bottom-left\";\n /** Auto-open the panel on first load. Defaults to false. */\n openOnLoad?: boolean;\n /** Coalesce rapid-fire messages: wait this many ms of quiet, then send the\n * buffered messages as one combined turn. Defaults to 700. 0 = per message. */\n debounceMs?: number;\n /** Append the widget to a custom element. Defaults to document.body. */\n container?: HTMLElement;\n\n // ── Prompt overrides forwarded to the agent for THIS widget instance ──\n systemPrompt?: string;\n clientPrompt?: string;\n\n // ── Lead linking ──\n /** Pre-known lead info (e.g. a logged-in user). Skips capture if complete. */\n lead?: {\n first_name?: string;\n last_name?: string;\n email?: string;\n phone?: string;\n metadata?: Record<string, unknown>;\n };\n capture?: ChatLeadCapture;\n /** Arbitrary metadata passed with each turn (page URL, UTM, …). */\n metadata?: Record<string, unknown>;\n\n // ── Callbacks ──\n onOpen?: () => void;\n onClose?: () => void;\n onMessage?: (msg: { role: \"user\" | \"bot\"; text: string }) => void;\n onLeadCaptured?: (leadId: UUID) => void;\n onError?: (err: Error) => void;\n}\n\nexport interface ChatHandle {\n open(): void;\n close(): void;\n toggle(): void;\n /** Programmatically send a user message. */\n send(text: string): Promise<void>;\n /** Tear down the widget and remove all DOM. */\n destroy(): void;\n /** Read the current session id (auto-generated on first open). */\n getSessionId(): string;\n}\n\n// ─── Internal resolved-config type ─────────────────────────────────────────\n\nexport interface ResolvedCfg {\n workflowId: UUID;\n title: string;\n subtitle: string;\n greeting: string;\n errorText: string;\n locale?: string;\n accentColor: string;\n accentTextColor: string;\n showBranding: boolean;\n position: \"bottom-right\" | \"bottom-left\";\n openOnLoad: boolean;\n debounceMs: number;\n container?: HTMLElement;\n systemPrompt?: string;\n clientPrompt?: string;\n lead?: ChatInitOptions[\"lead\"];\n capture: Required<ChatLeadCapture>;\n metadata?: Record<string, unknown>;\n onOpen?: () => void;\n onClose?: () => void;\n onMessage?: (msg: { role: \"user\" | \"bot\"; text: string }) => void;\n onLeadCaptured?: (leadId: UUID) => void;\n onError?: (err: Error) => void;\n}\n\n/**\n * Normalize user-provided options into a complete config object with every\n * field set. Downstream code reads from ResolvedCfg and never has to deal\n * with `undefined` for branding / behaviour fields.\n */\nexport function applyDefaults(o: ChatInitOptions): ResolvedCfg {\n return {\n workflowId: o.workflowId,\n title: o.title ?? \"Chat with us\",\n subtitle: o.subtitle ?? \"We typically reply in a few minutes\",\n greeting: o.greeting ?? \"Hi there! 👋 How can we help?\",\n errorText:\n o.errorText ?? \"Sorry, something went wrong. Please try again in a moment.\",\n locale:\n o.locale ??\n (typeof navigator !== \"undefined\" ? navigator.language : undefined),\n accentColor: o.accentColor ?? \"#111827\",\n accentTextColor: o.accentTextColor ?? \"#ffffff\",\n showBranding: o.showBranding ?? true,\n position: o.position ?? \"bottom-right\",\n openOnLoad: o.openOnLoad ?? false,\n debounceMs: o.debounceMs ?? 700,\n container: o.container,\n systemPrompt: o.systemPrompt,\n clientPrompt: o.clientPrompt,\n lead: o.lead,\n capture: {\n fields: o.capture?.fields ?? [\"first_name\", \"email\"],\n mode: o.capture?.mode ?? \"before\",\n label: o.capture?.label ?? \"Tell us a bit about you to get started:\",\n submitLabel: o.capture?.submitLabel ?? \"Start chat\",\n },\n metadata: o.metadata,\n onOpen: o.onOpen,\n onClose: o.onClose,\n onMessage: o.onMessage,\n onLeadCaptured: o.onLeadCaptured,\n onError: o.onError,\n };\n}\n\n/**\n * Does this widget need to show a lead-capture form before chat?\n * - \"skip\" mode → no\n * - Pre-known lead already covers every required field → no\n * - Otherwise → yes\n */\nexport function needsCapture(cfg: ResolvedCfg): boolean {\n if (cfg.capture.mode === \"skip\") return false;\n if (cfg.lead) {\n const have = cfg.lead;\n return cfg.capture.fields.some((f) => !have[f]);\n }\n return true;\n}\n","/**\n * Browser-side session-id management for the chat widget.\n *\n * The session id links anonymous turns to the same lead across page reloads.\n * It's persisted in localStorage with a last-activity timestamp and a sliding\n * retention window: a conversation is kept for at least SESSION_RETENTION_MS\n * after the last activity, after which a fresh session (and transcript) starts.\n * If storage is unavailable (private mode, sandboxed iframe) we fall back to a\n * per-tab id and accept that a refresh starts a new conversation.\n */\n\nconst SESSION_KEY = \"nexor.chat.session_id\";\n\n/** Keep a conversation (session + transcript) this long after the last\n * activity, so a returning visitor can resume it. Reused by the transcript\n * cache in `./index`. The host (e.g. the landing widget) decides when to\n * auto-resume vs. prompt \"continue or start new\". */\nexport const SESSION_RETENTION_MS = 30 * 24 * 60 * 60 * 1000; // 30 days\n\n/**\n * Return the persisted session id, generating one on first use or once the\n * retention window has lapsed. Reading it slides the window forward.\n */\nexport function ensureSessionId(): string {\n const now = Date.now();\n try {\n const rec = readRecord();\n if (rec && now - rec.ts < SESSION_RETENTION_MS) {\n writeRecord(rec.id, now); // slide the window on activity\n return rec.id;\n }\n } catch {\n /* localStorage may be unavailable (private mode, sandboxed iframe). */\n }\n const id = `sess_${randomHex(16)}`;\n try {\n writeRecord(id, now);\n } catch {\n /* ignore — id is still valid for this page load. */\n }\n return id;\n}\n\n/** Bump the session's last-activity timestamp (slides the retention window). */\nexport function touchSession(): void {\n try {\n const rec = readRecord();\n if (rec) writeRecord(rec.id, Date.now());\n } catch {\n /* ignore */\n }\n}\n\nfunction readRecord(): { id: string; ts: number } | null {\n const raw = window.localStorage.getItem(SESSION_KEY);\n if (!raw) return null;\n try {\n const o = JSON.parse(raw);\n if (o && typeof o.id === \"string\" && typeof o.ts === \"number\") return o;\n } catch {\n /* legacy value was a plain \"sess_…\" string — adopt it below. */\n }\n if (raw.startsWith(\"sess_\")) return { id: raw, ts: Date.now() };\n return null;\n}\n\nfunction writeRecord(id: string, ts: number): void {\n window.localStorage.setItem(SESSION_KEY, JSON.stringify({ id, ts }));\n}\n\n/**\n * Hex string from cryptographically-strong randomness when available, with\n * a Math.random() fallback for very old browsers.\n */\nfunction randomHex(bytes: number): string {\n const arr = new Uint8Array(bytes);\n if (typeof crypto !== \"undefined\" && crypto.getRandomValues) {\n crypto.getRandomValues(arr);\n } else {\n for (let i = 0; i < bytes; i++) arr[i] = Math.floor(Math.random() * 256);\n }\n return Array.from(arr, (b) => b.toString(16).padStart(2, \"0\")).join(\"\");\n}\n","/**\n * Scoped CSS for the chat widget.\n *\n * Everything is namespaced under `.nexor-chat` so it cannot leak into the host\n * page, and properties that hosts commonly override (color, font, line-height)\n * are set explicitly here so the host's reset can't bleed in.\n *\n * Animations are GPU-friendly (transform + opacity only — no layout-trashing\n * properties like top/left) and use modest durations so the widget feels\n * responsive on low-end devices.\n */\nexport const widgetCss = (accent: string, accentText: string): string => `\n.nexor-chat,\n.nexor-chat * {\n box-sizing: border-box;\n font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, \"Helvetica Neue\", Arial, sans-serif;\n}\n\n.nexor-chat {\n position: fixed;\n z-index: 2147483640;\n bottom: 20px;\n right: 20px;\n font-size: 14px;\n line-height: 1.4;\n color: #111;\n}\n\n.nexor-chat[data-position=\"bottom-left\"] {\n right: auto;\n left: 20px;\n}\n\n/* ── Launcher bubble ─────────────────────────────────────────────── */\n.nexor-chat__launcher {\n width: 56px;\n height: 56px;\n border-radius: 9999px;\n background: ${accent};\n color: ${accentText};\n border: none;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n box-shadow: 0 6px 18px rgba(0, 0, 0, 0.18);\n transition: transform 160ms cubic-bezier(.2,.7,.2,1.1),\n box-shadow 160ms ease,\n background 200ms ease;\n padding: 0;\n position: relative;\n animation: nexor-launcher-in 360ms cubic-bezier(.2,.7,.2,1.1) both;\n}\n.nexor-chat__launcher:hover {\n transform: translateY(-2px) scale(1.04);\n box-shadow: 0 10px 24px rgba(0, 0, 0, 0.24);\n}\n.nexor-chat__launcher:active {\n transform: translateY(0) scale(0.97);\n transition-duration: 80ms;\n}\n.nexor-chat__launcher:focus-visible {\n outline: 2px solid ${accent};\n outline-offset: 2px;\n}\n.nexor-chat[data-open=\"true\"] .nexor-chat__launcher {\n transform: scale(0.85);\n opacity: 0.75;\n}\n.nexor-chat__launcher svg { width: 24px; height: 24px; transition: transform 200ms ease; }\n.nexor-chat[data-open=\"true\"] .nexor-chat__launcher svg { transform: rotate(8deg); }\n\n.nexor-chat__unread {\n position: absolute;\n top: -4px;\n right: -4px;\n min-width: 18px;\n height: 18px;\n background: #ef4444;\n color: #fff;\n border-radius: 9999px;\n font-size: 11px;\n font-weight: 600;\n padding: 0 5px;\n display: flex;\n align-items: center;\n justify-content: center;\n border: 2px solid #fff;\n animation: nexor-pop-in 300ms cubic-bezier(.2,.7,.2,1.1) both;\n}\n\n@keyframes nexor-launcher-in {\n from { transform: translateY(20px) scale(0.6); opacity: 0; }\n to { transform: translateY(0) scale(1); opacity: 1; }\n}\n@keyframes nexor-pop-in {\n from { transform: scale(0); }\n to { transform: scale(1); }\n}\n\n/* ── Panel ────────────────────────────────────────────────────────── */\n.nexor-chat__panel {\n position: absolute;\n bottom: 72px;\n right: 0;\n width: 360px;\n max-width: calc(100vw - 32px);\n height: 540px;\n max-height: calc(100vh - 120px);\n background: #fff;\n border-radius: 14px;\n box-shadow: 0 24px 60px rgba(0, 0, 0, 0.22);\n display: flex;\n flex-direction: column;\n overflow: hidden;\n transform: translateY(14px) scale(0.96);\n opacity: 0;\n pointer-events: none;\n transition: transform 220ms cubic-bezier(.2,.7,.2,1.1),\n opacity 220ms ease;\n border: 1px solid rgba(0, 0, 0, 0.06);\n /* Use visibility so screen readers don't read collapsed content */\n visibility: hidden;\n}\n.nexor-chat[data-position=\"bottom-left\"] .nexor-chat__panel {\n right: auto;\n left: 0;\n}\n.nexor-chat[data-open=\"true\"] .nexor-chat__panel {\n transform: translateY(0) scale(1);\n opacity: 1;\n pointer-events: auto;\n visibility: visible;\n}\n\n.nexor-chat__header {\n background: ${accent};\n color: ${accentText};\n padding: 14px 16px;\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 12px;\n}\n.nexor-chat__title {\n font-weight: 600;\n font-size: 15px;\n margin: 0;\n}\n.nexor-chat__subtitle {\n font-size: 12px;\n opacity: 0.85;\n margin: 2px 0 0;\n}\n.nexor-chat__status-dot {\n display: inline-block;\n width: 8px;\n height: 8px;\n border-radius: 9999px;\n background: #34d399;\n margin-right: 6px;\n vertical-align: 1px;\n animation: nexor-pulse 2.4s ease-in-out infinite;\n box-shadow: 0 0 0 0 rgba(52, 211, 153, 0.6);\n}\n@keyframes nexor-pulse {\n 0%, 100% { box-shadow: 0 0 0 0 rgba(52, 211, 153, 0.55); }\n 50% { box-shadow: 0 0 0 6px rgba(52, 211, 153, 0); }\n}\n.nexor-chat__close {\n background: transparent;\n border: none;\n color: inherit;\n cursor: pointer;\n padding: 4px;\n border-radius: 6px;\n opacity: 0.9;\n transition: background 140ms ease, transform 140ms ease;\n}\n.nexor-chat__close:hover { background: rgba(255,255,255,0.18); opacity: 1; }\n.nexor-chat__close:active { transform: scale(0.92); }\n.nexor-chat__close svg { width: 18px; height: 18px; display: block; }\n\n/* ── Body / messages ──────────────────────────────────────────────── */\n.nexor-chat__body {\n flex: 1;\n overflow-y: auto;\n padding: 14px;\n background: #f6f7f9;\n display: flex;\n flex-direction: column;\n gap: 8px;\n scroll-behavior: smooth;\n /* Prevent layout shift when scrollbar appears */\n scrollbar-gutter: stable;\n}\n.nexor-chat__body::-webkit-scrollbar { width: 6px; }\n.nexor-chat__body::-webkit-scrollbar-thumb {\n background: rgba(0,0,0,0.15);\n border-radius: 9999px;\n}\n\n.nexor-chat__msg {\n max-width: 80%;\n padding: 8px 12px;\n border-radius: 14px;\n white-space: pre-wrap;\n word-wrap: break-word;\n animation: nexor-msg-in 240ms cubic-bezier(.2,.7,.2,1.1) both;\n will-change: transform, opacity;\n}\n.nexor-chat__msg--bot {\n background: #fff;\n align-self: flex-start;\n border: 1px solid rgba(0,0,0,0.06);\n border-bottom-left-radius: 4px;\n box-shadow: 0 1px 2px rgba(0,0,0,0.04);\n}\n.nexor-chat__msg--user {\n background: ${accent};\n color: ${accentText};\n align-self: flex-end;\n border-bottom-right-radius: 4px;\n animation-name: nexor-msg-in-user;\n}\n.nexor-chat__msg--system {\n background: transparent;\n color: #6b7280;\n font-size: 12px;\n align-self: center;\n text-align: center;\n max-width: 100%;\n animation-name: nexor-fade-in;\n}\n.nexor-chat__msg-time {\n display: block;\n margin-top: 4px;\n font-size: 10px;\n line-height: 1;\n opacity: 0.55;\n text-align: right;\n}\n.nexor-chat__msg--bot .nexor-chat__msg-time { text-align: left; }\n\n@keyframes nexor-msg-in {\n from { transform: translateY(8px) scale(0.96); opacity: 0; }\n to { transform: translateY(0) scale(1); opacity: 1; }\n}\n@keyframes nexor-msg-in-user {\n from { transform: translateY(8px) translateX(8px) scale(0.96); opacity: 0; }\n to { transform: translateY(0) translateX(0) scale(1); opacity: 1; }\n}\n@keyframes nexor-fade-in {\n from { opacity: 0; }\n to { opacity: 1; }\n}\n\n.nexor-chat__typing {\n align-self: flex-start;\n background: #fff;\n border: 1px solid rgba(0,0,0,0.06);\n border-radius: 14px;\n border-bottom-left-radius: 4px;\n padding: 10px 14px;\n display: inline-flex;\n gap: 4px;\n animation: nexor-msg-in 240ms cubic-bezier(.2,.7,.2,1.1) both;\n}\n.nexor-chat__typing span {\n width: 6px; height: 6px; border-radius: 9999px;\n background: #9ca3af;\n display: inline-block;\n animation: nexor-blink 1.2s infinite ease-in-out;\n}\n.nexor-chat__typing span:nth-child(2) { animation-delay: 0.15s; }\n.nexor-chat__typing span:nth-child(3) { animation-delay: 0.30s; }\n@keyframes nexor-blink {\n 0%, 60%, 100% { opacity: 0.3; transform: translateY(0); }\n 30% { opacity: 1; transform: translateY(-3px); }\n}\n\n/* ── Lead capture form ────────────────────────────────────────────── */\n.nexor-chat__capture {\n background: #fff;\n border: 1px solid rgba(0,0,0,0.06);\n border-radius: 12px;\n padding: 12px;\n display: flex;\n flex-direction: column;\n gap: 8px;\n margin-top: 4px;\n animation: nexor-msg-in 280ms cubic-bezier(.2,.7,.2,1.1) both;\n box-shadow: 0 2px 8px rgba(0,0,0,0.05);\n}\n.nexor-chat__capture-label {\n font-size: 12px;\n color: #6b7280;\n margin: 0;\n}\n.nexor-chat__capture-row {\n display: flex;\n gap: 8px;\n}\n.nexor-chat__capture-row > * { flex: 1; }\n.nexor-chat__input,\n.nexor-chat__capture input {\n font: inherit;\n padding: 8px 10px;\n border: 1px solid #d1d5db;\n border-radius: 8px;\n background: #fff;\n color: #111;\n outline: none;\n width: 100%;\n transition: border-color 140ms ease, box-shadow 140ms ease;\n}\n.nexor-chat__input:focus,\n.nexor-chat__capture input:focus {\n border-color: ${accent};\n box-shadow: 0 0 0 3px ${accent}33;\n}\n.nexor-chat__capture-submit {\n background: ${accent};\n color: ${accentText};\n border: none;\n border-radius: 8px;\n padding: 8px 12px;\n font: inherit;\n font-weight: 600;\n cursor: pointer;\n transition: transform 140ms ease, filter 140ms ease;\n}\n.nexor-chat__capture-submit:hover { filter: brightness(1.08); }\n.nexor-chat__capture-submit:active { transform: scale(0.97); }\n.nexor-chat__capture-submit[disabled] { opacity: 0.6; cursor: not-allowed; }\n\n/* ── Composer ─────────────────────────────────────────────────────── */\n.nexor-chat__composer {\n display: flex;\n gap: 8px;\n padding: 10px;\n background: #fff;\n border-top: 1px solid rgba(0,0,0,0.06);\n align-items: stretch;\n}\n.nexor-chat__send {\n background: ${accent};\n color: ${accentText};\n border: none;\n border-radius: 8px;\n padding: 0 14px;\n font: inherit;\n font-weight: 600;\n cursor: pointer;\n min-width: 44px;\n display: flex;\n align-items: center;\n justify-content: center;\n transition: transform 140ms ease, filter 140ms ease;\n}\n.nexor-chat__send:hover { filter: brightness(1.08); }\n.nexor-chat__send:active { transform: scale(0.95); }\n.nexor-chat__send[disabled] {\n opacity: 0.6;\n cursor: not-allowed;\n transform: none;\n}\n.nexor-chat__send svg {\n width: 18px;\n height: 18px;\n transition: transform 200ms ease;\n}\n.nexor-chat__send:not([disabled]):hover svg { transform: translateX(2px); }\n\n/* Small spinner inside the send button while a turn is in flight */\n.nexor-chat__send--loading svg { display: none; }\n.nexor-chat__send--loading::after {\n content: \"\";\n width: 14px;\n height: 14px;\n border-radius: 9999px;\n border: 2px solid currentColor;\n border-top-color: transparent;\n animation: nexor-spin 700ms linear infinite;\n}\n@keyframes nexor-spin {\n to { transform: rotate(360deg); }\n}\n\n.nexor-chat__footer {\n text-align: center;\n font-size: 11px;\n color: #9ca3af;\n padding: 6px;\n background: #fff;\n border-top: 1px solid rgba(0,0,0,0.04);\n}\n.nexor-chat__footer a {\n color: inherit;\n text-decoration: none;\n font-weight: 600;\n}\n.nexor-chat__footer a:hover { text-decoration: underline; }\n\n/* Respect users who request reduced motion. */\n@media (prefers-reduced-motion: reduce) {\n .nexor-chat,\n .nexor-chat * {\n animation-duration: 0.001ms !important;\n transition-duration: 0.001ms !important;\n }\n .nexor-chat__status-dot { animation: none; }\n}\n`;\n","/**\n * Pure DOM construction for the chat widget.\n *\n * Each `build*` function returns a fully-formed sub-tree plus refs to the\n * inner nodes the orchestrator (initChat) wires events to. No side effects\n * here other than calling `injectStyles()` once per page.\n *\n * Why split this out from index.ts?\n * - The DOM layer doesn't depend on the NexorClient or sessionId — keeping\n * it pure makes the widget easy to reason about and easy to dry-run in\n * unit tests by mocking `document`.\n * - The orchestrator becomes a 150-line state machine instead of a\n * 600-line god-function.\n */\nimport { needsCapture, type ResolvedCfg } from \"./config\";\nimport { widgetCss } from \"./styles\";\n\nconst STYLE_ATTR = \"data-nexor-chat-styles\";\n\n// ─── Stylesheet (singleton per page) ───────────────────────────────────────\n\n/**\n * Inject the widget's stylesheet once per page. If multiple widgets mount,\n * they share styles and the first widget's accent colour wins. Two widgets\n * with different accents on one page is an unsupported use case.\n */\nexport function injectStyles(accent: string, accentText: string): void {\n if (document.querySelector(`style[${STYLE_ATTR}]`)) return;\n const style = document.createElement(\"style\");\n style.setAttribute(STYLE_ATTR, \"1\");\n style.textContent = widgetCss(accent, accentText);\n document.head.appendChild(style);\n}\n\n// ─── Launcher ──────────────────────────────────────────────────────────────\n\nexport interface LauncherRefs {\n el: HTMLButtonElement;\n badge: HTMLSpanElement;\n}\n\nexport function buildLauncher(): LauncherRefs {\n const el = document.createElement(\"button\");\n el.type = \"button\";\n el.className = \"nexor-chat__launcher\";\n el.setAttribute(\"aria-label\", \"Open chat\");\n // Speech-bubble icon — SVG rather than emoji for crisp rendering at any DPR.\n el.innerHTML = `\n <svg viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\" aria-hidden=\"true\">\n <path d=\"M4 5.5C4 4.67 4.67 4 5.5 4h13c.83 0 1.5.67 1.5 1.5v9c0 .83-.67 1.5-1.5 1.5H9l-4 4V5.5Z\"\n stroke=\"currentColor\" stroke-width=\"1.8\" stroke-linejoin=\"round\"/>\n </svg>\n `;\n const badge = document.createElement(\"span\");\n badge.className = \"nexor-chat__unread\";\n badge.style.display = \"none\";\n el.appendChild(badge);\n return { el, badge };\n}\n\n// ─── Panel ─────────────────────────────────────────────────────────────────\n\ntype CaptureField = \"first_name\" | \"last_name\" | \"email\" | \"phone\";\n\nexport interface PanelRefs {\n el: HTMLDivElement;\n closeBtn: HTMLButtonElement;\n body: HTMLDivElement;\n form: HTMLFormElement;\n input: HTMLInputElement;\n send: HTMLButtonElement;\n captureForm: HTMLFormElement | null;\n captureInputs: Partial<Record<CaptureField, HTMLInputElement>>;\n}\n\nexport function buildPanel(cfg: ResolvedCfg): PanelRefs {\n const el = document.createElement(\"div\");\n el.className = \"nexor-chat__panel\";\n el.setAttribute(\"role\", \"dialog\");\n el.setAttribute(\"aria-label\", cfg.title);\n\n const { header, closeBtn } = buildHeader(cfg);\n const { body, captureForm, captureInputs } = buildBody(cfg);\n const { form, input, send } = buildComposer();\n const footer = cfg.showBranding ? buildFooter() : null;\n\n el.appendChild(header);\n el.appendChild(body);\n el.appendChild(form);\n if (footer) el.appendChild(footer);\n\n return { el, closeBtn, body, form, input, send, captureForm, captureInputs };\n}\n\nfunction buildHeader(cfg: ResolvedCfg): {\n header: HTMLDivElement;\n closeBtn: HTMLButtonElement;\n} {\n const header = document.createElement(\"div\");\n header.className = \"nexor-chat__header\";\n\n // The status dot signals \"we're live and listening\" — purely cosmetic, but\n // a strong UX signal. Hidden from assistive tech because the title carries\n // the meaning already.\n const subtitleHtml = cfg.subtitle\n ? `<p class=\"nexor-chat__subtitle\">\n <span class=\"nexor-chat__status-dot\" aria-hidden=\"true\"></span>${escapeHtml(cfg.subtitle)}\n </p>`\n : \"\";\n\n header.innerHTML = `\n <div>\n <p class=\"nexor-chat__title\">${escapeHtml(cfg.title)}</p>\n ${subtitleHtml}\n </div>\n `;\n\n const closeBtn = document.createElement(\"button\");\n closeBtn.type = \"button\";\n closeBtn.className = \"nexor-chat__close\";\n closeBtn.setAttribute(\"aria-label\", \"Close chat\");\n closeBtn.innerHTML = `\n <svg viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\" aria-hidden=\"true\">\n <path d=\"M6 6l12 12M6 18L18 6\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\"/>\n </svg>\n `;\n header.appendChild(closeBtn);\n return { header, closeBtn };\n}\n\nfunction buildBody(cfg: ResolvedCfg): {\n body: HTMLDivElement;\n captureForm: HTMLFormElement | null;\n captureInputs: Partial<Record<CaptureField, HTMLInputElement>>;\n} {\n const body = document.createElement(\"div\");\n body.className = \"nexor-chat__body\";\n const captureInputs: Partial<Record<CaptureField, HTMLInputElement>> = {};\n let captureForm: HTMLFormElement | null = null;\n\n if (needsCapture(cfg)) {\n captureForm = buildCaptureForm(cfg, captureInputs);\n body.appendChild(captureForm);\n }\n return { body, captureForm, captureInputs };\n}\n\nfunction buildCaptureForm(\n cfg: ResolvedCfg,\n inputsOut: Partial<Record<CaptureField, HTMLInputElement>>,\n): HTMLFormElement {\n const form = document.createElement(\"form\");\n form.className = \"nexor-chat__capture\";\n form.noValidate = true;\n\n const label = document.createElement(\"p\");\n label.className = \"nexor-chat__capture-label\";\n label.textContent = cfg.capture.label;\n form.appendChild(label);\n\n const fields = cfg.capture.fields;\n\n // first_name + last_name share a row to feel like a single \"your name\" prompt.\n if (fields.includes(\"first_name\") || fields.includes(\"last_name\")) {\n const row = document.createElement(\"div\");\n row.className = \"nexor-chat__capture-row\";\n if (fields.includes(\"first_name\")) {\n inputsOut.first_name = makeInput(\"first_name\", \"First name\", \"text\", cfg.lead?.first_name);\n row.appendChild(inputsOut.first_name);\n }\n if (fields.includes(\"last_name\")) {\n inputsOut.last_name = makeInput(\"last_name\", \"Last name\", \"text\", cfg.lead?.last_name);\n row.appendChild(inputsOut.last_name);\n }\n if (row.childElementCount > 0) form.appendChild(row);\n }\n if (fields.includes(\"email\")) {\n inputsOut.email = makeInput(\"email\", \"Email\", \"email\", cfg.lead?.email);\n form.appendChild(inputsOut.email);\n }\n if (fields.includes(\"phone\")) {\n inputsOut.phone = makeInput(\"phone\", \"Phone\", \"tel\", cfg.lead?.phone);\n form.appendChild(inputsOut.phone);\n }\n\n const submit = document.createElement(\"button\");\n submit.type = \"submit\";\n submit.className = \"nexor-chat__capture-submit\";\n submit.textContent = cfg.capture.submitLabel;\n form.appendChild(submit);\n\n return form;\n}\n\nfunction buildComposer(): {\n form: HTMLFormElement;\n input: HTMLInputElement;\n send: HTMLButtonElement;\n} {\n const form = document.createElement(\"form\");\n form.className = \"nexor-chat__composer\";\n\n const input = document.createElement(\"input\");\n input.type = \"text\";\n input.className = \"nexor-chat__input\";\n input.placeholder = \"Type a message…\";\n input.autocomplete = \"off\";\n\n const send = document.createElement(\"button\");\n send.type = \"submit\";\n send.className = \"nexor-chat__send\";\n send.setAttribute(\"aria-label\", \"Send message\");\n // Paper-airplane icon — language-agnostic, recognisable, replaces \"Send\" text.\n send.innerHTML = `\n <svg viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\" aria-hidden=\"true\">\n <path d=\"M3.4 11.2 20.5 4.3c.7-.3 1.4.4 1.1 1.1l-6.9 17.1c-.3.8-1.4.8-1.8 0L10 14l-7.5-3c-.8-.3-.8-1.5 0-1.8Z\"\n stroke=\"currentColor\" stroke-width=\"1.6\" stroke-linejoin=\"round\" fill=\"currentColor\"/>\n </svg>\n `;\n\n form.appendChild(input);\n form.appendChild(send);\n return { form, input, send };\n}\n\nfunction buildFooter(): HTMLDivElement {\n const el = document.createElement(\"div\");\n el.className = \"nexor-chat__footer\";\n el.innerHTML = `Powered by <a href=\"https://www.getnexor.ai\" target=\"_blank\" rel=\"noopener noreferrer\">Nexor</a>`;\n return el;\n}\n\n// ─── Message bubbles ───────────────────────────────────────────────────────\n\nexport type MessageRole = \"user\" | \"bot\" | \"system\";\n\n/**\n * Build a chat bubble. `textContent` is used (never innerHTML) so user input\n * is rendered as plain text — no XSS surface from message payloads.\n */\nexport function buildMessage(\n role: MessageRole,\n text: string,\n ts?: number,\n locale?: string,\n): HTMLDivElement {\n const el = document.createElement(\"div\");\n el.className = `nexor-chat__msg nexor-chat__msg--${role}`;\n const body = document.createElement(\"span\");\n body.className = \"nexor-chat__msg-text\";\n body.textContent = text;\n el.appendChild(body);\n // Relative time under user/bot messages (not system notices). `data-ts` lets\n // the widget refresh the label as time passes (see index.ts).\n if (role !== \"system\" && ts) {\n const time = document.createElement(\"time\");\n time.className = \"nexor-chat__msg-time\";\n time.dataset.ts = String(ts);\n time.textContent = formatRelativeTime(ts, locale);\n el.appendChild(time);\n }\n return el;\n}\n\n/**\n * Relative within the last week (\"ahora\", \"hace 3 minutos\", \"hace 2 horas\",\n * \"ayer\"), then an absolute date (\"12 may\"). Localized via Intl; falls back to\n * a plain clock time if Intl.RelativeTimeFormat is unavailable.\n */\nexport function formatRelativeTime(\n ts: number,\n locale?: string,\n now: number = Date.now(),\n): string {\n try {\n const diff = Math.max(0, now - ts);\n const min = Math.round(diff / 60000);\n const hr = Math.round(diff / 3600000);\n const day = Math.round(diff / 86400000);\n const rtf = new Intl.RelativeTimeFormat(locale, { numeric: \"auto\" });\n if (diff < 45000) return rtf.format(0, \"second\"); // \"ahora\" / \"now\"\n if (min < 60) return rtf.format(-min, \"minute\");\n if (hr < 24) return rtf.format(-hr, \"hour\");\n if (day < 7) return rtf.format(-day, \"day\"); // includes \"ayer\"/\"yesterday\"\n return new Date(ts).toLocaleDateString(locale, {\n day: \"numeric\",\n month: \"short\",\n });\n } catch {\n try {\n return new Date(ts).toLocaleTimeString(locale, {\n hour: \"2-digit\",\n minute: \"2-digit\",\n });\n } catch {\n return \"\";\n }\n }\n}\n\n/** Three-dot typing indicator. Animation lives in styles.ts. */\nexport function buildTypingIndicator(): HTMLDivElement {\n const el = document.createElement(\"div\");\n el.className = \"nexor-chat__typing\";\n el.innerHTML = \"<span></span><span></span><span></span>\";\n return el;\n}\n\n// ─── Helpers ───────────────────────────────────────────────────────────────\n\nfunction makeInput(\n name: string,\n placeholder: string,\n type: string,\n value?: string,\n): HTMLInputElement {\n const i = document.createElement(\"input\");\n i.name = name;\n i.type = type;\n i.placeholder = placeholder;\n if (value) i.value = value;\n return i;\n}\n\n/**\n * Escape strings before interpolation into innerHTML. Used only for\n * SDK-controlled config values (title, subtitle) — user-typed messages\n * always go through textContent, which doesn't need escaping.\n */\nfunction escapeHtml(s: string): string {\n return s\n .replace(/&/g, \"&amp;\")\n .replace(/</g, \"&lt;\")\n .replace(/>/g, \"&gt;\")\n .replace(/\"/g, \"&quot;\")\n .replace(/'/g, \"&#039;\");\n}\n","/**\n * Chat widget orchestrator.\n *\n * Responsibilities (everything else lives in sibling files):\n * - apply defaults / validate options (`./config`)\n * - manage session id (`./session`)\n * - build DOM (`./dom`)\n * - inject CSS (`./dom`)\n *\n * What stays here:\n * - the open/close state machine\n * - wiring DOM events to the NexorClient.chat() call\n * - lead-capture submission flow\n * - the public ChatHandle returned to callers\n */\nimport type { NexorClient } from \"../client\";\nimport type { UUID } from \"../types\";\nimport {\n applyDefaults,\n needsCapture,\n type ChatInitOptions,\n type ChatHandle,\n type ResolvedCfg,\n} from \"./config\";\nimport { ensureSessionId, touchSession, SESSION_RETENTION_MS } from \"./session\";\nimport {\n buildLauncher,\n buildMessage,\n buildPanel,\n buildTypingIndicator,\n formatRelativeTime,\n injectStyles,\n type LauncherRefs,\n type MessageRole,\n type PanelRefs,\n} from \"./dom\";\n\n// Re-export the public types so consumers can `import type { ChatHandle } from \"@getnexorai/sdk\"`.\nexport type { ChatInitOptions, ChatHandle, ChatLeadCapture } from \"./config\";\n\n// Delay before showing the typing indicator. Short replies arrive before this\n// fires and never show the dots, which feels snappier than always flashing them.\nconst TYPING_DELAY_MS = 220;\n\n/**\n * Mount the chat widget and return a handle for programmatic control.\n *\n * @param client The NexorClient instance that will send turns.\n * @param options User-facing widget configuration. See ChatInitOptions.\n * @throws If called outside a browser, or without a workflowId.\n */\nexport function initChat(\n client: NexorClient,\n options: ChatInitOptions,\n): ChatHandle {\n ensureBrowser();\n if (!options || !options.workflowId) {\n throw new Error(\"Nexor SDK: initChat() requires `workflowId`.\");\n }\n\n const cfg = applyDefaults(options);\n injectStyles(cfg.accentColor, cfg.accentTextColor);\n\n const sessionId = ensureSessionId();\n const historyKey = `nexor.chat.history.${sessionId}`;\n const root = buildRoot(cfg);\n const launcher = buildLauncher();\n const panel = buildPanel(cfg);\n root.appendChild(launcher.el);\n root.appendChild(panel.el);\n (cfg.container ?? document.body).appendChild(root);\n\n // ─── State (closure-private — no external observers needed) ─────────────\n const state = {\n isOpen: false,\n unread: 0,\n leadId: undefined as UUID | undefined,\n captured: !needsCapture(cfg),\n pendingLead: { ...(cfg.lead ?? {}) },\n history: [] as Array<{ role: \"user\" | \"bot\"; text: string; ts?: number }>,\n };\n\n // ─── DOM event wiring ───────────────────────────────────────────────────\n launcher.el.addEventListener(\"click\", toggle);\n panel.closeBtn.addEventListener(\"click\", close);\n panel.form.addEventListener(\"submit\", onComposerSubmit);\n panel.captureForm?.addEventListener(\"submit\", onCaptureSubmit);\n\n syncComposerLock();\n\n // Restore a prior transcript (persisted up to SESSION_RETENTION_MS) so a\n // page reload keeps the conversation. Rendered into the (possibly closed)\n // panel; the greeting is then skipped because history is non-empty.\n const restored = loadHistory();\n if (restored.length) {\n state.history = restored;\n for (const m of restored) appendBubble(m.role === \"user\" ? \"user\" : \"bot\", m.text, m.ts);\n scrollToBottom();\n }\n\n if (cfg.openOnLoad) open();\n\n // ─── State machine ──────────────────────────────────────────────────────\n\n function open(): void {\n if (state.isOpen) return;\n state.isOpen = true;\n root.setAttribute(\"data-open\", \"true\");\n clearUnread();\n // Lazy-greet: first time the panel opens, drop the greeting message.\n if (state.history.length === 0 && cfg.greeting && state.captured) {\n appendBot(cfg.greeting);\n }\n panel.input.focus();\n cfg.onOpen?.();\n }\n\n function close(): void {\n if (!state.isOpen) return;\n state.isOpen = false;\n root.setAttribute(\"data-open\", \"false\");\n cfg.onClose?.();\n }\n\n function toggle(): void {\n state.isOpen ? close() : open();\n }\n\n // ─── Capture flow ───────────────────────────────────────────────────────\n\n function onCaptureSubmit(e: Event): void {\n e.preventDefault();\n const collected = readCaptureFields(panel);\n // Validate that all required fields are filled before unlocking the chat.\n const required = cfg.capture.fields;\n for (const f of required) {\n if (!collected[f]) {\n panel.captureInputs[f]?.focus();\n return;\n }\n }\n state.pendingLead = { ...state.pendingLead, ...collected };\n state.captured = true;\n panel.captureForm?.remove();\n syncComposerLock();\n panel.input.focus();\n // Greet once capture clears, so the greeting feels like a response to \"I'm ready\".\n if (cfg.greeting && state.history.length === 0) appendBot(cfg.greeting);\n }\n\n // ─── Composer / send (debounced + coalesced) ────────────────────────────\n //\n // Visitors fire several short messages in a row (WhatsApp-style). We mirror\n // the WhatsApp contract — batch at the source, one LLM call per batch — by\n // buffering rapid messages in the browser and POSTing them as a SINGLE\n // combined turn after a short quiet window. The composer never locks, so the\n // user can keep typing and sending freely; messages that land mid-request are\n // sent in the next batch.\n\n const send = {\n pending: [] as string[],\n timer: 0,\n typingTimer: 0,\n inFlight: false,\n typing: null as HTMLElement | null,\n };\n\n function onComposerSubmit(e: Event): void {\n e.preventDefault();\n const text = panel.input.value.trim();\n if (!text) return;\n panel.input.value = \"\";\n queueMessage(text);\n }\n\n function queueMessage(text: string): void {\n if (!state.captured) {\n panel.captureInputs.first_name?.focus();\n return;\n }\n appendUser(text);\n send.pending.push(text);\n scheduleFlush();\n }\n\n function scheduleFlush(): void {\n if (send.timer) window.clearTimeout(send.timer);\n send.timer = window.setTimeout(() => void flush(), cfg.debounceMs);\n }\n\n async function flush(): Promise<void> {\n if (send.inFlight || send.pending.length === 0) return;\n const batch = send.pending.splice(0, send.pending.length);\n const message = batch.join(\"\\n\");\n send.inFlight = true;\n\n // Delay the typing dots so fast replies don't flash them.\n send.typingTimer = window.setTimeout(() => {\n send.typing = appendNode(buildTypingIndicator());\n }, TYPING_DELAY_MS);\n\n try {\n const res = await client.chat({\n workflow_id: cfg.workflowId,\n session_id: sessionId,\n message,\n system_prompt: cfg.systemPrompt,\n client_prompt: cfg.clientPrompt,\n lead: Object.keys(state.pendingLead).length ? state.pendingLead : undefined,\n metadata: cfg.metadata,\n });\n if (res.lead_id && !state.leadId) {\n state.leadId = res.lead_id;\n cfg.onLeadCaptured?.(state.leadId);\n }\n const reply = (res.reply ?? \"\").trim();\n if (reply) {\n appendBot(reply);\n } else {\n // No text came back (empty completion / tool-only turn). Never render a\n // blank bubble — show the fallback and surface it to the host.\n appendSystem(cfg.errorText);\n cfg.onError?.(new Error(\"Nexor SDK: empty reply from server\"));\n }\n } catch (err) {\n appendSystem(cfg.errorText);\n cfg.onError?.(err as Error);\n } finally {\n window.clearTimeout(send.typingTimer);\n send.typing?.remove();\n send.typing = null;\n send.inFlight = false;\n panel.input.focus();\n // Anything queued while the request was in flight goes out next.\n if (send.pending.length) scheduleFlush();\n }\n }\n\n // ─── Message rendering ──────────────────────────────────────────────────\n\n function appendUser(text: string): void {\n const ts = Date.now();\n appendBubble(\"user\", text, ts);\n state.history.push({ role: \"user\", text, ts });\n saveHistory();\n cfg.onMessage?.({ role: \"user\", text });\n }\n\n function appendBot(text: string): void {\n const ts = Date.now();\n appendBubble(\"bot\", text, ts);\n state.history.push({ role: \"bot\", text, ts });\n saveHistory();\n if (!state.isOpen) bumpUnread();\n cfg.onMessage?.({ role: \"bot\", text });\n }\n\n // ─── Transcript persistence (survives reloads up to SESSION_RETENTION_MS) ──\n\n function saveHistory(): void {\n try {\n window.localStorage.setItem(\n historyKey,\n JSON.stringify({ ts: Date.now(), history: state.history }),\n );\n touchSession(); // keep the session alive in step with the transcript\n } catch {\n /* storage unavailable — in-memory history still works for this load. */\n }\n }\n\n function loadHistory(): Array<{ role: \"user\" | \"bot\"; text: string; ts?: number }> {\n try {\n const raw = window.localStorage.getItem(historyKey);\n if (!raw) return [];\n const o = JSON.parse(raw);\n if (!o || !Array.isArray(o.history)) return [];\n if (Date.now() - (o.ts || 0) > SESSION_RETENTION_MS) {\n window.localStorage.removeItem(historyKey);\n return [];\n }\n return o.history;\n } catch {\n return [];\n }\n }\n\n function appendSystem(text: string): void {\n appendBubble(\"system\", text);\n }\n\n function appendBubble(\n role: MessageRole,\n text: string,\n ts?: number,\n ): HTMLDivElement {\n return appendNode(buildMessage(role, text, ts, cfg.locale));\n }\n\n // Keep relative timestamps (\"hace 3 minutos\") fresh while the panel is open.\n const refreshTimer = window.setInterval(() => {\n panel.body\n .querySelectorAll<HTMLTimeElement>(\".nexor-chat__msg-time[data-ts]\")\n .forEach((el) => {\n const ts = Number(el.dataset.ts);\n if (ts) el.textContent = formatRelativeTime(ts, cfg.locale);\n });\n }, 60_000);\n\n function appendNode<T extends HTMLElement>(node: T): T {\n panel.body.appendChild(node);\n // Keep the typing indicator pinned to the bottom: if the visitor fires\n // another message while we're awaiting a reply, the dots must stay BELOW\n // it (the bot hasn't \"typed\" yet), not stranded between messages.\n if (send.typing && send.typing !== node) panel.body.appendChild(send.typing);\n scrollToBottom();\n return node;\n }\n\n function scrollToBottom(): void {\n panel.body.scrollTop = panel.body.scrollHeight;\n }\n\n // ─── Unread badge ───────────────────────────────────────────────────────\n\n function bumpUnread(): void {\n state.unread++;\n launcher.badge.textContent = String(state.unread);\n launcher.badge.style.display = \"flex\";\n }\n function clearUnread(): void {\n state.unread = 0;\n launcher.badge.style.display = \"none\";\n }\n\n // ─── Composer lock (used while capture form is visible) ─────────────────\n\n function syncComposerLock(): void {\n const lock = !state.captured;\n panel.input.disabled = lock;\n panel.send.disabled = lock;\n panel.input.placeholder = lock\n ? \"Complete the form above to start…\"\n : \"Type a message…\";\n }\n\n // ─── Public handle ──────────────────────────────────────────────────────\n\n return {\n open,\n close,\n toggle,\n // Programmatic send goes through the same debounce/coalesce path. Resolves\n // immediately — the message is queued, not necessarily sent yet.\n send: (text: string) => {\n queueMessage(text);\n return Promise.resolve();\n },\n destroy: () => {\n if (send.timer) window.clearTimeout(send.timer);\n if (send.typingTimer) window.clearTimeout(send.typingTimer);\n window.clearInterval(refreshTimer);\n root.remove();\n },\n getSessionId: () => sessionId,\n };\n}\n\n// ─── Module-scoped helpers ────────────────────────────────────────────────\n\nfunction ensureBrowser(): void {\n if (typeof window === \"undefined\" || typeof document === \"undefined\") {\n throw new Error(\"Nexor SDK: initChat() requires a browser environment.\");\n }\n}\n\nfunction buildRoot(cfg: ResolvedCfg): HTMLDivElement {\n const root = document.createElement(\"div\");\n root.className = \"nexor-chat\";\n root.setAttribute(\"data-position\", cfg.position);\n root.setAttribute(\"data-open\", \"false\");\n return root;\n}\n\nfunction readCaptureFields(panel: PanelRefs): Record<string, string> {\n const out: Record<string, string> = {};\n const inputs = panel.captureInputs;\n if (inputs.first_name) out.first_name = inputs.first_name.value.trim();\n if (inputs.last_name) out.last_name = inputs.last_name.value.trim();\n if (inputs.email) out.email = inputs.email.value.trim();\n if (inputs.phone) out.phone = inputs.phone.value.trim();\n return out;\n}\n\n// Used by initChat's launcher → keeps the ref objects in scope for TS.\ntype _Refs = LauncherRefs & PanelRefs;\nvoid (null as unknown as _Refs);\n"]}
package/dist/index.cjs CHANGED
@@ -1293,6 +1293,7 @@ function initChat(client, options) {
1293
1293
  }, 6e4);
1294
1294
  function appendNode(node) {
1295
1295
  panel.body.appendChild(node);
1296
+ if (send.typing && send.typing !== node) panel.body.appendChild(send.typing);
1296
1297
  scrollToBottom();
1297
1298
  return node;
1298
1299
  }