@oyehello/chat 0.1.0 → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -13,13 +13,13 @@ npm install @oyehello/chat
13
13
  <oyehello-chat
14
14
  api-key="ohk_pub_…"
15
15
  agent-id="agt_…"
16
- base-url="https://call.hotreloads.ai"
16
+ base-url="https://api.oyehello.ai"
17
17
  ></oyehello-chat>
18
18
  ```
19
19
  Or via a plain script tag (no bundler):
20
20
  ```html
21
21
  <script src="https://unpkg.com/@oyehello/chat"></script>
22
- <oyehello-chat api-key="ohk_pub_…" agent-id="agt_…" base-url="https://call.hotreloads.ai"></oyehello-chat>
22
+ <oyehello-chat api-key="ohk_pub_…" agent-id="agt_…" base-url="https://api.oyehello.ai"></oyehello-chat>
23
23
  ```
24
24
  Theme the accent with the `--oc-accent` CSS variable.
25
25
 
@@ -28,7 +28,7 @@ The custom element works in React too (React 19 natively; React 18 fine for thes
28
28
  ```tsx
29
29
  import '@oyehello/chat';
30
30
  export default function Chat() {
31
- return <oyehello-chat api-key="ohk_pub_…" agent-id="agt_…" base-url="https://call.hotreloads.ai" />;
31
+ return <oyehello-chat api-key="ohk_pub_…" agent-id="agt_…" base-url="https://api.oyehello.ai" />;
32
32
  }
33
33
  ```
34
34
  TypeScript/TSX users add this ambient declaration once (e.g. `oyehello-chat.d.ts`) so the tag typechecks:
@@ -47,7 +47,7 @@ export {};
47
47
  ## Headless (build your own UI)
48
48
  ```js
49
49
  import { createChatClient } from '@oyehello/chat';
50
- const chat = createChatClient({ apiKey: 'ohk_pub_…', agentId: 'agt_…', baseUrl: 'https://call.hotreloads.ai' });
50
+ const chat = createChatClient({ apiKey: 'ohk_pub_…', agentId: 'agt_…', baseUrl: 'https://api.oyehello.ai' });
51
51
  chat.on((e) => { if (e.type === 'messages') render(e.messages); });
52
52
  await chat.start();
53
53
  await chat.sendMessage('Hello');
package/dist/index.cjs CHANGED
@@ -105,7 +105,7 @@ async function uploadToPresigned(uploadUrl, file, fetchImpl) {
105
105
  var seq = 0;
106
106
  var uid = (p) => `${p}_${Date.now().toString(36)}_${(seq++).toString(36)}`;
107
107
  function createChatClient(options) {
108
- const fetchImpl = options.fetch ?? globalThis.fetch;
108
+ const fetchImpl = options.fetch ?? globalThis.fetch.bind(globalThis);
109
109
  const ES = options.eventSource ?? globalThis.EventSource;
110
110
  const maxAttachments = options.maxAttachments ?? 4;
111
111
  const maxAttachmentBytes = options.maxAttachmentBytes ?? 1e7;
@@ -363,6 +363,10 @@ var OyehelloChatElement = class extends HTMLElement {
363
363
  // Transient "agent is typing…" affordance (Phase 7 followups) - never a message, only rendered
364
364
  // while a handoff is active (human/awaiting_human).
365
365
  agentTyping = false;
366
+ // Last connection/runtime error message (client emits an 'error' event on a failed start() or
367
+ // send). Surfaced as a visible banner so a disabled composer always shows WHY, instead of sitting
368
+ // dead. Cleared when the client reaches a healthy state again.
369
+ lastError = null;
366
370
  // registerTools() may be called before connectedCallback creates the client (e.g. right after
367
371
  // document.createElement, before the element is attached). Buffer until the client exists.
368
372
  pendingTools = {};
@@ -391,10 +395,13 @@ var OyehelloChatElement = class extends HTMLElement {
391
395
  }
392
396
  this.off = this.client.on((e) => {
393
397
  if (e.type === "messages") this.messages = e.messages;
394
- else if (e.type === "state") this.state = e.state;
395
- else if (e.type === "agent") this.agentName = e.agent.name;
398
+ else if (e.type === "state") {
399
+ this.state = e.state;
400
+ if (e.state === "ready" || e.state === "opening") this.lastError = null;
401
+ } else if (e.type === "agent") this.agentName = e.agent.name;
396
402
  else if (e.type === "handoff") this.handoffState = e.state;
397
403
  else if (e.type === "agentTyping") this.agentTyping = e.active;
404
+ else if (e.type === "error") this.lastError = e.error.message;
398
405
  this.render();
399
406
  });
400
407
  this.render();
@@ -464,6 +471,7 @@ var OyehelloChatElement = class extends HTMLElement {
464
471
  }).join("");
465
472
  const statusText = HANDOFF_STATUS_TEXT[this.handoffState];
466
473
  const status = statusText ? `<div class="status">${escapeHtml(statusText)}</div>` : "";
474
+ const errBanner = this.state === "error" && this.lastError ? `<div class="err">Couldn't start chat: ${escapeHtml(this.lastError)}</div>` : "";
467
475
  const showTyping = this.agentTyping && (this.handoffState === "human" || this.handoffState === "awaiting_human");
468
476
  const typingIndicator = showTyping ? `<div class="b assistant typing">${escapeHtml(AGENT_TYPING_TEXT)}</div>` : "";
469
477
  const disabled = this.state !== "ready" ? "disabled" : "";
@@ -485,6 +493,7 @@ var OyehelloChatElement = class extends HTMLElement {
485
493
  .b.typing{font-style:italic;color:#6b7280;opacity:.85}
486
494
  .human-label{font-size:11px;font-weight:600;opacity:.7;margin-bottom:2px}
487
495
  .status{padding:6px 14px;font-size:12px;color:#6b7280;background:#f9fafb;border-bottom:1px solid #e5e7eb}
496
+ .err{padding:8px 14px;font-size:12px;color:#b91c1c;background:#fef2f2;border-bottom:1px solid #fecaca}
488
497
  .att-thumb{display:block;max-width:160px;max-height:160px;border-radius:8px;margin-bottom:6px}
489
498
  .att-chip{display:inline-block;font-size:12px;background:rgba(0,0,0,.08);border-radius:6px;padding:2px 8px;margin:0 0 6px}
490
499
  .b.user .att-chip{background:rgba(255,255,255,.25)}
@@ -498,7 +507,7 @@ var OyehelloChatElement = class extends HTMLElement {
498
507
  </style>
499
508
  <div class="wrap">
500
509
  <div class="hd">${escapeHtml(title)}</div>
501
- ${status}
510
+ ${status}${errBanner}
502
511
  <div class="body">${bubbles}${typingIndicator}</div>
503
512
  <form>
504
513
  <input aria-label="message" placeholder="Type a message\u2026" ${disabled}/>
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/errors.ts","../src/transport.ts","../src/client.ts","../src/element.ts","../src/index.ts"],"names":[],"mappings":"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","file":"index.cjs","sourcesContent":["export class ChatApiError extends Error {\n constructor(message: string, readonly status: number, readonly code?: string, readonly meta?: Record<string, unknown>) {\n super(message);\n this.name = 'ChatApiError';\n }\n}\n","import { ChatApiError } from './errors';\nimport type { ChatAttachmentDescriptor, OpenSessionResponse, StreamTicket } from './protocol';\n\nasync function asError(res: Response, fallbackCode?: string): Promise<ChatApiError> {\n let body: { error?: string; code?: string; meta?: Record<string, unknown> } = {};\n try { body = (await res.json()) as { error?: string; code?: string; meta?: Record<string, unknown> }; } catch { /* non-json */ }\n return new ChatApiError(body.error ?? `HTTP ${res.status}`, res.status, body.code ?? fallbackCode, body.meta);\n}\n\nexport async function openSession(opts: { baseUrl: string; apiKey: string; agentId: string; user?: { id?: string }; clientTools?: string[]; fetchImpl: typeof fetch }): Promise<OpenSessionResponse> {\n const body: Record<string, unknown> = { agentId: opts.agentId };\n if (opts.user) body.user = opts.user;\n if (opts.clientTools && opts.clientTools.length > 0) body.clientTools = opts.clientTools;\n const res = await opts.fetchImpl(`${opts.baseUrl}/chat/sessions`, {\n method: 'POST', credentials: 'omit',\n headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${opts.apiKey}` },\n body: JSON.stringify(body),\n });\n if (!res.ok) throw await asError(res);\n return (await res.json()) as OpenSessionResponse;\n}\n\nexport async function postMessage(opts: { baseUrl: string; sessionId: string; sessionToken: string; text: string; attachments?: ChatAttachmentDescriptor[]; fetchImpl: typeof fetch }): Promise<void> {\n const body: Record<string, unknown> = { text: opts.text };\n if (opts.attachments && opts.attachments.length > 0) body.attachments = opts.attachments;\n const res = await opts.fetchImpl(`${opts.baseUrl}/chat/sessions/${opts.sessionId}/messages`, {\n method: 'POST', credentials: 'omit',\n headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${opts.sessionToken}` },\n body: JSON.stringify(body),\n });\n // A 401 here means the 15-min session token expired (no refresh endpoint) — surface a stable code\n // so the client can transparently re-open a session and retry.\n if (!res.ok) throw await asError(res, res.status === 401 ? 'session_expired' : undefined);\n}\n\nexport async function endSession(opts: { baseUrl: string; sessionId: string; sessionToken: string; fetchImpl: typeof fetch }): Promise<void> {\n await opts.fetchImpl(`${opts.baseUrl}/chat/sessions/${opts.sessionId}/end`, {\n method: 'POST', credentials: 'omit',\n headers: { Authorization: `Bearer ${opts.sessionToken}` },\n }).catch(() => {}); // best-effort teardown\n}\n\nexport async function postToolResult(opts: { baseUrl: string; sessionId: string; sessionToken: string; callId: string; ok: boolean; result: unknown; fetchImpl: typeof fetch }): Promise<void> {\n await opts.fetchImpl(`${opts.baseUrl}/chat/sessions/${opts.sessionId}/tool-results`, {\n method: 'POST', credentials: 'omit',\n headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${opts.sessionToken}` },\n body: JSON.stringify({ callId: opts.callId, ok: opts.ok, result: opts.result }),\n }).catch(() => {}); // best-effort; a dropped result times out server-side and the model recovers\n}\n\nexport async function mintStreamTicket(opts: { baseUrl: string; sessionId: string; sessionToken: string; fetchImpl: typeof fetch }): Promise<StreamTicket> {\n const res = await opts.fetchImpl(`${opts.baseUrl}/chat/sessions/${opts.sessionId}/stream-ticket`, {\n method: 'POST', credentials: 'omit',\n headers: { Authorization: `Bearer ${opts.sessionToken}` },\n });\n // A 401 here means the session token is invalid/expired — surface a stable code so the client\n // can distinguish this from a transient failure (mirrors postMessage's 401 mapping).\n if (!res.ok) throw await asError(res, res.status === 401 ? 'session_expired' : undefined);\n return (await res.json()) as StreamTicket;\n}\n\nexport function streamUrl(baseUrl: string, sessionId: string, ticket: string): string {\n return `${baseUrl}/chat/sessions/${sessionId}/stream?ticket=${encodeURIComponent(ticket)}`;\n}\n\n// POST /chat/sessions/:id/attachments — mints a presigned S3 PUT for a visitor upload. Bearer session\n// token auth, mirrors mintStreamTicket's shape/error-mapping exactly.\nexport async function presignAttachment(opts: { baseUrl: string; sessionId: string; sessionToken: string; contentType: string; fetchImpl: typeof fetch }): Promise<{ storageRef: string; uploadUrl: string }> {\n const res = await opts.fetchImpl(`${opts.baseUrl}/chat/sessions/${opts.sessionId}/attachments`, {\n method: 'POST', credentials: 'omit',\n headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${opts.sessionToken}` },\n body: JSON.stringify({ contentType: opts.contentType }),\n });\n // A 401 here means the session token is invalid/expired — surface a stable code so the client\n // can distinguish this from a transient failure (mirrors postMessage's 401 mapping).\n if (!res.ok) throw await asError(res, res.status === 401 ? 'session_expired' : undefined);\n return (await res.json()) as { storageRef: string; uploadUrl: string };\n}\n\n// POST /chat/sessions/:id/attachment-url — mints a presigned S3 GET so an already-uploaded\n// attachment can be read back (e.g. rendering an image thumbnail on reconnect, when no local blob\n// is cached). Bearer session token auth, mirrors presignAttachment's shape/error-mapping exactly.\nexport async function getAttachmentUrl(opts: { baseUrl: string; sessionId: string; sessionToken: string; storageRef: string; fetchImpl: typeof fetch }): Promise<string> {\n const res = await opts.fetchImpl(`${opts.baseUrl}/chat/sessions/${opts.sessionId}/attachment-url`, {\n method: 'POST', credentials: 'omit',\n headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${opts.sessionToken}` },\n body: JSON.stringify({ storageRef: opts.storageRef }),\n });\n // A 401 here means the session token is invalid/expired — surface a stable code so the client\n // can distinguish this from a transient failure (mirrors postMessage's 401 mapping).\n if (!res.ok) throw await asError(res, res.status === 401 ? 'session_expired' : undefined);\n return ((await res.json()) as { url: string }).url;\n}\n\n// Uploads a file directly to the presigned S3 URL. The URL is already absolute and fully signed —\n// NO baseUrl prefix, NO Authorization header (would break the signature), just a bare PUT with the\n// file's own content type (Task 4 dropped SSE from the presign so this needs no extra headers).\nexport async function uploadToPresigned(uploadUrl: string, file: File, fetchImpl: typeof fetch): Promise<void> {\n const res = await fetchImpl(uploadUrl, { method: 'PUT', body: file, headers: { 'Content-Type': file.type } });\n if (!res.ok) throw new ChatApiError(`attachment upload failed with HTTP ${res.status}`, res.status);\n}\n","import { openSession, postMessage, endSession, streamUrl, mintStreamTicket, postToolResult, presignAttachment, uploadToPresigned, getAttachmentUrl } from './transport';\nimport { ChatApiError } from './errors';\nimport type { ChatAttachmentDescriptor, ChatClientOptions, ChatEvent, OpenSessionResponse } from './protocol';\n\nexport interface ChatMessage { id: string; role: 'user' | 'assistant' | 'human'; text: string; streaming: boolean; attachments?: ChatAttachmentDescriptor[]; sources?: { id: string; title: string; snippet: string }[]; turnId?: string }\nexport type ChatClientState = 'idle' | 'opening' | 'ready' | 'ended' | 'error';\n// Handoff status of the session, driven by the backend's `state` SSE event (Phase 7). 'ai' = the\n// AI is answering (default/no handoff), 'awaiting_human' = a handoff was requested and no human\n// has taken over yet, 'human' = a human agent is answering.\nexport type HandoffState = 'ai' | 'awaiting_human' | 'human';\nexport type ChatClientEvent =\n | { type: 'state'; state: ChatClientState }\n | { type: 'messages'; messages: ChatMessage[] }\n | { type: 'error'; error: Error }\n | { type: 'agent'; agent: { id: string; name: string } }\n // Handoff status changed (Phase 7) - the widget uses this to show a status line.\n | { type: 'handoff'; state: HandoffState }\n // A human agent is (or stopped) typing in the console during a handoff (Phase 7 followups). The\n // widget uses this to show a transient \"agent is typing…\" affordance - never a message.\n | { type: 'agentTyping'; active: boolean };\nexport type ChatToolHandler = (args: Record<string, unknown>) => unknown | Promise<unknown>;\nexport interface ChatClient {\n start(): Promise<void>;\n sendMessage(text: string, files?: File[]): Promise<void>;\n end(): Promise<void>;\n getMessages(): ChatMessage[];\n getState(): ChatClientState;\n on(listener: (e: ChatClientEvent) => void): () => void;\n // Register browser-side tool handlers the server may call mid-conversation. Register BEFORE\n // start() — the handler names are sent as `clientTools` on session open so the server knows\n // which tools this session can execute.\n registerTools(handlers: Record<string, ChatToolHandler>): void;\n // Resolves a read-back URL for an already-uploaded attachment (e.g. an image thumbnail with no\n // local blob cached — a reconnect, or an `attachment` SSE echo). Requires start() to have been\n // called (a live session).\n getAttachmentUrl(storageRef: string): Promise<string>;\n}\n\nlet seq = 0;\nconst uid = (p: string) => `${p}_${Date.now().toString(36)}_${(seq++).toString(36)}`;\n\nexport function createChatClient(options: ChatClientOptions): ChatClient {\n const fetchImpl = options.fetch ?? globalThis.fetch;\n const ES = options.eventSource ?? globalThis.EventSource;\n // Mirrors the server's CHAT_ATTACHMENT_MAX_PER_MESSAGE default (apps/api/src/config/env.ts).\n const maxAttachments = options.maxAttachments ?? 4;\n // Mirrors the server's CHAT_ATTACHMENT_MAX_BYTES default (apps/api/src/config/env.ts). UX-only\n // fast pre-check - the server is authoritative (message-time HeadObject size enforcement).\n const maxAttachmentBytes = options.maxAttachmentBytes ?? 10_000_000;\n const listeners = new Set<(e: ChatClientEvent) => void>();\n let state: ChatClientState = 'idle';\n const messages: ChatMessage[] = [];\n let streamingId: string | null = null;\n let session: OpenSessionResponse | null = null;\n let es: EventSource | null = null;\n const seenTurnIds = new Set<string>();\n const seenCallIds = new Set<string>();\n let handoffState: HandoffState = 'ai';\n let reconnectTimer: ReturnType<typeof setTimeout> | null = null;\n let reconnectAttempts = 0;\n let closed = false;\n const toolHandlers = new Map<string, ChatToolHandler>();\n const clearReconnect = () => { if (reconnectTimer) { clearTimeout(reconnectTimer); reconnectTimer = null; } };\n\n const emit = (e: ChatClientEvent) => { for (const l of listeners) l(e); };\n const setState = (s: ChatClientState) => { state = s; emit({ type: 'state', state: s }); };\n const emitMessages = () => emit({ type: 'messages', messages: messages.slice() });\n\n const onEvent = (ev: ChatEvent) => {\n if (ev.type === 'token') {\n let m = streamingId ? messages.find((x) => x.id === streamingId) : undefined;\n if (!m) { m = { id: uid('m'), role: 'assistant', text: '', streaming: true }; messages.push(m); streamingId = m.id; }\n m.text += ev.text; emitMessages();\n } else if (ev.type === 'message') {\n if (seenTurnIds.has(ev.turnId)) {\n // Replay of an already-finalized turn (EventSource reconnect replays the session's\n // event buffer). Discard it, and drop any partial streaming bubble its replayed\n // tokens built up, without emitting a duplicate assistant message.\n if (streamingId) {\n const idx = messages.findIndex((x) => x.id === streamingId);\n if (idx !== -1) messages.splice(idx, 1);\n streamingId = null;\n emitMessages();\n }\n return;\n }\n seenTurnIds.add(ev.turnId);\n const m = streamingId ? messages.find((x) => x.id === streamingId) : undefined;\n if (m) { m.text = ev.text; m.streaming = false; m.turnId = ev.turnId; } else { messages.push({ id: uid('m'), role: 'assistant', text: ev.text, streaming: false, turnId: ev.turnId }); }\n streamingId = null; emitMessages();\n } else if (ev.type === 'citations') {\n // Arrives AFTER `message` (streamingId already cleared) so the target message is located by\n // the turnId stamped above, not by streamingId. Ignore an unknown turnId (reconnect-safe: a\n // stale/duplicate citations replay for a turn we don't have never crashes or creates a bubble).\n const m = messages.find((x) => x.turnId === ev.turnId);\n if (m) { m.sources = ev.sources; emitMessages(); }\n } else if (ev.type === 'error') {\n emit({ type: 'error', error: new Error(ev.message) });\n } else if (ev.type === 'tool_call') {\n if (seenCallIds.has(ev.callId)) return; // replayed on EventSource reconnect — dispatch once\n seenCallIds.add(ev.callId);\n const handler = toolHandlers.get(ev.name);\n void (async () => {\n if (!session) return;\n const base = { baseUrl: options.baseUrl, sessionId: session.sessionId, sessionToken: session.sessionToken, callId: ev.callId, fetchImpl };\n if (!handler) {\n await postToolResult({ ...base, ok: false, result: `no handler registered for ${ev.name}` });\n return;\n }\n try {\n const out = await handler(ev.args);\n await postToolResult({ ...base, ok: true, result: typeof out === 'string' ? out : JSON.stringify(out ?? { ok: true }) });\n } catch (err) {\n await postToolResult({ ...base, ok: false, result: (err as Error).message });\n }\n })();\n } else if (ev.type === 'attachment') {\n // The runtime re-publishes a visitor's message attachments over this event (Phase 5\n // follow-up) so a reconnecting client (buffer replay) or a future second viewer can render\n // them, now that a read-back URL exists (getAttachmentUrl / element.ts's lazy image src).\n // Hardened so it can never double-render on the SENDING client itself, which already rendered\n // these optimistically from its own sendMessage(): if any existing message already carries an\n // attachment with one of these storageRefs, the event is a stale/duplicate echo of something\n // already rendered — ignore it entirely instead of guessing which message to attach to (a\n // \"most recent attachment-less user message\" heuristic misattaches when a second image-first\n // message is sent before the echo of the first one arrives).\n const items = ev.items;\n const alreadyRendered = messages.some((m) => m.attachments?.some((a) => items.some((i) => i.storageRef === a.storageRef)));\n if (alreadyRendered) return;\n const target = [...messages].reverse().find((m) => m.role === 'user' && !m.attachments);\n if (target) target.attachments = items;\n else messages.push({ id: uid('u'), role: 'user', text: '', streaming: false, attachments: items });\n emitMessages();\n } else if (ev.type === 'human_message') {\n // A human agent's reply from the console inbox (Phase 7 handoff) - render as a distinct bubble.\n // Dedup by turnId (shared with the `message` branch's seenTurnIds) - EventSource reconnect\n // replays the session's buffered events, and human_message turnIds (newId('tn')) are distinct\n // from message turnIds, so sharing the Set is safe.\n if (seenTurnIds.has(ev.turnId)) return;\n seenTurnIds.add(ev.turnId);\n messages.push({ id: uid('m'), role: 'human', text: ev.text, streaming: false });\n emitMessages();\n } else if (ev.type === 'visitor_message') {\n // Echo of the visitor's own message, published so the console inbox sees it live. The widget\n // already rendered this optimistically in sendMessage() - ignore the echo entirely.\n } else if (ev.type === 'state') {\n // Handoff status transition (Phase 7): 'ai' | 'awaiting_human' | 'human'. Ignore any other/\n // future state string - forward-compat, no status line for an unrecognized value.\n if (ev.state === 'ai' || ev.state === 'awaiting_human' || ev.state === 'human') {\n handoffState = ev.state;\n emit({ type: 'handoff', state: handoffState });\n }\n } else if (ev.type === 'agent_typing') {\n // Transient signal only - never pushed as a message, never touches dedup/streaming state.\n emit({ type: 'agentTyping', active: !!ev.active });\n }\n // 'done' and any future unknown types are ignored (forward-compat).\n };\n\n // Tickets are single-use and short-lived: a fresh one must be minted for every (re)connect.\n // Native EventSource auto-reconnect would retry the SAME url whose ticket is already consumed\n // (→ 401 forever), so on error we close it ourselves and drive reconnection here instead.\n const openStream = async () => {\n if (!session || closed) return;\n es?.close();\n const { ticket } = await mintStreamTicket({ baseUrl: options.baseUrl, sessionId: session.sessionId, sessionToken: session.sessionToken, fetchImpl });\n if (closed) return;\n es = new ES(streamUrl(options.baseUrl, session.sessionId, ticket));\n es.onopen = () => { reconnectAttempts = 0; };\n es.onmessage = (e: MessageEvent) => { try { onEvent(JSON.parse(e.data) as ChatEvent); } catch { /* ignore malformed */ } };\n es.onerror = () => { es?.close(); es = null; scheduleReconnect(); };\n };\n\n const scheduleReconnect = () => {\n if (closed) return;\n clearReconnect();\n const delay = Math.min(30_000, 500 * 2 ** reconnectAttempts);\n reconnectAttempts += 1;\n reconnectTimer = setTimeout(() => {\n openStream().catch((err) => {\n if (err instanceof ChatApiError && (err as ChatApiError).code === 'session_expired') {\n open().catch((e) => { emit({ type: 'error', error: e as Error }); scheduleReconnect(); });\n } else {\n scheduleReconnect();\n }\n });\n }, delay);\n };\n\n const open = async () => {\n session = await openSession({ baseUrl: options.baseUrl, apiKey: options.apiKey, agentId: options.agentId, user: options.user, clientTools: Array.from(toolHandlers.keys()), fetchImpl });\n emit({ type: 'agent', agent: session.agent });\n await openStream();\n };\n\n // Presign + PUT every file against the CURRENT session. Called from the main sendMessage path and,\n // after a session_expired reopen, from the retry — a storageRef presigned against the old\n // interactionId is rejected cross-session (403 attachment_cross_session) if reused post-reopen.\n const uploadFiles = async (files: File[]): Promise<ChatAttachmentDescriptor[]> => {\n return Promise.all(files.map(async (file): Promise<ChatAttachmentDescriptor> => {\n const { storageRef, uploadUrl } = await presignAttachment({ baseUrl: options.baseUrl, sessionId: session!.sessionId, sessionToken: session!.sessionToken, contentType: file.type, fetchImpl });\n await uploadToPresigned(uploadUrl, file, fetchImpl);\n return { storageRef, contentType: file.type, name: file.name };\n }));\n };\n\n return {\n getMessages: () => messages.slice(),\n getState: () => state,\n on(listener) { listeners.add(listener); return () => listeners.delete(listener); },\n registerTools(handlers) { for (const [name, fn] of Object.entries(handlers)) toolHandlers.set(name, fn); },\n async getAttachmentUrl(storageRef) {\n if (!session) throw new Error('call start() before getAttachmentUrl');\n return getAttachmentUrl({ baseUrl: options.baseUrl, sessionId: session.sessionId, sessionToken: session.sessionToken, storageRef, fetchImpl });\n },\n async start() {\n if (state !== 'idle') return;\n setState('opening');\n try { await open(); setState('ready'); }\n catch (err) { setState('error'); emit({ type: 'error', error: err as Error }); }\n },\n async sendMessage(text, files) {\n if (!session) { emit({ type: 'error', error: new Error('call start() before sendMessage') }); return; }\n const fileList = files ?? [];\n if (fileList.length > maxAttachments) {\n emit({ type: 'error', error: new Error(`too many attachments: max ${maxAttachments} per message`) });\n return;\n }\n const oversized = fileList.find((f) => f.size > maxAttachmentBytes);\n if (oversized) {\n emit({ type: 'error', error: new Error(`attachment too large: ${oversized.name} exceeds ${maxAttachmentBytes} bytes`) });\n return;\n }\n // Upload every file BEFORE posting the message or pushing the optimistic bubble — a failed\n // upload must never leave a broken/partial message in the thread.\n let attachments: ChatAttachmentDescriptor[] = [];\n if (fileList.length > 0) {\n try {\n attachments = await uploadFiles(fileList);\n } catch (err) {\n emit({ type: 'error', error: err as Error });\n return;\n }\n }\n messages.push({ id: uid('u'), role: 'user', text, streaming: false, attachments: attachments.length > 0 ? attachments : undefined }); emitMessages();\n try {\n await postMessage({ baseUrl: options.baseUrl, sessionId: session.sessionId, sessionToken: session.sessionToken, text, attachments, fetchImpl });\n } catch (err) {\n if (err instanceof ChatApiError && err.code === 'session_expired') {\n try {\n await open(); // fresh backend session, same UI thread\n // Re-upload against the NEW session — the old attachments' storageRefs are bound to the\n // stale interactionId and would 403 (attachment_cross_session) if re-posted as-is.\n const freshAttachments = fileList.length ? await uploadFiles(fileList) : [];\n await postMessage({ baseUrl: options.baseUrl, sessionId: session!.sessionId, sessionToken: session!.sessionToken, text, attachments: freshAttachments, fetchImpl });\n } catch (retryErr) {\n emit({ type: 'error', error: retryErr as Error });\n }\n } else { emit({ type: 'error', error: err as Error }); }\n }\n },\n async end() {\n closed = true; clearReconnect();\n if (session) await endSession({ baseUrl: options.baseUrl, sessionId: session.sessionId, sessionToken: session.sessionToken, fetchImpl });\n es?.close(); es = null; setState('ended');\n },\n };\n}\n","import { createChatClient, type ChatClient, type ChatMessage, type ChatClientState, type ChatToolHandler, type HandoffState } from './client';\nimport type { ChatAttachmentDescriptor } from './protocol';\n\nconst HANDOFF_STATUS_TEXT: Record<HandoffState, string | null> = {\n ai: null,\n awaiting_human: 'Connecting you to a person…',\n human: \"You're chatting with a person\",\n};\n\nconst ATTACHMENT_ACCEPT = 'image/*,application/pdf,text/plain,text/csv';\nconst AGENT_TYPING_TEXT = 'The agent is typing…';\n\nexport class OyehelloChatElement extends HTMLElement {\n static observedAttributes = ['api-key', 'agent-id', 'base-url', 'title'];\n private client: ChatClient | null = null;\n private off: (() => void) | null = null;\n private messages: ChatMessage[] = [];\n private state: ChatClientState = 'idle';\n private agentName: string | null = null;\n private handoffState: HandoffState = 'ai';\n // Transient \"agent is typing…\" affordance (Phase 7 followups) - never a message, only rendered\n // while a handoff is active (human/awaiting_human).\n private agentTyping = false;\n // registerTools() may be called before connectedCallback creates the client (e.g. right after\n // document.createElement, before the element is attached). Buffer until the client exists.\n private pendingTools: Record<string, ChatToolHandler> = {};\n // Files picked in the file input, staged until the form submits alongside the text.\n private pendingFiles: File[] = [];\n // Best-effort local thumbnail cache for images THIS widget instance just sent, keyed by filename -\n // an instant blob src, no round-trip needed.\n private imagePreviewCache = new Map<string, string>();\n // Read-back URLs resolved lazily (via client.getAttachmentUrl) for images with no local blob (a\n // reconnect, or an `attachment` SSE echo), keyed by storageRef. Cached across re-renders so the\n // same image isn't re-fetched on every render() call.\n private resolvedUrlCache = new Map<string, string>();\n\n connectedCallback() {\n if (!this.shadowRoot) this.attachShadow({ mode: 'open' });\n const apiKey = this.getAttribute('api-key');\n const agentId = this.getAttribute('agent-id');\n const baseUrl = this.getAttribute('base-url');\n if (!apiKey || !agentId || !baseUrl) { this.renderError('oyehello-chat: api-key, agent-id and base-url are required'); return; }\n this.client = createChatClient({ apiKey, agentId, baseUrl });\n if (Object.keys(this.pendingTools).length > 0) { this.client.registerTools(this.pendingTools); this.pendingTools = {}; }\n this.off = this.client.on((e) => {\n if (e.type === 'messages') this.messages = e.messages;\n else if (e.type === 'state') this.state = e.state;\n else if (e.type === 'agent') this.agentName = e.agent.name;\n else if (e.type === 'handoff') this.handoffState = e.state;\n else if (e.type === 'agentTyping') this.agentTyping = e.active;\n this.render();\n });\n this.render();\n void this.client.start();\n }\n disconnectedCallback() {\n this.off?.(); void this.client?.end();\n for (const url of this.imagePreviewCache.values()) { if (typeof URL.revokeObjectURL === 'function') URL.revokeObjectURL(url); }\n this.imagePreviewCache.clear();\n }\n\n registerTools(handlers: Record<string, ChatToolHandler>) {\n if (this.client) this.client.registerTools(handlers);\n else Object.assign(this.pendingTools, handlers);\n }\n\n private send(text: string, files: File[]) {\n if (!text.trim()) return;\n for (const f of files) {\n if (f.type.startsWith('image/') && typeof URL.createObjectURL === 'function' && !this.imagePreviewCache.has(f.name)) {\n this.imagePreviewCache.set(f.name, URL.createObjectURL(f));\n }\n }\n void this.client?.sendMessage(text, files.length > 0 ? files : undefined);\n }\n private renderError(msg: string) {\n if (!this.shadowRoot) this.attachShadow({ mode: 'open' });\n this.shadowRoot!.innerHTML = `<div style=\"color:#b91c1c;font:13px system-ui;padding:12px\">${escapeHtml(msg)}</div>`;\n }\n private renderAttachment(a: ChatAttachmentDescriptor): string {\n if (a.contentType.startsWith('image/')) {\n // Instant src when a local blob (just sent by this widget instance) or a previously-resolved\n // read-back URL is cached. Otherwise render the placeholder with a data-oc-ref marker and no\n // src attribute (an empty src=\"\" would make the browser (re)request the current page) -\n // hydrateAttachmentImages() resolves it lazily right after this markup is attached to the DOM.\n const cached = (a.name ? this.imagePreviewCache.get(a.name) : undefined) ?? this.resolvedUrlCache.get(a.storageRef);\n const srcAttr = cached ? ` src=\"${cached}\"` : '';\n return `<img class=\"att-thumb\" data-oc-ref=\"${escapeHtml(a.storageRef)}\"${srcAttr} alt=\"${escapeHtml(a.name ?? 'image')}\"/>`;\n }\n return `<div class=\"att-chip\">📎 ${escapeHtml(a.name ?? a.contentType)}</div>`;\n }\n private renderSource(s: { id: string; title: string; snippet: string }): string {\n return `<div class=\"src-chip\" title=\"${escapeHtml(s.snippet)}\">${escapeHtml(s.title)}</div>`;\n }\n\n // After render() attaches the markup, resolve a read-back URL (via the client) for every image\n // placeholder that has no src yet - a local blob or a previously-resolved URL already set one, so\n // those are left untouched (no redundant network call).\n private hydrateAttachmentImages() {\n if (!this.client) return;\n const imgs = this.shadowRoot!.querySelectorAll<HTMLImageElement>('img.att-thumb[data-oc-ref]');\n imgs.forEach((img) => {\n if (img.hasAttribute('src')) return;\n const ref = img.getAttribute('data-oc-ref');\n if (!ref) return;\n void this.client!.getAttachmentUrl(ref)\n .then((url) => { this.resolvedUrlCache.set(ref, url); img.src = url; })\n .catch(() => { /* leave unresolved - no thumbnail is an acceptable degrade, not fatal */ });\n });\n }\n\n private render() {\n const title = this.getAttribute('title') ?? this.agentName ?? 'Chat';\n const bubbles = this.messages.map((m) => {\n const atts = (m.attachments ?? []).map((a) => this.renderAttachment(a)).join('');\n const label = m.role === 'human' ? '<div class=\"human-label\">Support</div>' : '';\n const bubble = `<div class=\"b ${m.role}\">${label}${atts}${m.text ? escapeHtml(m.text) : ''}${m.streaming ? '…' : ''}</div>`;\n const sources = m.sources && m.sources.length > 0 ? `<div class=\"src-row\">${m.sources.map((s) => this.renderSource(s)).join('')}</div>` : '';\n return bubble + sources;\n }).join('');\n const statusText = HANDOFF_STATUS_TEXT[this.handoffState];\n const status = statusText ? `<div class=\"status\">${escapeHtml(statusText)}</div>` : '';\n const showTyping = this.agentTyping && (this.handoffState === 'human' || this.handoffState === 'awaiting_human');\n const typingIndicator = showTyping ? `<div class=\"b assistant typing\">${escapeHtml(AGENT_TYPING_TEXT)}</div>` : '';\n const disabled = this.state !== 'ready' ? 'disabled' : '';\n // Rebuilding innerHTML replaces the input node, which would otherwise drop the user's\n // in-progress text + caret on every streamed token. Capture and restore across the rebuild.\n const prevInput = this.shadowRoot!.querySelector<HTMLInputElement>('input[aria-label=\"message\"]');\n const prevValue = prevInput?.value ?? '';\n const prevSelectionStart = prevInput?.selectionStart ?? null;\n const prevSelectionEnd = prevInput?.selectionEnd ?? null;\n const hadFocus = !!prevInput && this.shadowRoot!.activeElement === prevInput;\n this.shadowRoot!.innerHTML = `\n <style>\n :host{display:block;height:100%;min-height:320px;font-family:system-ui,sans-serif;--oc-accent:#2563eb}\n .wrap{display:flex;flex-direction:column;height:100%;border:1px solid #e5e7eb;border-radius:12px;overflow:hidden}\n .hd{padding:10px 14px;border-bottom:1px solid #e5e7eb;font-weight:600}\n .body{flex:1;overflow-y:auto;padding:12px;display:flex;flex-direction:column;gap:8px}\n .b{max-width:80%;padding:8px 12px;border-radius:12px;white-space:pre-wrap;word-break:break-word}\n .b.user{align-self:flex-end;background:var(--oc-accent);color:#fff}\n .b.assistant{align-self:flex-start;background:#f3f4f6;color:#111}\n .b.human{align-self:flex-start;background:#dbeafe;color:#111}\n .b.typing{font-style:italic;color:#6b7280;opacity:.85}\n .human-label{font-size:11px;font-weight:600;opacity:.7;margin-bottom:2px}\n .status{padding:6px 14px;font-size:12px;color:#6b7280;background:#f9fafb;border-bottom:1px solid #e5e7eb}\n .att-thumb{display:block;max-width:160px;max-height:160px;border-radius:8px;margin-bottom:6px}\n .att-chip{display:inline-block;font-size:12px;background:rgba(0,0,0,.08);border-radius:6px;padding:2px 8px;margin:0 0 6px}\n .b.user .att-chip{background:rgba(255,255,255,.25)}\n .src-row{align-self:flex-start;display:flex;flex-wrap:wrap;gap:6px;max-width:80%}\n .src-chip{display:inline-block;font-size:11px;background:rgba(0,0,0,.06);color:#374151;border-radius:6px;padding:2px 8px;cursor:default}\n form{display:flex;gap:8px;padding:10px;border-top:1px solid #e5e7eb;align-items:center}\n input[aria-label=\"message\"]{flex:1;padding:8px 10px;border-radius:8px;border:1px solid #d1d5db;font:inherit}\n input[type=\"file\"]{max-width:120px;font-size:12px}\n button{padding:8px 14px;border-radius:8px;border:none;background:var(--oc-accent);color:#fff;font-weight:600;cursor:pointer}\n button:disabled,input:disabled{opacity:.6;cursor:not-allowed}\n </style>\n <div class=\"wrap\">\n <div class=\"hd\">${escapeHtml(title)}</div>\n ${status}\n <div class=\"body\">${bubbles}${typingIndicator}</div>\n <form>\n <input aria-label=\"message\" placeholder=\"Type a message…\" ${disabled}/>\n <input type=\"file\" accept=\"${ATTACHMENT_ACCEPT}\" multiple ${disabled}/>\n <button type=\"submit\" ${disabled}>Send</button>\n </form>\n </div>`;\n const form = this.shadowRoot!.querySelector('form')!;\n const input = this.shadowRoot!.querySelector<HTMLInputElement>('input[aria-label=\"message\"]')!;\n const fileInput = this.shadowRoot!.querySelector<HTMLInputElement>('input[type=\"file\"]')!;\n fileInput.addEventListener('change', () => { this.pendingFiles = fileInput.files ? Array.from(fileInput.files) : []; });\n form.addEventListener('submit', (e) => {\n e.preventDefault();\n const files = this.pendingFiles;\n this.pendingFiles = [];\n this.send(input.value, files);\n input.value = '';\n });\n if (prevValue) {\n input.value = prevValue;\n if (prevSelectionStart !== null && prevSelectionEnd !== null) input.setSelectionRange(prevSelectionStart, prevSelectionEnd);\n }\n if (hadFocus) input.focus();\n const body = this.shadowRoot!.querySelector('.body')!;\n body.scrollTop = body.scrollHeight;\n this.hydrateAttachmentImages();\n }\n}\nfunction escapeHtml(s: string) { return s.replace(/[&<>\"]/g, (c) => ({ '&': '&amp;', '<': '&lt;', '>': '&gt;', '\"': '&quot;' }[c]!)); }\n","export { ChatApiError } from './errors';\nexport type { ChatEvent, OpenSessionResponse, ChatClientOptions, ChatAttachmentDescriptor } from './protocol';\nexport { createChatClient } from './client';\nexport type { ChatClient, ChatMessage, ChatClientState, ChatClientEvent, ChatToolHandler } from './client';\nexport { OyehelloChatElement } from './element';\n\nimport { OyehelloChatElement } from './element';\n// Side effect: registering the element is why the package is sideEffects:true.\nif (typeof customElements !== 'undefined' && !customElements.get('oyehello-chat')) {\n customElements.define('oyehello-chat', OyehelloChatElement);\n}\n"]}
1
+ {"version":3,"sources":["../src/errors.ts","../src/transport.ts","../src/client.ts","../src/element.ts","../src/index.ts"],"names":[],"mappings":"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","file":"index.cjs","sourcesContent":["export class ChatApiError extends Error {\n constructor(message: string, readonly status: number, readonly code?: string, readonly meta?: Record<string, unknown>) {\n super(message);\n this.name = 'ChatApiError';\n }\n}\n","import { ChatApiError } from './errors';\nimport type { ChatAttachmentDescriptor, OpenSessionResponse, StreamTicket } from './protocol';\n\nasync function asError(res: Response, fallbackCode?: string): Promise<ChatApiError> {\n let body: { error?: string; code?: string; meta?: Record<string, unknown> } = {};\n try { body = (await res.json()) as { error?: string; code?: string; meta?: Record<string, unknown> }; } catch { /* non-json */ }\n return new ChatApiError(body.error ?? `HTTP ${res.status}`, res.status, body.code ?? fallbackCode, body.meta);\n}\n\nexport async function openSession(opts: { baseUrl: string; apiKey: string; agentId: string; user?: { id?: string }; clientTools?: string[]; fetchImpl: typeof fetch }): Promise<OpenSessionResponse> {\n const body: Record<string, unknown> = { agentId: opts.agentId };\n if (opts.user) body.user = opts.user;\n if (opts.clientTools && opts.clientTools.length > 0) body.clientTools = opts.clientTools;\n const res = await opts.fetchImpl(`${opts.baseUrl}/chat/sessions`, {\n method: 'POST', credentials: 'omit',\n headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${opts.apiKey}` },\n body: JSON.stringify(body),\n });\n if (!res.ok) throw await asError(res);\n return (await res.json()) as OpenSessionResponse;\n}\n\nexport async function postMessage(opts: { baseUrl: string; sessionId: string; sessionToken: string; text: string; attachments?: ChatAttachmentDescriptor[]; fetchImpl: typeof fetch }): Promise<void> {\n const body: Record<string, unknown> = { text: opts.text };\n if (opts.attachments && opts.attachments.length > 0) body.attachments = opts.attachments;\n const res = await opts.fetchImpl(`${opts.baseUrl}/chat/sessions/${opts.sessionId}/messages`, {\n method: 'POST', credentials: 'omit',\n headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${opts.sessionToken}` },\n body: JSON.stringify(body),\n });\n // A 401 here means the 15-min session token expired (no refresh endpoint) — surface a stable code\n // so the client can transparently re-open a session and retry.\n if (!res.ok) throw await asError(res, res.status === 401 ? 'session_expired' : undefined);\n}\n\nexport async function endSession(opts: { baseUrl: string; sessionId: string; sessionToken: string; fetchImpl: typeof fetch }): Promise<void> {\n await opts.fetchImpl(`${opts.baseUrl}/chat/sessions/${opts.sessionId}/end`, {\n method: 'POST', credentials: 'omit',\n headers: { Authorization: `Bearer ${opts.sessionToken}` },\n }).catch(() => {}); // best-effort teardown\n}\n\nexport async function postToolResult(opts: { baseUrl: string; sessionId: string; sessionToken: string; callId: string; ok: boolean; result: unknown; fetchImpl: typeof fetch }): Promise<void> {\n await opts.fetchImpl(`${opts.baseUrl}/chat/sessions/${opts.sessionId}/tool-results`, {\n method: 'POST', credentials: 'omit',\n headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${opts.sessionToken}` },\n body: JSON.stringify({ callId: opts.callId, ok: opts.ok, result: opts.result }),\n }).catch(() => {}); // best-effort; a dropped result times out server-side and the model recovers\n}\n\nexport async function mintStreamTicket(opts: { baseUrl: string; sessionId: string; sessionToken: string; fetchImpl: typeof fetch }): Promise<StreamTicket> {\n const res = await opts.fetchImpl(`${opts.baseUrl}/chat/sessions/${opts.sessionId}/stream-ticket`, {\n method: 'POST', credentials: 'omit',\n headers: { Authorization: `Bearer ${opts.sessionToken}` },\n });\n // A 401 here means the session token is invalid/expired — surface a stable code so the client\n // can distinguish this from a transient failure (mirrors postMessage's 401 mapping).\n if (!res.ok) throw await asError(res, res.status === 401 ? 'session_expired' : undefined);\n return (await res.json()) as StreamTicket;\n}\n\nexport function streamUrl(baseUrl: string, sessionId: string, ticket: string): string {\n return `${baseUrl}/chat/sessions/${sessionId}/stream?ticket=${encodeURIComponent(ticket)}`;\n}\n\n// POST /chat/sessions/:id/attachments — mints a presigned S3 PUT for a visitor upload. Bearer session\n// token auth, mirrors mintStreamTicket's shape/error-mapping exactly.\nexport async function presignAttachment(opts: { baseUrl: string; sessionId: string; sessionToken: string; contentType: string; fetchImpl: typeof fetch }): Promise<{ storageRef: string; uploadUrl: string }> {\n const res = await opts.fetchImpl(`${opts.baseUrl}/chat/sessions/${opts.sessionId}/attachments`, {\n method: 'POST', credentials: 'omit',\n headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${opts.sessionToken}` },\n body: JSON.stringify({ contentType: opts.contentType }),\n });\n // A 401 here means the session token is invalid/expired — surface a stable code so the client\n // can distinguish this from a transient failure (mirrors postMessage's 401 mapping).\n if (!res.ok) throw await asError(res, res.status === 401 ? 'session_expired' : undefined);\n return (await res.json()) as { storageRef: string; uploadUrl: string };\n}\n\n// POST /chat/sessions/:id/attachment-url — mints a presigned S3 GET so an already-uploaded\n// attachment can be read back (e.g. rendering an image thumbnail on reconnect, when no local blob\n// is cached). Bearer session token auth, mirrors presignAttachment's shape/error-mapping exactly.\nexport async function getAttachmentUrl(opts: { baseUrl: string; sessionId: string; sessionToken: string; storageRef: string; fetchImpl: typeof fetch }): Promise<string> {\n const res = await opts.fetchImpl(`${opts.baseUrl}/chat/sessions/${opts.sessionId}/attachment-url`, {\n method: 'POST', credentials: 'omit',\n headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${opts.sessionToken}` },\n body: JSON.stringify({ storageRef: opts.storageRef }),\n });\n // A 401 here means the session token is invalid/expired — surface a stable code so the client\n // can distinguish this from a transient failure (mirrors postMessage's 401 mapping).\n if (!res.ok) throw await asError(res, res.status === 401 ? 'session_expired' : undefined);\n return ((await res.json()) as { url: string }).url;\n}\n\n// Uploads a file directly to the presigned S3 URL. The URL is already absolute and fully signed —\n// NO baseUrl prefix, NO Authorization header (would break the signature), just a bare PUT with the\n// file's own content type (Task 4 dropped SSE from the presign so this needs no extra headers).\nexport async function uploadToPresigned(uploadUrl: string, file: File, fetchImpl: typeof fetch): Promise<void> {\n const res = await fetchImpl(uploadUrl, { method: 'PUT', body: file, headers: { 'Content-Type': file.type } });\n if (!res.ok) throw new ChatApiError(`attachment upload failed with HTTP ${res.status}`, res.status);\n}\n","import { openSession, postMessage, endSession, streamUrl, mintStreamTicket, postToolResult, presignAttachment, uploadToPresigned, getAttachmentUrl } from './transport';\nimport { ChatApiError } from './errors';\nimport type { ChatAttachmentDescriptor, ChatClientOptions, ChatEvent, OpenSessionResponse } from './protocol';\n\nexport interface ChatMessage { id: string; role: 'user' | 'assistant' | 'human'; text: string; streaming: boolean; attachments?: ChatAttachmentDescriptor[]; sources?: { id: string; title: string; snippet: string }[]; turnId?: string }\nexport type ChatClientState = 'idle' | 'opening' | 'ready' | 'ended' | 'error';\n// Handoff status of the session, driven by the backend's `state` SSE event (Phase 7). 'ai' = the\n// AI is answering (default/no handoff), 'awaiting_human' = a handoff was requested and no human\n// has taken over yet, 'human' = a human agent is answering.\nexport type HandoffState = 'ai' | 'awaiting_human' | 'human';\nexport type ChatClientEvent =\n | { type: 'state'; state: ChatClientState }\n | { type: 'messages'; messages: ChatMessage[] }\n | { type: 'error'; error: Error }\n | { type: 'agent'; agent: { id: string; name: string } }\n // Handoff status changed (Phase 7) - the widget uses this to show a status line.\n | { type: 'handoff'; state: HandoffState }\n // A human agent is (or stopped) typing in the console during a handoff (Phase 7 followups). The\n // widget uses this to show a transient \"agent is typing…\" affordance - never a message.\n | { type: 'agentTyping'; active: boolean };\nexport type ChatToolHandler = (args: Record<string, unknown>) => unknown | Promise<unknown>;\nexport interface ChatClient {\n start(): Promise<void>;\n sendMessage(text: string, files?: File[]): Promise<void>;\n end(): Promise<void>;\n getMessages(): ChatMessage[];\n getState(): ChatClientState;\n on(listener: (e: ChatClientEvent) => void): () => void;\n // Register browser-side tool handlers the server may call mid-conversation. Register BEFORE\n // start() — the handler names are sent as `clientTools` on session open so the server knows\n // which tools this session can execute.\n registerTools(handlers: Record<string, ChatToolHandler>): void;\n // Resolves a read-back URL for an already-uploaded attachment (e.g. an image thumbnail with no\n // local blob cached — a reconnect, or an `attachment` SSE echo). Requires start() to have been\n // called (a live session).\n getAttachmentUrl(storageRef: string): Promise<string>;\n}\n\nlet seq = 0;\nconst uid = (p: string) => `${p}_${Date.now().toString(36)}_${(seq++).toString(36)}`;\n\nexport function createChatClient(options: ChatClientOptions): ChatClient {\n // Native fetch must be invoked with `this === window`; the transport calls this as\n // `opts.fetchImpl(...)`, so a bare `globalThis.fetch` reference throws \"Illegal invocation\".\n // Bind the default to the global. A caller-supplied fetch is used as-is.\n const fetchImpl = options.fetch ?? globalThis.fetch.bind(globalThis);\n const ES = options.eventSource ?? globalThis.EventSource;\n // Mirrors the server's CHAT_ATTACHMENT_MAX_PER_MESSAGE default (apps/api/src/config/env.ts).\n const maxAttachments = options.maxAttachments ?? 4;\n // Mirrors the server's CHAT_ATTACHMENT_MAX_BYTES default (apps/api/src/config/env.ts). UX-only\n // fast pre-check - the server is authoritative (message-time HeadObject size enforcement).\n const maxAttachmentBytes = options.maxAttachmentBytes ?? 10_000_000;\n const listeners = new Set<(e: ChatClientEvent) => void>();\n let state: ChatClientState = 'idle';\n const messages: ChatMessage[] = [];\n let streamingId: string | null = null;\n let session: OpenSessionResponse | null = null;\n let es: EventSource | null = null;\n const seenTurnIds = new Set<string>();\n const seenCallIds = new Set<string>();\n let handoffState: HandoffState = 'ai';\n let reconnectTimer: ReturnType<typeof setTimeout> | null = null;\n let reconnectAttempts = 0;\n let closed = false;\n const toolHandlers = new Map<string, ChatToolHandler>();\n const clearReconnect = () => { if (reconnectTimer) { clearTimeout(reconnectTimer); reconnectTimer = null; } };\n\n const emit = (e: ChatClientEvent) => { for (const l of listeners) l(e); };\n const setState = (s: ChatClientState) => { state = s; emit({ type: 'state', state: s }); };\n const emitMessages = () => emit({ type: 'messages', messages: messages.slice() });\n\n const onEvent = (ev: ChatEvent) => {\n if (ev.type === 'token') {\n let m = streamingId ? messages.find((x) => x.id === streamingId) : undefined;\n if (!m) { m = { id: uid('m'), role: 'assistant', text: '', streaming: true }; messages.push(m); streamingId = m.id; }\n m.text += ev.text; emitMessages();\n } else if (ev.type === 'message') {\n if (seenTurnIds.has(ev.turnId)) {\n // Replay of an already-finalized turn (EventSource reconnect replays the session's\n // event buffer). Discard it, and drop any partial streaming bubble its replayed\n // tokens built up, without emitting a duplicate assistant message.\n if (streamingId) {\n const idx = messages.findIndex((x) => x.id === streamingId);\n if (idx !== -1) messages.splice(idx, 1);\n streamingId = null;\n emitMessages();\n }\n return;\n }\n seenTurnIds.add(ev.turnId);\n const m = streamingId ? messages.find((x) => x.id === streamingId) : undefined;\n if (m) { m.text = ev.text; m.streaming = false; m.turnId = ev.turnId; } else { messages.push({ id: uid('m'), role: 'assistant', text: ev.text, streaming: false, turnId: ev.turnId }); }\n streamingId = null; emitMessages();\n } else if (ev.type === 'citations') {\n // Arrives AFTER `message` (streamingId already cleared) so the target message is located by\n // the turnId stamped above, not by streamingId. Ignore an unknown turnId (reconnect-safe: a\n // stale/duplicate citations replay for a turn we don't have never crashes or creates a bubble).\n const m = messages.find((x) => x.turnId === ev.turnId);\n if (m) { m.sources = ev.sources; emitMessages(); }\n } else if (ev.type === 'error') {\n emit({ type: 'error', error: new Error(ev.message) });\n } else if (ev.type === 'tool_call') {\n if (seenCallIds.has(ev.callId)) return; // replayed on EventSource reconnect — dispatch once\n seenCallIds.add(ev.callId);\n const handler = toolHandlers.get(ev.name);\n void (async () => {\n if (!session) return;\n const base = { baseUrl: options.baseUrl, sessionId: session.sessionId, sessionToken: session.sessionToken, callId: ev.callId, fetchImpl };\n if (!handler) {\n await postToolResult({ ...base, ok: false, result: `no handler registered for ${ev.name}` });\n return;\n }\n try {\n const out = await handler(ev.args);\n await postToolResult({ ...base, ok: true, result: typeof out === 'string' ? out : JSON.stringify(out ?? { ok: true }) });\n } catch (err) {\n await postToolResult({ ...base, ok: false, result: (err as Error).message });\n }\n })();\n } else if (ev.type === 'attachment') {\n // The runtime re-publishes a visitor's message attachments over this event (Phase 5\n // follow-up) so a reconnecting client (buffer replay) or a future second viewer can render\n // them, now that a read-back URL exists (getAttachmentUrl / element.ts's lazy image src).\n // Hardened so it can never double-render on the SENDING client itself, which already rendered\n // these optimistically from its own sendMessage(): if any existing message already carries an\n // attachment with one of these storageRefs, the event is a stale/duplicate echo of something\n // already rendered — ignore it entirely instead of guessing which message to attach to (a\n // \"most recent attachment-less user message\" heuristic misattaches when a second image-first\n // message is sent before the echo of the first one arrives).\n const items = ev.items;\n const alreadyRendered = messages.some((m) => m.attachments?.some((a) => items.some((i) => i.storageRef === a.storageRef)));\n if (alreadyRendered) return;\n const target = [...messages].reverse().find((m) => m.role === 'user' && !m.attachments);\n if (target) target.attachments = items;\n else messages.push({ id: uid('u'), role: 'user', text: '', streaming: false, attachments: items });\n emitMessages();\n } else if (ev.type === 'human_message') {\n // A human agent's reply from the console inbox (Phase 7 handoff) - render as a distinct bubble.\n // Dedup by turnId (shared with the `message` branch's seenTurnIds) - EventSource reconnect\n // replays the session's buffered events, and human_message turnIds (newId('tn')) are distinct\n // from message turnIds, so sharing the Set is safe.\n if (seenTurnIds.has(ev.turnId)) return;\n seenTurnIds.add(ev.turnId);\n messages.push({ id: uid('m'), role: 'human', text: ev.text, streaming: false });\n emitMessages();\n } else if (ev.type === 'visitor_message') {\n // Echo of the visitor's own message, published so the console inbox sees it live. The widget\n // already rendered this optimistically in sendMessage() - ignore the echo entirely.\n } else if (ev.type === 'state') {\n // Handoff status transition (Phase 7): 'ai' | 'awaiting_human' | 'human'. Ignore any other/\n // future state string - forward-compat, no status line for an unrecognized value.\n if (ev.state === 'ai' || ev.state === 'awaiting_human' || ev.state === 'human') {\n handoffState = ev.state;\n emit({ type: 'handoff', state: handoffState });\n }\n } else if (ev.type === 'agent_typing') {\n // Transient signal only - never pushed as a message, never touches dedup/streaming state.\n emit({ type: 'agentTyping', active: !!ev.active });\n }\n // 'done' and any future unknown types are ignored (forward-compat).\n };\n\n // Tickets are single-use and short-lived: a fresh one must be minted for every (re)connect.\n // Native EventSource auto-reconnect would retry the SAME url whose ticket is already consumed\n // (→ 401 forever), so on error we close it ourselves and drive reconnection here instead.\n const openStream = async () => {\n if (!session || closed) return;\n es?.close();\n const { ticket } = await mintStreamTicket({ baseUrl: options.baseUrl, sessionId: session.sessionId, sessionToken: session.sessionToken, fetchImpl });\n if (closed) return;\n es = new ES(streamUrl(options.baseUrl, session.sessionId, ticket));\n es.onopen = () => { reconnectAttempts = 0; };\n es.onmessage = (e: MessageEvent) => { try { onEvent(JSON.parse(e.data) as ChatEvent); } catch { /* ignore malformed */ } };\n es.onerror = () => { es?.close(); es = null; scheduleReconnect(); };\n };\n\n const scheduleReconnect = () => {\n if (closed) return;\n clearReconnect();\n const delay = Math.min(30_000, 500 * 2 ** reconnectAttempts);\n reconnectAttempts += 1;\n reconnectTimer = setTimeout(() => {\n openStream().catch((err) => {\n if (err instanceof ChatApiError && (err as ChatApiError).code === 'session_expired') {\n open().catch((e) => { emit({ type: 'error', error: e as Error }); scheduleReconnect(); });\n } else {\n scheduleReconnect();\n }\n });\n }, delay);\n };\n\n const open = async () => {\n session = await openSession({ baseUrl: options.baseUrl, apiKey: options.apiKey, agentId: options.agentId, user: options.user, clientTools: Array.from(toolHandlers.keys()), fetchImpl });\n emit({ type: 'agent', agent: session.agent });\n await openStream();\n };\n\n // Presign + PUT every file against the CURRENT session. Called from the main sendMessage path and,\n // after a session_expired reopen, from the retry — a storageRef presigned against the old\n // interactionId is rejected cross-session (403 attachment_cross_session) if reused post-reopen.\n const uploadFiles = async (files: File[]): Promise<ChatAttachmentDescriptor[]> => {\n return Promise.all(files.map(async (file): Promise<ChatAttachmentDescriptor> => {\n const { storageRef, uploadUrl } = await presignAttachment({ baseUrl: options.baseUrl, sessionId: session!.sessionId, sessionToken: session!.sessionToken, contentType: file.type, fetchImpl });\n await uploadToPresigned(uploadUrl, file, fetchImpl);\n return { storageRef, contentType: file.type, name: file.name };\n }));\n };\n\n return {\n getMessages: () => messages.slice(),\n getState: () => state,\n on(listener) { listeners.add(listener); return () => listeners.delete(listener); },\n registerTools(handlers) { for (const [name, fn] of Object.entries(handlers)) toolHandlers.set(name, fn); },\n async getAttachmentUrl(storageRef) {\n if (!session) throw new Error('call start() before getAttachmentUrl');\n return getAttachmentUrl({ baseUrl: options.baseUrl, sessionId: session.sessionId, sessionToken: session.sessionToken, storageRef, fetchImpl });\n },\n async start() {\n if (state !== 'idle') return;\n setState('opening');\n try { await open(); setState('ready'); }\n catch (err) { setState('error'); emit({ type: 'error', error: err as Error }); }\n },\n async sendMessage(text, files) {\n if (!session) { emit({ type: 'error', error: new Error('call start() before sendMessage') }); return; }\n const fileList = files ?? [];\n if (fileList.length > maxAttachments) {\n emit({ type: 'error', error: new Error(`too many attachments: max ${maxAttachments} per message`) });\n return;\n }\n const oversized = fileList.find((f) => f.size > maxAttachmentBytes);\n if (oversized) {\n emit({ type: 'error', error: new Error(`attachment too large: ${oversized.name} exceeds ${maxAttachmentBytes} bytes`) });\n return;\n }\n // Upload every file BEFORE posting the message or pushing the optimistic bubble — a failed\n // upload must never leave a broken/partial message in the thread.\n let attachments: ChatAttachmentDescriptor[] = [];\n if (fileList.length > 0) {\n try {\n attachments = await uploadFiles(fileList);\n } catch (err) {\n emit({ type: 'error', error: err as Error });\n return;\n }\n }\n messages.push({ id: uid('u'), role: 'user', text, streaming: false, attachments: attachments.length > 0 ? attachments : undefined }); emitMessages();\n try {\n await postMessage({ baseUrl: options.baseUrl, sessionId: session.sessionId, sessionToken: session.sessionToken, text, attachments, fetchImpl });\n } catch (err) {\n if (err instanceof ChatApiError && err.code === 'session_expired') {\n try {\n await open(); // fresh backend session, same UI thread\n // Re-upload against the NEW session — the old attachments' storageRefs are bound to the\n // stale interactionId and would 403 (attachment_cross_session) if re-posted as-is.\n const freshAttachments = fileList.length ? await uploadFiles(fileList) : [];\n await postMessage({ baseUrl: options.baseUrl, sessionId: session!.sessionId, sessionToken: session!.sessionToken, text, attachments: freshAttachments, fetchImpl });\n } catch (retryErr) {\n emit({ type: 'error', error: retryErr as Error });\n }\n } else { emit({ type: 'error', error: err as Error }); }\n }\n },\n async end() {\n closed = true; clearReconnect();\n if (session) await endSession({ baseUrl: options.baseUrl, sessionId: session.sessionId, sessionToken: session.sessionToken, fetchImpl });\n es?.close(); es = null; setState('ended');\n },\n };\n}\n","import { createChatClient, type ChatClient, type ChatMessage, type ChatClientState, type ChatToolHandler, type HandoffState } from './client';\nimport type { ChatAttachmentDescriptor } from './protocol';\n\nconst HANDOFF_STATUS_TEXT: Record<HandoffState, string | null> = {\n ai: null,\n awaiting_human: 'Connecting you to a person…',\n human: \"You're chatting with a person\",\n};\n\nconst ATTACHMENT_ACCEPT = 'image/*,application/pdf,text/plain,text/csv';\nconst AGENT_TYPING_TEXT = 'The agent is typing…';\n\nexport class OyehelloChatElement extends HTMLElement {\n static observedAttributes = ['api-key', 'agent-id', 'base-url', 'title'];\n private client: ChatClient | null = null;\n private off: (() => void) | null = null;\n private messages: ChatMessage[] = [];\n private state: ChatClientState = 'idle';\n private agentName: string | null = null;\n private handoffState: HandoffState = 'ai';\n // Transient \"agent is typing…\" affordance (Phase 7 followups) - never a message, only rendered\n // while a handoff is active (human/awaiting_human).\n private agentTyping = false;\n // Last connection/runtime error message (client emits an 'error' event on a failed start() or\n // send). Surfaced as a visible banner so a disabled composer always shows WHY, instead of sitting\n // dead. Cleared when the client reaches a healthy state again.\n private lastError: string | null = null;\n // registerTools() may be called before connectedCallback creates the client (e.g. right after\n // document.createElement, before the element is attached). Buffer until the client exists.\n private pendingTools: Record<string, ChatToolHandler> = {};\n // Files picked in the file input, staged until the form submits alongside the text.\n private pendingFiles: File[] = [];\n // Best-effort local thumbnail cache for images THIS widget instance just sent, keyed by filename -\n // an instant blob src, no round-trip needed.\n private imagePreviewCache = new Map<string, string>();\n // Read-back URLs resolved lazily (via client.getAttachmentUrl) for images with no local blob (a\n // reconnect, or an `attachment` SSE echo), keyed by storageRef. Cached across re-renders so the\n // same image isn't re-fetched on every render() call.\n private resolvedUrlCache = new Map<string, string>();\n\n connectedCallback() {\n if (!this.shadowRoot) this.attachShadow({ mode: 'open' });\n const apiKey = this.getAttribute('api-key');\n const agentId = this.getAttribute('agent-id');\n const baseUrl = this.getAttribute('base-url');\n if (!apiKey || !agentId || !baseUrl) { this.renderError('oyehello-chat: api-key, agent-id and base-url are required'); return; }\n this.client = createChatClient({ apiKey, agentId, baseUrl });\n if (Object.keys(this.pendingTools).length > 0) { this.client.registerTools(this.pendingTools); this.pendingTools = {}; }\n this.off = this.client.on((e) => {\n if (e.type === 'messages') this.messages = e.messages;\n else if (e.type === 'state') { this.state = e.state; if (e.state === 'ready' || e.state === 'opening') this.lastError = null; }\n else if (e.type === 'agent') this.agentName = e.agent.name;\n else if (e.type === 'handoff') this.handoffState = e.state;\n else if (e.type === 'agentTyping') this.agentTyping = e.active;\n else if (e.type === 'error') this.lastError = e.error.message;\n this.render();\n });\n this.render();\n void this.client.start();\n }\n disconnectedCallback() {\n this.off?.(); void this.client?.end();\n for (const url of this.imagePreviewCache.values()) { if (typeof URL.revokeObjectURL === 'function') URL.revokeObjectURL(url); }\n this.imagePreviewCache.clear();\n }\n\n registerTools(handlers: Record<string, ChatToolHandler>) {\n if (this.client) this.client.registerTools(handlers);\n else Object.assign(this.pendingTools, handlers);\n }\n\n private send(text: string, files: File[]) {\n if (!text.trim()) return;\n for (const f of files) {\n if (f.type.startsWith('image/') && typeof URL.createObjectURL === 'function' && !this.imagePreviewCache.has(f.name)) {\n this.imagePreviewCache.set(f.name, URL.createObjectURL(f));\n }\n }\n void this.client?.sendMessage(text, files.length > 0 ? files : undefined);\n }\n private renderError(msg: string) {\n if (!this.shadowRoot) this.attachShadow({ mode: 'open' });\n this.shadowRoot!.innerHTML = `<div style=\"color:#b91c1c;font:13px system-ui;padding:12px\">${escapeHtml(msg)}</div>`;\n }\n private renderAttachment(a: ChatAttachmentDescriptor): string {\n if (a.contentType.startsWith('image/')) {\n // Instant src when a local blob (just sent by this widget instance) or a previously-resolved\n // read-back URL is cached. Otherwise render the placeholder with a data-oc-ref marker and no\n // src attribute (an empty src=\"\" would make the browser (re)request the current page) -\n // hydrateAttachmentImages() resolves it lazily right after this markup is attached to the DOM.\n const cached = (a.name ? this.imagePreviewCache.get(a.name) : undefined) ?? this.resolvedUrlCache.get(a.storageRef);\n const srcAttr = cached ? ` src=\"${cached}\"` : '';\n return `<img class=\"att-thumb\" data-oc-ref=\"${escapeHtml(a.storageRef)}\"${srcAttr} alt=\"${escapeHtml(a.name ?? 'image')}\"/>`;\n }\n return `<div class=\"att-chip\">📎 ${escapeHtml(a.name ?? a.contentType)}</div>`;\n }\n private renderSource(s: { id: string; title: string; snippet: string }): string {\n return `<div class=\"src-chip\" title=\"${escapeHtml(s.snippet)}\">${escapeHtml(s.title)}</div>`;\n }\n\n // After render() attaches the markup, resolve a read-back URL (via the client) for every image\n // placeholder that has no src yet - a local blob or a previously-resolved URL already set one, so\n // those are left untouched (no redundant network call).\n private hydrateAttachmentImages() {\n if (!this.client) return;\n const imgs = this.shadowRoot!.querySelectorAll<HTMLImageElement>('img.att-thumb[data-oc-ref]');\n imgs.forEach((img) => {\n if (img.hasAttribute('src')) return;\n const ref = img.getAttribute('data-oc-ref');\n if (!ref) return;\n void this.client!.getAttachmentUrl(ref)\n .then((url) => { this.resolvedUrlCache.set(ref, url); img.src = url; })\n .catch(() => { /* leave unresolved - no thumbnail is an acceptable degrade, not fatal */ });\n });\n }\n\n private render() {\n const title = this.getAttribute('title') ?? this.agentName ?? 'Chat';\n const bubbles = this.messages.map((m) => {\n const atts = (m.attachments ?? []).map((a) => this.renderAttachment(a)).join('');\n const label = m.role === 'human' ? '<div class=\"human-label\">Support</div>' : '';\n const bubble = `<div class=\"b ${m.role}\">${label}${atts}${m.text ? escapeHtml(m.text) : ''}${m.streaming ? '…' : ''}</div>`;\n const sources = m.sources && m.sources.length > 0 ? `<div class=\"src-row\">${m.sources.map((s) => this.renderSource(s)).join('')}</div>` : '';\n return bubble + sources;\n }).join('');\n const statusText = HANDOFF_STATUS_TEXT[this.handoffState];\n const status = statusText ? `<div class=\"status\">${escapeHtml(statusText)}</div>` : '';\n const errBanner = this.state === 'error' && this.lastError\n ? `<div class=\"err\">Couldn't start chat: ${escapeHtml(this.lastError)}</div>`\n : '';\n const showTyping = this.agentTyping && (this.handoffState === 'human' || this.handoffState === 'awaiting_human');\n const typingIndicator = showTyping ? `<div class=\"b assistant typing\">${escapeHtml(AGENT_TYPING_TEXT)}</div>` : '';\n const disabled = this.state !== 'ready' ? 'disabled' : '';\n // Rebuilding innerHTML replaces the input node, which would otherwise drop the user's\n // in-progress text + caret on every streamed token. Capture and restore across the rebuild.\n const prevInput = this.shadowRoot!.querySelector<HTMLInputElement>('input[aria-label=\"message\"]');\n const prevValue = prevInput?.value ?? '';\n const prevSelectionStart = prevInput?.selectionStart ?? null;\n const prevSelectionEnd = prevInput?.selectionEnd ?? null;\n const hadFocus = !!prevInput && this.shadowRoot!.activeElement === prevInput;\n this.shadowRoot!.innerHTML = `\n <style>\n :host{display:block;height:100%;min-height:320px;font-family:system-ui,sans-serif;--oc-accent:#2563eb}\n .wrap{display:flex;flex-direction:column;height:100%;border:1px solid #e5e7eb;border-radius:12px;overflow:hidden}\n .hd{padding:10px 14px;border-bottom:1px solid #e5e7eb;font-weight:600}\n .body{flex:1;overflow-y:auto;padding:12px;display:flex;flex-direction:column;gap:8px}\n .b{max-width:80%;padding:8px 12px;border-radius:12px;white-space:pre-wrap;word-break:break-word}\n .b.user{align-self:flex-end;background:var(--oc-accent);color:#fff}\n .b.assistant{align-self:flex-start;background:#f3f4f6;color:#111}\n .b.human{align-self:flex-start;background:#dbeafe;color:#111}\n .b.typing{font-style:italic;color:#6b7280;opacity:.85}\n .human-label{font-size:11px;font-weight:600;opacity:.7;margin-bottom:2px}\n .status{padding:6px 14px;font-size:12px;color:#6b7280;background:#f9fafb;border-bottom:1px solid #e5e7eb}\n .err{padding:8px 14px;font-size:12px;color:#b91c1c;background:#fef2f2;border-bottom:1px solid #fecaca}\n .att-thumb{display:block;max-width:160px;max-height:160px;border-radius:8px;margin-bottom:6px}\n .att-chip{display:inline-block;font-size:12px;background:rgba(0,0,0,.08);border-radius:6px;padding:2px 8px;margin:0 0 6px}\n .b.user .att-chip{background:rgba(255,255,255,.25)}\n .src-row{align-self:flex-start;display:flex;flex-wrap:wrap;gap:6px;max-width:80%}\n .src-chip{display:inline-block;font-size:11px;background:rgba(0,0,0,.06);color:#374151;border-radius:6px;padding:2px 8px;cursor:default}\n form{display:flex;gap:8px;padding:10px;border-top:1px solid #e5e7eb;align-items:center}\n input[aria-label=\"message\"]{flex:1;padding:8px 10px;border-radius:8px;border:1px solid #d1d5db;font:inherit}\n input[type=\"file\"]{max-width:120px;font-size:12px}\n button{padding:8px 14px;border-radius:8px;border:none;background:var(--oc-accent);color:#fff;font-weight:600;cursor:pointer}\n button:disabled,input:disabled{opacity:.6;cursor:not-allowed}\n </style>\n <div class=\"wrap\">\n <div class=\"hd\">${escapeHtml(title)}</div>\n ${status}${errBanner}\n <div class=\"body\">${bubbles}${typingIndicator}</div>\n <form>\n <input aria-label=\"message\" placeholder=\"Type a message…\" ${disabled}/>\n <input type=\"file\" accept=\"${ATTACHMENT_ACCEPT}\" multiple ${disabled}/>\n <button type=\"submit\" ${disabled}>Send</button>\n </form>\n </div>`;\n const form = this.shadowRoot!.querySelector('form')!;\n const input = this.shadowRoot!.querySelector<HTMLInputElement>('input[aria-label=\"message\"]')!;\n const fileInput = this.shadowRoot!.querySelector<HTMLInputElement>('input[type=\"file\"]')!;\n fileInput.addEventListener('change', () => { this.pendingFiles = fileInput.files ? Array.from(fileInput.files) : []; });\n form.addEventListener('submit', (e) => {\n e.preventDefault();\n const files = this.pendingFiles;\n this.pendingFiles = [];\n this.send(input.value, files);\n input.value = '';\n });\n if (prevValue) {\n input.value = prevValue;\n if (prevSelectionStart !== null && prevSelectionEnd !== null) input.setSelectionRange(prevSelectionStart, prevSelectionEnd);\n }\n if (hadFocus) input.focus();\n const body = this.shadowRoot!.querySelector('.body')!;\n body.scrollTop = body.scrollHeight;\n this.hydrateAttachmentImages();\n }\n}\nfunction escapeHtml(s: string) { return s.replace(/[&<>\"]/g, (c) => ({ '&': '&amp;', '<': '&lt;', '>': '&gt;', '\"': '&quot;' }[c]!)); }\n","export { ChatApiError } from './errors';\nexport type { ChatEvent, OpenSessionResponse, ChatClientOptions, ChatAttachmentDescriptor } from './protocol';\nexport { createChatClient } from './client';\nexport type { ChatClient, ChatMessage, ChatClientState, ChatClientEvent, ChatToolHandler } from './client';\nexport { OyehelloChatElement } from './element';\n\nimport { OyehelloChatElement } from './element';\n// Side effect: registering the element is why the package is sideEffects:true.\nif (typeof customElements !== 'undefined' && !customElements.get('oyehello-chat')) {\n customElements.define('oyehello-chat', OyehelloChatElement);\n}\n"]}
package/dist/index.d.cts CHANGED
@@ -139,6 +139,7 @@ declare class OyehelloChatElement extends HTMLElement {
139
139
  private agentName;
140
140
  private handoffState;
141
141
  private agentTyping;
142
+ private lastError;
142
143
  private pendingTools;
143
144
  private pendingFiles;
144
145
  private imagePreviewCache;
package/dist/index.d.ts CHANGED
@@ -139,6 +139,7 @@ declare class OyehelloChatElement extends HTMLElement {
139
139
  private agentName;
140
140
  private handoffState;
141
141
  private agentTyping;
142
+ private lastError;
142
143
  private pendingTools;
143
144
  private pendingFiles;
144
145
  private imagePreviewCache;
@@ -106,7 +106,7 @@ var OyehelloChat = (function (exports) {
106
106
  var seq = 0;
107
107
  var uid = (p) => `${p}_${Date.now().toString(36)}_${(seq++).toString(36)}`;
108
108
  function createChatClient(options) {
109
- const fetchImpl = options.fetch ?? globalThis.fetch;
109
+ const fetchImpl = options.fetch ?? globalThis.fetch.bind(globalThis);
110
110
  const ES = options.eventSource ?? globalThis.EventSource;
111
111
  const maxAttachments = options.maxAttachments ?? 4;
112
112
  const maxAttachmentBytes = options.maxAttachmentBytes ?? 1e7;
@@ -364,6 +364,10 @@ var OyehelloChat = (function (exports) {
364
364
  // Transient "agent is typing…" affordance (Phase 7 followups) - never a message, only rendered
365
365
  // while a handoff is active (human/awaiting_human).
366
366
  agentTyping = false;
367
+ // Last connection/runtime error message (client emits an 'error' event on a failed start() or
368
+ // send). Surfaced as a visible banner so a disabled composer always shows WHY, instead of sitting
369
+ // dead. Cleared when the client reaches a healthy state again.
370
+ lastError = null;
367
371
  // registerTools() may be called before connectedCallback creates the client (e.g. right after
368
372
  // document.createElement, before the element is attached). Buffer until the client exists.
369
373
  pendingTools = {};
@@ -392,10 +396,13 @@ var OyehelloChat = (function (exports) {
392
396
  }
393
397
  this.off = this.client.on((e) => {
394
398
  if (e.type === "messages") this.messages = e.messages;
395
- else if (e.type === "state") this.state = e.state;
396
- else if (e.type === "agent") this.agentName = e.agent.name;
399
+ else if (e.type === "state") {
400
+ this.state = e.state;
401
+ if (e.state === "ready" || e.state === "opening") this.lastError = null;
402
+ } else if (e.type === "agent") this.agentName = e.agent.name;
397
403
  else if (e.type === "handoff") this.handoffState = e.state;
398
404
  else if (e.type === "agentTyping") this.agentTyping = e.active;
405
+ else if (e.type === "error") this.lastError = e.error.message;
399
406
  this.render();
400
407
  });
401
408
  this.render();
@@ -465,6 +472,7 @@ var OyehelloChat = (function (exports) {
465
472
  }).join("");
466
473
  const statusText = HANDOFF_STATUS_TEXT[this.handoffState];
467
474
  const status = statusText ? `<div class="status">${escapeHtml(statusText)}</div>` : "";
475
+ const errBanner = this.state === "error" && this.lastError ? `<div class="err">Couldn't start chat: ${escapeHtml(this.lastError)}</div>` : "";
468
476
  const showTyping = this.agentTyping && (this.handoffState === "human" || this.handoffState === "awaiting_human");
469
477
  const typingIndicator = showTyping ? `<div class="b assistant typing">${escapeHtml(AGENT_TYPING_TEXT)}</div>` : "";
470
478
  const disabled = this.state !== "ready" ? "disabled" : "";
@@ -486,6 +494,7 @@ var OyehelloChat = (function (exports) {
486
494
  .b.typing{font-style:italic;color:#6b7280;opacity:.85}
487
495
  .human-label{font-size:11px;font-weight:600;opacity:.7;margin-bottom:2px}
488
496
  .status{padding:6px 14px;font-size:12px;color:#6b7280;background:#f9fafb;border-bottom:1px solid #e5e7eb}
497
+ .err{padding:8px 14px;font-size:12px;color:#b91c1c;background:#fef2f2;border-bottom:1px solid #fecaca}
489
498
  .att-thumb{display:block;max-width:160px;max-height:160px;border-radius:8px;margin-bottom:6px}
490
499
  .att-chip{display:inline-block;font-size:12px;background:rgba(0,0,0,.08);border-radius:6px;padding:2px 8px;margin:0 0 6px}
491
500
  .b.user .att-chip{background:rgba(255,255,255,.25)}
@@ -499,7 +508,7 @@ var OyehelloChat = (function (exports) {
499
508
  </style>
500
509
  <div class="wrap">
501
510
  <div class="hd">${escapeHtml(title)}</div>
502
- ${status}
511
+ ${status}${errBanner}
503
512
  <div class="body">${bubbles}${typingIndicator}</div>
504
513
  <form>
505
514
  <input aria-label="message" placeholder="Type a message\u2026" ${disabled}/>
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/errors.ts","../src/transport.ts","../src/client.ts","../src/element.ts","../src/index.ts"],"names":[],"mappings":"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","file":"index.global.js","sourcesContent":["export class ChatApiError extends Error {\n constructor(message: string, readonly status: number, readonly code?: string, readonly meta?: Record<string, unknown>) {\n super(message);\n this.name = 'ChatApiError';\n }\n}\n","import { ChatApiError } from './errors';\nimport type { ChatAttachmentDescriptor, OpenSessionResponse, StreamTicket } from './protocol';\n\nasync function asError(res: Response, fallbackCode?: string): Promise<ChatApiError> {\n let body: { error?: string; code?: string; meta?: Record<string, unknown> } = {};\n try { body = (await res.json()) as { error?: string; code?: string; meta?: Record<string, unknown> }; } catch { /* non-json */ }\n return new ChatApiError(body.error ?? `HTTP ${res.status}`, res.status, body.code ?? fallbackCode, body.meta);\n}\n\nexport async function openSession(opts: { baseUrl: string; apiKey: string; agentId: string; user?: { id?: string }; clientTools?: string[]; fetchImpl: typeof fetch }): Promise<OpenSessionResponse> {\n const body: Record<string, unknown> = { agentId: opts.agentId };\n if (opts.user) body.user = opts.user;\n if (opts.clientTools && opts.clientTools.length > 0) body.clientTools = opts.clientTools;\n const res = await opts.fetchImpl(`${opts.baseUrl}/chat/sessions`, {\n method: 'POST', credentials: 'omit',\n headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${opts.apiKey}` },\n body: JSON.stringify(body),\n });\n if (!res.ok) throw await asError(res);\n return (await res.json()) as OpenSessionResponse;\n}\n\nexport async function postMessage(opts: { baseUrl: string; sessionId: string; sessionToken: string; text: string; attachments?: ChatAttachmentDescriptor[]; fetchImpl: typeof fetch }): Promise<void> {\n const body: Record<string, unknown> = { text: opts.text };\n if (opts.attachments && opts.attachments.length > 0) body.attachments = opts.attachments;\n const res = await opts.fetchImpl(`${opts.baseUrl}/chat/sessions/${opts.sessionId}/messages`, {\n method: 'POST', credentials: 'omit',\n headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${opts.sessionToken}` },\n body: JSON.stringify(body),\n });\n // A 401 here means the 15-min session token expired (no refresh endpoint) — surface a stable code\n // so the client can transparently re-open a session and retry.\n if (!res.ok) throw await asError(res, res.status === 401 ? 'session_expired' : undefined);\n}\n\nexport async function endSession(opts: { baseUrl: string; sessionId: string; sessionToken: string; fetchImpl: typeof fetch }): Promise<void> {\n await opts.fetchImpl(`${opts.baseUrl}/chat/sessions/${opts.sessionId}/end`, {\n method: 'POST', credentials: 'omit',\n headers: { Authorization: `Bearer ${opts.sessionToken}` },\n }).catch(() => {}); // best-effort teardown\n}\n\nexport async function postToolResult(opts: { baseUrl: string; sessionId: string; sessionToken: string; callId: string; ok: boolean; result: unknown; fetchImpl: typeof fetch }): Promise<void> {\n await opts.fetchImpl(`${opts.baseUrl}/chat/sessions/${opts.sessionId}/tool-results`, {\n method: 'POST', credentials: 'omit',\n headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${opts.sessionToken}` },\n body: JSON.stringify({ callId: opts.callId, ok: opts.ok, result: opts.result }),\n }).catch(() => {}); // best-effort; a dropped result times out server-side and the model recovers\n}\n\nexport async function mintStreamTicket(opts: { baseUrl: string; sessionId: string; sessionToken: string; fetchImpl: typeof fetch }): Promise<StreamTicket> {\n const res = await opts.fetchImpl(`${opts.baseUrl}/chat/sessions/${opts.sessionId}/stream-ticket`, {\n method: 'POST', credentials: 'omit',\n headers: { Authorization: `Bearer ${opts.sessionToken}` },\n });\n // A 401 here means the session token is invalid/expired — surface a stable code so the client\n // can distinguish this from a transient failure (mirrors postMessage's 401 mapping).\n if (!res.ok) throw await asError(res, res.status === 401 ? 'session_expired' : undefined);\n return (await res.json()) as StreamTicket;\n}\n\nexport function streamUrl(baseUrl: string, sessionId: string, ticket: string): string {\n return `${baseUrl}/chat/sessions/${sessionId}/stream?ticket=${encodeURIComponent(ticket)}`;\n}\n\n// POST /chat/sessions/:id/attachments — mints a presigned S3 PUT for a visitor upload. Bearer session\n// token auth, mirrors mintStreamTicket's shape/error-mapping exactly.\nexport async function presignAttachment(opts: { baseUrl: string; sessionId: string; sessionToken: string; contentType: string; fetchImpl: typeof fetch }): Promise<{ storageRef: string; uploadUrl: string }> {\n const res = await opts.fetchImpl(`${opts.baseUrl}/chat/sessions/${opts.sessionId}/attachments`, {\n method: 'POST', credentials: 'omit',\n headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${opts.sessionToken}` },\n body: JSON.stringify({ contentType: opts.contentType }),\n });\n // A 401 here means the session token is invalid/expired — surface a stable code so the client\n // can distinguish this from a transient failure (mirrors postMessage's 401 mapping).\n if (!res.ok) throw await asError(res, res.status === 401 ? 'session_expired' : undefined);\n return (await res.json()) as { storageRef: string; uploadUrl: string };\n}\n\n// POST /chat/sessions/:id/attachment-url — mints a presigned S3 GET so an already-uploaded\n// attachment can be read back (e.g. rendering an image thumbnail on reconnect, when no local blob\n// is cached). Bearer session token auth, mirrors presignAttachment's shape/error-mapping exactly.\nexport async function getAttachmentUrl(opts: { baseUrl: string; sessionId: string; sessionToken: string; storageRef: string; fetchImpl: typeof fetch }): Promise<string> {\n const res = await opts.fetchImpl(`${opts.baseUrl}/chat/sessions/${opts.sessionId}/attachment-url`, {\n method: 'POST', credentials: 'omit',\n headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${opts.sessionToken}` },\n body: JSON.stringify({ storageRef: opts.storageRef }),\n });\n // A 401 here means the session token is invalid/expired — surface a stable code so the client\n // can distinguish this from a transient failure (mirrors postMessage's 401 mapping).\n if (!res.ok) throw await asError(res, res.status === 401 ? 'session_expired' : undefined);\n return ((await res.json()) as { url: string }).url;\n}\n\n// Uploads a file directly to the presigned S3 URL. The URL is already absolute and fully signed —\n// NO baseUrl prefix, NO Authorization header (would break the signature), just a bare PUT with the\n// file's own content type (Task 4 dropped SSE from the presign so this needs no extra headers).\nexport async function uploadToPresigned(uploadUrl: string, file: File, fetchImpl: typeof fetch): Promise<void> {\n const res = await fetchImpl(uploadUrl, { method: 'PUT', body: file, headers: { 'Content-Type': file.type } });\n if (!res.ok) throw new ChatApiError(`attachment upload failed with HTTP ${res.status}`, res.status);\n}\n","import { openSession, postMessage, endSession, streamUrl, mintStreamTicket, postToolResult, presignAttachment, uploadToPresigned, getAttachmentUrl } from './transport';\nimport { ChatApiError } from './errors';\nimport type { ChatAttachmentDescriptor, ChatClientOptions, ChatEvent, OpenSessionResponse } from './protocol';\n\nexport interface ChatMessage { id: string; role: 'user' | 'assistant' | 'human'; text: string; streaming: boolean; attachments?: ChatAttachmentDescriptor[]; sources?: { id: string; title: string; snippet: string }[]; turnId?: string }\nexport type ChatClientState = 'idle' | 'opening' | 'ready' | 'ended' | 'error';\n// Handoff status of the session, driven by the backend's `state` SSE event (Phase 7). 'ai' = the\n// AI is answering (default/no handoff), 'awaiting_human' = a handoff was requested and no human\n// has taken over yet, 'human' = a human agent is answering.\nexport type HandoffState = 'ai' | 'awaiting_human' | 'human';\nexport type ChatClientEvent =\n | { type: 'state'; state: ChatClientState }\n | { type: 'messages'; messages: ChatMessage[] }\n | { type: 'error'; error: Error }\n | { type: 'agent'; agent: { id: string; name: string } }\n // Handoff status changed (Phase 7) - the widget uses this to show a status line.\n | { type: 'handoff'; state: HandoffState }\n // A human agent is (or stopped) typing in the console during a handoff (Phase 7 followups). The\n // widget uses this to show a transient \"agent is typing…\" affordance - never a message.\n | { type: 'agentTyping'; active: boolean };\nexport type ChatToolHandler = (args: Record<string, unknown>) => unknown | Promise<unknown>;\nexport interface ChatClient {\n start(): Promise<void>;\n sendMessage(text: string, files?: File[]): Promise<void>;\n end(): Promise<void>;\n getMessages(): ChatMessage[];\n getState(): ChatClientState;\n on(listener: (e: ChatClientEvent) => void): () => void;\n // Register browser-side tool handlers the server may call mid-conversation. Register BEFORE\n // start() — the handler names are sent as `clientTools` on session open so the server knows\n // which tools this session can execute.\n registerTools(handlers: Record<string, ChatToolHandler>): void;\n // Resolves a read-back URL for an already-uploaded attachment (e.g. an image thumbnail with no\n // local blob cached — a reconnect, or an `attachment` SSE echo). Requires start() to have been\n // called (a live session).\n getAttachmentUrl(storageRef: string): Promise<string>;\n}\n\nlet seq = 0;\nconst uid = (p: string) => `${p}_${Date.now().toString(36)}_${(seq++).toString(36)}`;\n\nexport function createChatClient(options: ChatClientOptions): ChatClient {\n const fetchImpl = options.fetch ?? globalThis.fetch;\n const ES = options.eventSource ?? globalThis.EventSource;\n // Mirrors the server's CHAT_ATTACHMENT_MAX_PER_MESSAGE default (apps/api/src/config/env.ts).\n const maxAttachments = options.maxAttachments ?? 4;\n // Mirrors the server's CHAT_ATTACHMENT_MAX_BYTES default (apps/api/src/config/env.ts). UX-only\n // fast pre-check - the server is authoritative (message-time HeadObject size enforcement).\n const maxAttachmentBytes = options.maxAttachmentBytes ?? 10_000_000;\n const listeners = new Set<(e: ChatClientEvent) => void>();\n let state: ChatClientState = 'idle';\n const messages: ChatMessage[] = [];\n let streamingId: string | null = null;\n let session: OpenSessionResponse | null = null;\n let es: EventSource | null = null;\n const seenTurnIds = new Set<string>();\n const seenCallIds = new Set<string>();\n let handoffState: HandoffState = 'ai';\n let reconnectTimer: ReturnType<typeof setTimeout> | null = null;\n let reconnectAttempts = 0;\n let closed = false;\n const toolHandlers = new Map<string, ChatToolHandler>();\n const clearReconnect = () => { if (reconnectTimer) { clearTimeout(reconnectTimer); reconnectTimer = null; } };\n\n const emit = (e: ChatClientEvent) => { for (const l of listeners) l(e); };\n const setState = (s: ChatClientState) => { state = s; emit({ type: 'state', state: s }); };\n const emitMessages = () => emit({ type: 'messages', messages: messages.slice() });\n\n const onEvent = (ev: ChatEvent) => {\n if (ev.type === 'token') {\n let m = streamingId ? messages.find((x) => x.id === streamingId) : undefined;\n if (!m) { m = { id: uid('m'), role: 'assistant', text: '', streaming: true }; messages.push(m); streamingId = m.id; }\n m.text += ev.text; emitMessages();\n } else if (ev.type === 'message') {\n if (seenTurnIds.has(ev.turnId)) {\n // Replay of an already-finalized turn (EventSource reconnect replays the session's\n // event buffer). Discard it, and drop any partial streaming bubble its replayed\n // tokens built up, without emitting a duplicate assistant message.\n if (streamingId) {\n const idx = messages.findIndex((x) => x.id === streamingId);\n if (idx !== -1) messages.splice(idx, 1);\n streamingId = null;\n emitMessages();\n }\n return;\n }\n seenTurnIds.add(ev.turnId);\n const m = streamingId ? messages.find((x) => x.id === streamingId) : undefined;\n if (m) { m.text = ev.text; m.streaming = false; m.turnId = ev.turnId; } else { messages.push({ id: uid('m'), role: 'assistant', text: ev.text, streaming: false, turnId: ev.turnId }); }\n streamingId = null; emitMessages();\n } else if (ev.type === 'citations') {\n // Arrives AFTER `message` (streamingId already cleared) so the target message is located by\n // the turnId stamped above, not by streamingId. Ignore an unknown turnId (reconnect-safe: a\n // stale/duplicate citations replay for a turn we don't have never crashes or creates a bubble).\n const m = messages.find((x) => x.turnId === ev.turnId);\n if (m) { m.sources = ev.sources; emitMessages(); }\n } else if (ev.type === 'error') {\n emit({ type: 'error', error: new Error(ev.message) });\n } else if (ev.type === 'tool_call') {\n if (seenCallIds.has(ev.callId)) return; // replayed on EventSource reconnect — dispatch once\n seenCallIds.add(ev.callId);\n const handler = toolHandlers.get(ev.name);\n void (async () => {\n if (!session) return;\n const base = { baseUrl: options.baseUrl, sessionId: session.sessionId, sessionToken: session.sessionToken, callId: ev.callId, fetchImpl };\n if (!handler) {\n await postToolResult({ ...base, ok: false, result: `no handler registered for ${ev.name}` });\n return;\n }\n try {\n const out = await handler(ev.args);\n await postToolResult({ ...base, ok: true, result: typeof out === 'string' ? out : JSON.stringify(out ?? { ok: true }) });\n } catch (err) {\n await postToolResult({ ...base, ok: false, result: (err as Error).message });\n }\n })();\n } else if (ev.type === 'attachment') {\n // The runtime re-publishes a visitor's message attachments over this event (Phase 5\n // follow-up) so a reconnecting client (buffer replay) or a future second viewer can render\n // them, now that a read-back URL exists (getAttachmentUrl / element.ts's lazy image src).\n // Hardened so it can never double-render on the SENDING client itself, which already rendered\n // these optimistically from its own sendMessage(): if any existing message already carries an\n // attachment with one of these storageRefs, the event is a stale/duplicate echo of something\n // already rendered — ignore it entirely instead of guessing which message to attach to (a\n // \"most recent attachment-less user message\" heuristic misattaches when a second image-first\n // message is sent before the echo of the first one arrives).\n const items = ev.items;\n const alreadyRendered = messages.some((m) => m.attachments?.some((a) => items.some((i) => i.storageRef === a.storageRef)));\n if (alreadyRendered) return;\n const target = [...messages].reverse().find((m) => m.role === 'user' && !m.attachments);\n if (target) target.attachments = items;\n else messages.push({ id: uid('u'), role: 'user', text: '', streaming: false, attachments: items });\n emitMessages();\n } else if (ev.type === 'human_message') {\n // A human agent's reply from the console inbox (Phase 7 handoff) - render as a distinct bubble.\n // Dedup by turnId (shared with the `message` branch's seenTurnIds) - EventSource reconnect\n // replays the session's buffered events, and human_message turnIds (newId('tn')) are distinct\n // from message turnIds, so sharing the Set is safe.\n if (seenTurnIds.has(ev.turnId)) return;\n seenTurnIds.add(ev.turnId);\n messages.push({ id: uid('m'), role: 'human', text: ev.text, streaming: false });\n emitMessages();\n } else if (ev.type === 'visitor_message') {\n // Echo of the visitor's own message, published so the console inbox sees it live. The widget\n // already rendered this optimistically in sendMessage() - ignore the echo entirely.\n } else if (ev.type === 'state') {\n // Handoff status transition (Phase 7): 'ai' | 'awaiting_human' | 'human'. Ignore any other/\n // future state string - forward-compat, no status line for an unrecognized value.\n if (ev.state === 'ai' || ev.state === 'awaiting_human' || ev.state === 'human') {\n handoffState = ev.state;\n emit({ type: 'handoff', state: handoffState });\n }\n } else if (ev.type === 'agent_typing') {\n // Transient signal only - never pushed as a message, never touches dedup/streaming state.\n emit({ type: 'agentTyping', active: !!ev.active });\n }\n // 'done' and any future unknown types are ignored (forward-compat).\n };\n\n // Tickets are single-use and short-lived: a fresh one must be minted for every (re)connect.\n // Native EventSource auto-reconnect would retry the SAME url whose ticket is already consumed\n // (→ 401 forever), so on error we close it ourselves and drive reconnection here instead.\n const openStream = async () => {\n if (!session || closed) return;\n es?.close();\n const { ticket } = await mintStreamTicket({ baseUrl: options.baseUrl, sessionId: session.sessionId, sessionToken: session.sessionToken, fetchImpl });\n if (closed) return;\n es = new ES(streamUrl(options.baseUrl, session.sessionId, ticket));\n es.onopen = () => { reconnectAttempts = 0; };\n es.onmessage = (e: MessageEvent) => { try { onEvent(JSON.parse(e.data) as ChatEvent); } catch { /* ignore malformed */ } };\n es.onerror = () => { es?.close(); es = null; scheduleReconnect(); };\n };\n\n const scheduleReconnect = () => {\n if (closed) return;\n clearReconnect();\n const delay = Math.min(30_000, 500 * 2 ** reconnectAttempts);\n reconnectAttempts += 1;\n reconnectTimer = setTimeout(() => {\n openStream().catch((err) => {\n if (err instanceof ChatApiError && (err as ChatApiError).code === 'session_expired') {\n open().catch((e) => { emit({ type: 'error', error: e as Error }); scheduleReconnect(); });\n } else {\n scheduleReconnect();\n }\n });\n }, delay);\n };\n\n const open = async () => {\n session = await openSession({ baseUrl: options.baseUrl, apiKey: options.apiKey, agentId: options.agentId, user: options.user, clientTools: Array.from(toolHandlers.keys()), fetchImpl });\n emit({ type: 'agent', agent: session.agent });\n await openStream();\n };\n\n // Presign + PUT every file against the CURRENT session. Called from the main sendMessage path and,\n // after a session_expired reopen, from the retry — a storageRef presigned against the old\n // interactionId is rejected cross-session (403 attachment_cross_session) if reused post-reopen.\n const uploadFiles = async (files: File[]): Promise<ChatAttachmentDescriptor[]> => {\n return Promise.all(files.map(async (file): Promise<ChatAttachmentDescriptor> => {\n const { storageRef, uploadUrl } = await presignAttachment({ baseUrl: options.baseUrl, sessionId: session!.sessionId, sessionToken: session!.sessionToken, contentType: file.type, fetchImpl });\n await uploadToPresigned(uploadUrl, file, fetchImpl);\n return { storageRef, contentType: file.type, name: file.name };\n }));\n };\n\n return {\n getMessages: () => messages.slice(),\n getState: () => state,\n on(listener) { listeners.add(listener); return () => listeners.delete(listener); },\n registerTools(handlers) { for (const [name, fn] of Object.entries(handlers)) toolHandlers.set(name, fn); },\n async getAttachmentUrl(storageRef) {\n if (!session) throw new Error('call start() before getAttachmentUrl');\n return getAttachmentUrl({ baseUrl: options.baseUrl, sessionId: session.sessionId, sessionToken: session.sessionToken, storageRef, fetchImpl });\n },\n async start() {\n if (state !== 'idle') return;\n setState('opening');\n try { await open(); setState('ready'); }\n catch (err) { setState('error'); emit({ type: 'error', error: err as Error }); }\n },\n async sendMessage(text, files) {\n if (!session) { emit({ type: 'error', error: new Error('call start() before sendMessage') }); return; }\n const fileList = files ?? [];\n if (fileList.length > maxAttachments) {\n emit({ type: 'error', error: new Error(`too many attachments: max ${maxAttachments} per message`) });\n return;\n }\n const oversized = fileList.find((f) => f.size > maxAttachmentBytes);\n if (oversized) {\n emit({ type: 'error', error: new Error(`attachment too large: ${oversized.name} exceeds ${maxAttachmentBytes} bytes`) });\n return;\n }\n // Upload every file BEFORE posting the message or pushing the optimistic bubble — a failed\n // upload must never leave a broken/partial message in the thread.\n let attachments: ChatAttachmentDescriptor[] = [];\n if (fileList.length > 0) {\n try {\n attachments = await uploadFiles(fileList);\n } catch (err) {\n emit({ type: 'error', error: err as Error });\n return;\n }\n }\n messages.push({ id: uid('u'), role: 'user', text, streaming: false, attachments: attachments.length > 0 ? attachments : undefined }); emitMessages();\n try {\n await postMessage({ baseUrl: options.baseUrl, sessionId: session.sessionId, sessionToken: session.sessionToken, text, attachments, fetchImpl });\n } catch (err) {\n if (err instanceof ChatApiError && err.code === 'session_expired') {\n try {\n await open(); // fresh backend session, same UI thread\n // Re-upload against the NEW session — the old attachments' storageRefs are bound to the\n // stale interactionId and would 403 (attachment_cross_session) if re-posted as-is.\n const freshAttachments = fileList.length ? await uploadFiles(fileList) : [];\n await postMessage({ baseUrl: options.baseUrl, sessionId: session!.sessionId, sessionToken: session!.sessionToken, text, attachments: freshAttachments, fetchImpl });\n } catch (retryErr) {\n emit({ type: 'error', error: retryErr as Error });\n }\n } else { emit({ type: 'error', error: err as Error }); }\n }\n },\n async end() {\n closed = true; clearReconnect();\n if (session) await endSession({ baseUrl: options.baseUrl, sessionId: session.sessionId, sessionToken: session.sessionToken, fetchImpl });\n es?.close(); es = null; setState('ended');\n },\n };\n}\n","import { createChatClient, type ChatClient, type ChatMessage, type ChatClientState, type ChatToolHandler, type HandoffState } from './client';\nimport type { ChatAttachmentDescriptor } from './protocol';\n\nconst HANDOFF_STATUS_TEXT: Record<HandoffState, string | null> = {\n ai: null,\n awaiting_human: 'Connecting you to a person…',\n human: \"You're chatting with a person\",\n};\n\nconst ATTACHMENT_ACCEPT = 'image/*,application/pdf,text/plain,text/csv';\nconst AGENT_TYPING_TEXT = 'The agent is typing…';\n\nexport class OyehelloChatElement extends HTMLElement {\n static observedAttributes = ['api-key', 'agent-id', 'base-url', 'title'];\n private client: ChatClient | null = null;\n private off: (() => void) | null = null;\n private messages: ChatMessage[] = [];\n private state: ChatClientState = 'idle';\n private agentName: string | null = null;\n private handoffState: HandoffState = 'ai';\n // Transient \"agent is typing…\" affordance (Phase 7 followups) - never a message, only rendered\n // while a handoff is active (human/awaiting_human).\n private agentTyping = false;\n // registerTools() may be called before connectedCallback creates the client (e.g. right after\n // document.createElement, before the element is attached). Buffer until the client exists.\n private pendingTools: Record<string, ChatToolHandler> = {};\n // Files picked in the file input, staged until the form submits alongside the text.\n private pendingFiles: File[] = [];\n // Best-effort local thumbnail cache for images THIS widget instance just sent, keyed by filename -\n // an instant blob src, no round-trip needed.\n private imagePreviewCache = new Map<string, string>();\n // Read-back URLs resolved lazily (via client.getAttachmentUrl) for images with no local blob (a\n // reconnect, or an `attachment` SSE echo), keyed by storageRef. Cached across re-renders so the\n // same image isn't re-fetched on every render() call.\n private resolvedUrlCache = new Map<string, string>();\n\n connectedCallback() {\n if (!this.shadowRoot) this.attachShadow({ mode: 'open' });\n const apiKey = this.getAttribute('api-key');\n const agentId = this.getAttribute('agent-id');\n const baseUrl = this.getAttribute('base-url');\n if (!apiKey || !agentId || !baseUrl) { this.renderError('oyehello-chat: api-key, agent-id and base-url are required'); return; }\n this.client = createChatClient({ apiKey, agentId, baseUrl });\n if (Object.keys(this.pendingTools).length > 0) { this.client.registerTools(this.pendingTools); this.pendingTools = {}; }\n this.off = this.client.on((e) => {\n if (e.type === 'messages') this.messages = e.messages;\n else if (e.type === 'state') this.state = e.state;\n else if (e.type === 'agent') this.agentName = e.agent.name;\n else if (e.type === 'handoff') this.handoffState = e.state;\n else if (e.type === 'agentTyping') this.agentTyping = e.active;\n this.render();\n });\n this.render();\n void this.client.start();\n }\n disconnectedCallback() {\n this.off?.(); void this.client?.end();\n for (const url of this.imagePreviewCache.values()) { if (typeof URL.revokeObjectURL === 'function') URL.revokeObjectURL(url); }\n this.imagePreviewCache.clear();\n }\n\n registerTools(handlers: Record<string, ChatToolHandler>) {\n if (this.client) this.client.registerTools(handlers);\n else Object.assign(this.pendingTools, handlers);\n }\n\n private send(text: string, files: File[]) {\n if (!text.trim()) return;\n for (const f of files) {\n if (f.type.startsWith('image/') && typeof URL.createObjectURL === 'function' && !this.imagePreviewCache.has(f.name)) {\n this.imagePreviewCache.set(f.name, URL.createObjectURL(f));\n }\n }\n void this.client?.sendMessage(text, files.length > 0 ? files : undefined);\n }\n private renderError(msg: string) {\n if (!this.shadowRoot) this.attachShadow({ mode: 'open' });\n this.shadowRoot!.innerHTML = `<div style=\"color:#b91c1c;font:13px system-ui;padding:12px\">${escapeHtml(msg)}</div>`;\n }\n private renderAttachment(a: ChatAttachmentDescriptor): string {\n if (a.contentType.startsWith('image/')) {\n // Instant src when a local blob (just sent by this widget instance) or a previously-resolved\n // read-back URL is cached. Otherwise render the placeholder with a data-oc-ref marker and no\n // src attribute (an empty src=\"\" would make the browser (re)request the current page) -\n // hydrateAttachmentImages() resolves it lazily right after this markup is attached to the DOM.\n const cached = (a.name ? this.imagePreviewCache.get(a.name) : undefined) ?? this.resolvedUrlCache.get(a.storageRef);\n const srcAttr = cached ? ` src=\"${cached}\"` : '';\n return `<img class=\"att-thumb\" data-oc-ref=\"${escapeHtml(a.storageRef)}\"${srcAttr} alt=\"${escapeHtml(a.name ?? 'image')}\"/>`;\n }\n return `<div class=\"att-chip\">📎 ${escapeHtml(a.name ?? a.contentType)}</div>`;\n }\n private renderSource(s: { id: string; title: string; snippet: string }): string {\n return `<div class=\"src-chip\" title=\"${escapeHtml(s.snippet)}\">${escapeHtml(s.title)}</div>`;\n }\n\n // After render() attaches the markup, resolve a read-back URL (via the client) for every image\n // placeholder that has no src yet - a local blob or a previously-resolved URL already set one, so\n // those are left untouched (no redundant network call).\n private hydrateAttachmentImages() {\n if (!this.client) return;\n const imgs = this.shadowRoot!.querySelectorAll<HTMLImageElement>('img.att-thumb[data-oc-ref]');\n imgs.forEach((img) => {\n if (img.hasAttribute('src')) return;\n const ref = img.getAttribute('data-oc-ref');\n if (!ref) return;\n void this.client!.getAttachmentUrl(ref)\n .then((url) => { this.resolvedUrlCache.set(ref, url); img.src = url; })\n .catch(() => { /* leave unresolved - no thumbnail is an acceptable degrade, not fatal */ });\n });\n }\n\n private render() {\n const title = this.getAttribute('title') ?? this.agentName ?? 'Chat';\n const bubbles = this.messages.map((m) => {\n const atts = (m.attachments ?? []).map((a) => this.renderAttachment(a)).join('');\n const label = m.role === 'human' ? '<div class=\"human-label\">Support</div>' : '';\n const bubble = `<div class=\"b ${m.role}\">${label}${atts}${m.text ? escapeHtml(m.text) : ''}${m.streaming ? '…' : ''}</div>`;\n const sources = m.sources && m.sources.length > 0 ? `<div class=\"src-row\">${m.sources.map((s) => this.renderSource(s)).join('')}</div>` : '';\n return bubble + sources;\n }).join('');\n const statusText = HANDOFF_STATUS_TEXT[this.handoffState];\n const status = statusText ? `<div class=\"status\">${escapeHtml(statusText)}</div>` : '';\n const showTyping = this.agentTyping && (this.handoffState === 'human' || this.handoffState === 'awaiting_human');\n const typingIndicator = showTyping ? `<div class=\"b assistant typing\">${escapeHtml(AGENT_TYPING_TEXT)}</div>` : '';\n const disabled = this.state !== 'ready' ? 'disabled' : '';\n // Rebuilding innerHTML replaces the input node, which would otherwise drop the user's\n // in-progress text + caret on every streamed token. Capture and restore across the rebuild.\n const prevInput = this.shadowRoot!.querySelector<HTMLInputElement>('input[aria-label=\"message\"]');\n const prevValue = prevInput?.value ?? '';\n const prevSelectionStart = prevInput?.selectionStart ?? null;\n const prevSelectionEnd = prevInput?.selectionEnd ?? null;\n const hadFocus = !!prevInput && this.shadowRoot!.activeElement === prevInput;\n this.shadowRoot!.innerHTML = `\n <style>\n :host{display:block;height:100%;min-height:320px;font-family:system-ui,sans-serif;--oc-accent:#2563eb}\n .wrap{display:flex;flex-direction:column;height:100%;border:1px solid #e5e7eb;border-radius:12px;overflow:hidden}\n .hd{padding:10px 14px;border-bottom:1px solid #e5e7eb;font-weight:600}\n .body{flex:1;overflow-y:auto;padding:12px;display:flex;flex-direction:column;gap:8px}\n .b{max-width:80%;padding:8px 12px;border-radius:12px;white-space:pre-wrap;word-break:break-word}\n .b.user{align-self:flex-end;background:var(--oc-accent);color:#fff}\n .b.assistant{align-self:flex-start;background:#f3f4f6;color:#111}\n .b.human{align-self:flex-start;background:#dbeafe;color:#111}\n .b.typing{font-style:italic;color:#6b7280;opacity:.85}\n .human-label{font-size:11px;font-weight:600;opacity:.7;margin-bottom:2px}\n .status{padding:6px 14px;font-size:12px;color:#6b7280;background:#f9fafb;border-bottom:1px solid #e5e7eb}\n .att-thumb{display:block;max-width:160px;max-height:160px;border-radius:8px;margin-bottom:6px}\n .att-chip{display:inline-block;font-size:12px;background:rgba(0,0,0,.08);border-radius:6px;padding:2px 8px;margin:0 0 6px}\n .b.user .att-chip{background:rgba(255,255,255,.25)}\n .src-row{align-self:flex-start;display:flex;flex-wrap:wrap;gap:6px;max-width:80%}\n .src-chip{display:inline-block;font-size:11px;background:rgba(0,0,0,.06);color:#374151;border-radius:6px;padding:2px 8px;cursor:default}\n form{display:flex;gap:8px;padding:10px;border-top:1px solid #e5e7eb;align-items:center}\n input[aria-label=\"message\"]{flex:1;padding:8px 10px;border-radius:8px;border:1px solid #d1d5db;font:inherit}\n input[type=\"file\"]{max-width:120px;font-size:12px}\n button{padding:8px 14px;border-radius:8px;border:none;background:var(--oc-accent);color:#fff;font-weight:600;cursor:pointer}\n button:disabled,input:disabled{opacity:.6;cursor:not-allowed}\n </style>\n <div class=\"wrap\">\n <div class=\"hd\">${escapeHtml(title)}</div>\n ${status}\n <div class=\"body\">${bubbles}${typingIndicator}</div>\n <form>\n <input aria-label=\"message\" placeholder=\"Type a message…\" ${disabled}/>\n <input type=\"file\" accept=\"${ATTACHMENT_ACCEPT}\" multiple ${disabled}/>\n <button type=\"submit\" ${disabled}>Send</button>\n </form>\n </div>`;\n const form = this.shadowRoot!.querySelector('form')!;\n const input = this.shadowRoot!.querySelector<HTMLInputElement>('input[aria-label=\"message\"]')!;\n const fileInput = this.shadowRoot!.querySelector<HTMLInputElement>('input[type=\"file\"]')!;\n fileInput.addEventListener('change', () => { this.pendingFiles = fileInput.files ? Array.from(fileInput.files) : []; });\n form.addEventListener('submit', (e) => {\n e.preventDefault();\n const files = this.pendingFiles;\n this.pendingFiles = [];\n this.send(input.value, files);\n input.value = '';\n });\n if (prevValue) {\n input.value = prevValue;\n if (prevSelectionStart !== null && prevSelectionEnd !== null) input.setSelectionRange(prevSelectionStart, prevSelectionEnd);\n }\n if (hadFocus) input.focus();\n const body = this.shadowRoot!.querySelector('.body')!;\n body.scrollTop = body.scrollHeight;\n this.hydrateAttachmentImages();\n }\n}\nfunction escapeHtml(s: string) { return s.replace(/[&<>\"]/g, (c) => ({ '&': '&amp;', '<': '&lt;', '>': '&gt;', '\"': '&quot;' }[c]!)); }\n","export { ChatApiError } from './errors';\nexport type { ChatEvent, OpenSessionResponse, ChatClientOptions, ChatAttachmentDescriptor } from './protocol';\nexport { createChatClient } from './client';\nexport type { ChatClient, ChatMessage, ChatClientState, ChatClientEvent, ChatToolHandler } from './client';\nexport { OyehelloChatElement } from './element';\n\nimport { OyehelloChatElement } from './element';\n// Side effect: registering the element is why the package is sideEffects:true.\nif (typeof customElements !== 'undefined' && !customElements.get('oyehello-chat')) {\n customElements.define('oyehello-chat', OyehelloChatElement);\n}\n"]}
1
+ {"version":3,"sources":["../src/errors.ts","../src/transport.ts","../src/client.ts","../src/element.ts","../src/index.ts"],"names":[],"mappings":"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","file":"index.global.js","sourcesContent":["export class ChatApiError extends Error {\n constructor(message: string, readonly status: number, readonly code?: string, readonly meta?: Record<string, unknown>) {\n super(message);\n this.name = 'ChatApiError';\n }\n}\n","import { ChatApiError } from './errors';\nimport type { ChatAttachmentDescriptor, OpenSessionResponse, StreamTicket } from './protocol';\n\nasync function asError(res: Response, fallbackCode?: string): Promise<ChatApiError> {\n let body: { error?: string; code?: string; meta?: Record<string, unknown> } = {};\n try { body = (await res.json()) as { error?: string; code?: string; meta?: Record<string, unknown> }; } catch { /* non-json */ }\n return new ChatApiError(body.error ?? `HTTP ${res.status}`, res.status, body.code ?? fallbackCode, body.meta);\n}\n\nexport async function openSession(opts: { baseUrl: string; apiKey: string; agentId: string; user?: { id?: string }; clientTools?: string[]; fetchImpl: typeof fetch }): Promise<OpenSessionResponse> {\n const body: Record<string, unknown> = { agentId: opts.agentId };\n if (opts.user) body.user = opts.user;\n if (opts.clientTools && opts.clientTools.length > 0) body.clientTools = opts.clientTools;\n const res = await opts.fetchImpl(`${opts.baseUrl}/chat/sessions`, {\n method: 'POST', credentials: 'omit',\n headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${opts.apiKey}` },\n body: JSON.stringify(body),\n });\n if (!res.ok) throw await asError(res);\n return (await res.json()) as OpenSessionResponse;\n}\n\nexport async function postMessage(opts: { baseUrl: string; sessionId: string; sessionToken: string; text: string; attachments?: ChatAttachmentDescriptor[]; fetchImpl: typeof fetch }): Promise<void> {\n const body: Record<string, unknown> = { text: opts.text };\n if (opts.attachments && opts.attachments.length > 0) body.attachments = opts.attachments;\n const res = await opts.fetchImpl(`${opts.baseUrl}/chat/sessions/${opts.sessionId}/messages`, {\n method: 'POST', credentials: 'omit',\n headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${opts.sessionToken}` },\n body: JSON.stringify(body),\n });\n // A 401 here means the 15-min session token expired (no refresh endpoint) — surface a stable code\n // so the client can transparently re-open a session and retry.\n if (!res.ok) throw await asError(res, res.status === 401 ? 'session_expired' : undefined);\n}\n\nexport async function endSession(opts: { baseUrl: string; sessionId: string; sessionToken: string; fetchImpl: typeof fetch }): Promise<void> {\n await opts.fetchImpl(`${opts.baseUrl}/chat/sessions/${opts.sessionId}/end`, {\n method: 'POST', credentials: 'omit',\n headers: { Authorization: `Bearer ${opts.sessionToken}` },\n }).catch(() => {}); // best-effort teardown\n}\n\nexport async function postToolResult(opts: { baseUrl: string; sessionId: string; sessionToken: string; callId: string; ok: boolean; result: unknown; fetchImpl: typeof fetch }): Promise<void> {\n await opts.fetchImpl(`${opts.baseUrl}/chat/sessions/${opts.sessionId}/tool-results`, {\n method: 'POST', credentials: 'omit',\n headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${opts.sessionToken}` },\n body: JSON.stringify({ callId: opts.callId, ok: opts.ok, result: opts.result }),\n }).catch(() => {}); // best-effort; a dropped result times out server-side and the model recovers\n}\n\nexport async function mintStreamTicket(opts: { baseUrl: string; sessionId: string; sessionToken: string; fetchImpl: typeof fetch }): Promise<StreamTicket> {\n const res = await opts.fetchImpl(`${opts.baseUrl}/chat/sessions/${opts.sessionId}/stream-ticket`, {\n method: 'POST', credentials: 'omit',\n headers: { Authorization: `Bearer ${opts.sessionToken}` },\n });\n // A 401 here means the session token is invalid/expired — surface a stable code so the client\n // can distinguish this from a transient failure (mirrors postMessage's 401 mapping).\n if (!res.ok) throw await asError(res, res.status === 401 ? 'session_expired' : undefined);\n return (await res.json()) as StreamTicket;\n}\n\nexport function streamUrl(baseUrl: string, sessionId: string, ticket: string): string {\n return `${baseUrl}/chat/sessions/${sessionId}/stream?ticket=${encodeURIComponent(ticket)}`;\n}\n\n// POST /chat/sessions/:id/attachments — mints a presigned S3 PUT for a visitor upload. Bearer session\n// token auth, mirrors mintStreamTicket's shape/error-mapping exactly.\nexport async function presignAttachment(opts: { baseUrl: string; sessionId: string; sessionToken: string; contentType: string; fetchImpl: typeof fetch }): Promise<{ storageRef: string; uploadUrl: string }> {\n const res = await opts.fetchImpl(`${opts.baseUrl}/chat/sessions/${opts.sessionId}/attachments`, {\n method: 'POST', credentials: 'omit',\n headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${opts.sessionToken}` },\n body: JSON.stringify({ contentType: opts.contentType }),\n });\n // A 401 here means the session token is invalid/expired — surface a stable code so the client\n // can distinguish this from a transient failure (mirrors postMessage's 401 mapping).\n if (!res.ok) throw await asError(res, res.status === 401 ? 'session_expired' : undefined);\n return (await res.json()) as { storageRef: string; uploadUrl: string };\n}\n\n// POST /chat/sessions/:id/attachment-url — mints a presigned S3 GET so an already-uploaded\n// attachment can be read back (e.g. rendering an image thumbnail on reconnect, when no local blob\n// is cached). Bearer session token auth, mirrors presignAttachment's shape/error-mapping exactly.\nexport async function getAttachmentUrl(opts: { baseUrl: string; sessionId: string; sessionToken: string; storageRef: string; fetchImpl: typeof fetch }): Promise<string> {\n const res = await opts.fetchImpl(`${opts.baseUrl}/chat/sessions/${opts.sessionId}/attachment-url`, {\n method: 'POST', credentials: 'omit',\n headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${opts.sessionToken}` },\n body: JSON.stringify({ storageRef: opts.storageRef }),\n });\n // A 401 here means the session token is invalid/expired — surface a stable code so the client\n // can distinguish this from a transient failure (mirrors postMessage's 401 mapping).\n if (!res.ok) throw await asError(res, res.status === 401 ? 'session_expired' : undefined);\n return ((await res.json()) as { url: string }).url;\n}\n\n// Uploads a file directly to the presigned S3 URL. The URL is already absolute and fully signed —\n// NO baseUrl prefix, NO Authorization header (would break the signature), just a bare PUT with the\n// file's own content type (Task 4 dropped SSE from the presign so this needs no extra headers).\nexport async function uploadToPresigned(uploadUrl: string, file: File, fetchImpl: typeof fetch): Promise<void> {\n const res = await fetchImpl(uploadUrl, { method: 'PUT', body: file, headers: { 'Content-Type': file.type } });\n if (!res.ok) throw new ChatApiError(`attachment upload failed with HTTP ${res.status}`, res.status);\n}\n","import { openSession, postMessage, endSession, streamUrl, mintStreamTicket, postToolResult, presignAttachment, uploadToPresigned, getAttachmentUrl } from './transport';\nimport { ChatApiError } from './errors';\nimport type { ChatAttachmentDescriptor, ChatClientOptions, ChatEvent, OpenSessionResponse } from './protocol';\n\nexport interface ChatMessage { id: string; role: 'user' | 'assistant' | 'human'; text: string; streaming: boolean; attachments?: ChatAttachmentDescriptor[]; sources?: { id: string; title: string; snippet: string }[]; turnId?: string }\nexport type ChatClientState = 'idle' | 'opening' | 'ready' | 'ended' | 'error';\n// Handoff status of the session, driven by the backend's `state` SSE event (Phase 7). 'ai' = the\n// AI is answering (default/no handoff), 'awaiting_human' = a handoff was requested and no human\n// has taken over yet, 'human' = a human agent is answering.\nexport type HandoffState = 'ai' | 'awaiting_human' | 'human';\nexport type ChatClientEvent =\n | { type: 'state'; state: ChatClientState }\n | { type: 'messages'; messages: ChatMessage[] }\n | { type: 'error'; error: Error }\n | { type: 'agent'; agent: { id: string; name: string } }\n // Handoff status changed (Phase 7) - the widget uses this to show a status line.\n | { type: 'handoff'; state: HandoffState }\n // A human agent is (or stopped) typing in the console during a handoff (Phase 7 followups). The\n // widget uses this to show a transient \"agent is typing…\" affordance - never a message.\n | { type: 'agentTyping'; active: boolean };\nexport type ChatToolHandler = (args: Record<string, unknown>) => unknown | Promise<unknown>;\nexport interface ChatClient {\n start(): Promise<void>;\n sendMessage(text: string, files?: File[]): Promise<void>;\n end(): Promise<void>;\n getMessages(): ChatMessage[];\n getState(): ChatClientState;\n on(listener: (e: ChatClientEvent) => void): () => void;\n // Register browser-side tool handlers the server may call mid-conversation. Register BEFORE\n // start() — the handler names are sent as `clientTools` on session open so the server knows\n // which tools this session can execute.\n registerTools(handlers: Record<string, ChatToolHandler>): void;\n // Resolves a read-back URL for an already-uploaded attachment (e.g. an image thumbnail with no\n // local blob cached — a reconnect, or an `attachment` SSE echo). Requires start() to have been\n // called (a live session).\n getAttachmentUrl(storageRef: string): Promise<string>;\n}\n\nlet seq = 0;\nconst uid = (p: string) => `${p}_${Date.now().toString(36)}_${(seq++).toString(36)}`;\n\nexport function createChatClient(options: ChatClientOptions): ChatClient {\n // Native fetch must be invoked with `this === window`; the transport calls this as\n // `opts.fetchImpl(...)`, so a bare `globalThis.fetch` reference throws \"Illegal invocation\".\n // Bind the default to the global. A caller-supplied fetch is used as-is.\n const fetchImpl = options.fetch ?? globalThis.fetch.bind(globalThis);\n const ES = options.eventSource ?? globalThis.EventSource;\n // Mirrors the server's CHAT_ATTACHMENT_MAX_PER_MESSAGE default (apps/api/src/config/env.ts).\n const maxAttachments = options.maxAttachments ?? 4;\n // Mirrors the server's CHAT_ATTACHMENT_MAX_BYTES default (apps/api/src/config/env.ts). UX-only\n // fast pre-check - the server is authoritative (message-time HeadObject size enforcement).\n const maxAttachmentBytes = options.maxAttachmentBytes ?? 10_000_000;\n const listeners = new Set<(e: ChatClientEvent) => void>();\n let state: ChatClientState = 'idle';\n const messages: ChatMessage[] = [];\n let streamingId: string | null = null;\n let session: OpenSessionResponse | null = null;\n let es: EventSource | null = null;\n const seenTurnIds = new Set<string>();\n const seenCallIds = new Set<string>();\n let handoffState: HandoffState = 'ai';\n let reconnectTimer: ReturnType<typeof setTimeout> | null = null;\n let reconnectAttempts = 0;\n let closed = false;\n const toolHandlers = new Map<string, ChatToolHandler>();\n const clearReconnect = () => { if (reconnectTimer) { clearTimeout(reconnectTimer); reconnectTimer = null; } };\n\n const emit = (e: ChatClientEvent) => { for (const l of listeners) l(e); };\n const setState = (s: ChatClientState) => { state = s; emit({ type: 'state', state: s }); };\n const emitMessages = () => emit({ type: 'messages', messages: messages.slice() });\n\n const onEvent = (ev: ChatEvent) => {\n if (ev.type === 'token') {\n let m = streamingId ? messages.find((x) => x.id === streamingId) : undefined;\n if (!m) { m = { id: uid('m'), role: 'assistant', text: '', streaming: true }; messages.push(m); streamingId = m.id; }\n m.text += ev.text; emitMessages();\n } else if (ev.type === 'message') {\n if (seenTurnIds.has(ev.turnId)) {\n // Replay of an already-finalized turn (EventSource reconnect replays the session's\n // event buffer). Discard it, and drop any partial streaming bubble its replayed\n // tokens built up, without emitting a duplicate assistant message.\n if (streamingId) {\n const idx = messages.findIndex((x) => x.id === streamingId);\n if (idx !== -1) messages.splice(idx, 1);\n streamingId = null;\n emitMessages();\n }\n return;\n }\n seenTurnIds.add(ev.turnId);\n const m = streamingId ? messages.find((x) => x.id === streamingId) : undefined;\n if (m) { m.text = ev.text; m.streaming = false; m.turnId = ev.turnId; } else { messages.push({ id: uid('m'), role: 'assistant', text: ev.text, streaming: false, turnId: ev.turnId }); }\n streamingId = null; emitMessages();\n } else if (ev.type === 'citations') {\n // Arrives AFTER `message` (streamingId already cleared) so the target message is located by\n // the turnId stamped above, not by streamingId. Ignore an unknown turnId (reconnect-safe: a\n // stale/duplicate citations replay for a turn we don't have never crashes or creates a bubble).\n const m = messages.find((x) => x.turnId === ev.turnId);\n if (m) { m.sources = ev.sources; emitMessages(); }\n } else if (ev.type === 'error') {\n emit({ type: 'error', error: new Error(ev.message) });\n } else if (ev.type === 'tool_call') {\n if (seenCallIds.has(ev.callId)) return; // replayed on EventSource reconnect — dispatch once\n seenCallIds.add(ev.callId);\n const handler = toolHandlers.get(ev.name);\n void (async () => {\n if (!session) return;\n const base = { baseUrl: options.baseUrl, sessionId: session.sessionId, sessionToken: session.sessionToken, callId: ev.callId, fetchImpl };\n if (!handler) {\n await postToolResult({ ...base, ok: false, result: `no handler registered for ${ev.name}` });\n return;\n }\n try {\n const out = await handler(ev.args);\n await postToolResult({ ...base, ok: true, result: typeof out === 'string' ? out : JSON.stringify(out ?? { ok: true }) });\n } catch (err) {\n await postToolResult({ ...base, ok: false, result: (err as Error).message });\n }\n })();\n } else if (ev.type === 'attachment') {\n // The runtime re-publishes a visitor's message attachments over this event (Phase 5\n // follow-up) so a reconnecting client (buffer replay) or a future second viewer can render\n // them, now that a read-back URL exists (getAttachmentUrl / element.ts's lazy image src).\n // Hardened so it can never double-render on the SENDING client itself, which already rendered\n // these optimistically from its own sendMessage(): if any existing message already carries an\n // attachment with one of these storageRefs, the event is a stale/duplicate echo of something\n // already rendered — ignore it entirely instead of guessing which message to attach to (a\n // \"most recent attachment-less user message\" heuristic misattaches when a second image-first\n // message is sent before the echo of the first one arrives).\n const items = ev.items;\n const alreadyRendered = messages.some((m) => m.attachments?.some((a) => items.some((i) => i.storageRef === a.storageRef)));\n if (alreadyRendered) return;\n const target = [...messages].reverse().find((m) => m.role === 'user' && !m.attachments);\n if (target) target.attachments = items;\n else messages.push({ id: uid('u'), role: 'user', text: '', streaming: false, attachments: items });\n emitMessages();\n } else if (ev.type === 'human_message') {\n // A human agent's reply from the console inbox (Phase 7 handoff) - render as a distinct bubble.\n // Dedup by turnId (shared with the `message` branch's seenTurnIds) - EventSource reconnect\n // replays the session's buffered events, and human_message turnIds (newId('tn')) are distinct\n // from message turnIds, so sharing the Set is safe.\n if (seenTurnIds.has(ev.turnId)) return;\n seenTurnIds.add(ev.turnId);\n messages.push({ id: uid('m'), role: 'human', text: ev.text, streaming: false });\n emitMessages();\n } else if (ev.type === 'visitor_message') {\n // Echo of the visitor's own message, published so the console inbox sees it live. The widget\n // already rendered this optimistically in sendMessage() - ignore the echo entirely.\n } else if (ev.type === 'state') {\n // Handoff status transition (Phase 7): 'ai' | 'awaiting_human' | 'human'. Ignore any other/\n // future state string - forward-compat, no status line for an unrecognized value.\n if (ev.state === 'ai' || ev.state === 'awaiting_human' || ev.state === 'human') {\n handoffState = ev.state;\n emit({ type: 'handoff', state: handoffState });\n }\n } else if (ev.type === 'agent_typing') {\n // Transient signal only - never pushed as a message, never touches dedup/streaming state.\n emit({ type: 'agentTyping', active: !!ev.active });\n }\n // 'done' and any future unknown types are ignored (forward-compat).\n };\n\n // Tickets are single-use and short-lived: a fresh one must be minted for every (re)connect.\n // Native EventSource auto-reconnect would retry the SAME url whose ticket is already consumed\n // (→ 401 forever), so on error we close it ourselves and drive reconnection here instead.\n const openStream = async () => {\n if (!session || closed) return;\n es?.close();\n const { ticket } = await mintStreamTicket({ baseUrl: options.baseUrl, sessionId: session.sessionId, sessionToken: session.sessionToken, fetchImpl });\n if (closed) return;\n es = new ES(streamUrl(options.baseUrl, session.sessionId, ticket));\n es.onopen = () => { reconnectAttempts = 0; };\n es.onmessage = (e: MessageEvent) => { try { onEvent(JSON.parse(e.data) as ChatEvent); } catch { /* ignore malformed */ } };\n es.onerror = () => { es?.close(); es = null; scheduleReconnect(); };\n };\n\n const scheduleReconnect = () => {\n if (closed) return;\n clearReconnect();\n const delay = Math.min(30_000, 500 * 2 ** reconnectAttempts);\n reconnectAttempts += 1;\n reconnectTimer = setTimeout(() => {\n openStream().catch((err) => {\n if (err instanceof ChatApiError && (err as ChatApiError).code === 'session_expired') {\n open().catch((e) => { emit({ type: 'error', error: e as Error }); scheduleReconnect(); });\n } else {\n scheduleReconnect();\n }\n });\n }, delay);\n };\n\n const open = async () => {\n session = await openSession({ baseUrl: options.baseUrl, apiKey: options.apiKey, agentId: options.agentId, user: options.user, clientTools: Array.from(toolHandlers.keys()), fetchImpl });\n emit({ type: 'agent', agent: session.agent });\n await openStream();\n };\n\n // Presign + PUT every file against the CURRENT session. Called from the main sendMessage path and,\n // after a session_expired reopen, from the retry — a storageRef presigned against the old\n // interactionId is rejected cross-session (403 attachment_cross_session) if reused post-reopen.\n const uploadFiles = async (files: File[]): Promise<ChatAttachmentDescriptor[]> => {\n return Promise.all(files.map(async (file): Promise<ChatAttachmentDescriptor> => {\n const { storageRef, uploadUrl } = await presignAttachment({ baseUrl: options.baseUrl, sessionId: session!.sessionId, sessionToken: session!.sessionToken, contentType: file.type, fetchImpl });\n await uploadToPresigned(uploadUrl, file, fetchImpl);\n return { storageRef, contentType: file.type, name: file.name };\n }));\n };\n\n return {\n getMessages: () => messages.slice(),\n getState: () => state,\n on(listener) { listeners.add(listener); return () => listeners.delete(listener); },\n registerTools(handlers) { for (const [name, fn] of Object.entries(handlers)) toolHandlers.set(name, fn); },\n async getAttachmentUrl(storageRef) {\n if (!session) throw new Error('call start() before getAttachmentUrl');\n return getAttachmentUrl({ baseUrl: options.baseUrl, sessionId: session.sessionId, sessionToken: session.sessionToken, storageRef, fetchImpl });\n },\n async start() {\n if (state !== 'idle') return;\n setState('opening');\n try { await open(); setState('ready'); }\n catch (err) { setState('error'); emit({ type: 'error', error: err as Error }); }\n },\n async sendMessage(text, files) {\n if (!session) { emit({ type: 'error', error: new Error('call start() before sendMessage') }); return; }\n const fileList = files ?? [];\n if (fileList.length > maxAttachments) {\n emit({ type: 'error', error: new Error(`too many attachments: max ${maxAttachments} per message`) });\n return;\n }\n const oversized = fileList.find((f) => f.size > maxAttachmentBytes);\n if (oversized) {\n emit({ type: 'error', error: new Error(`attachment too large: ${oversized.name} exceeds ${maxAttachmentBytes} bytes`) });\n return;\n }\n // Upload every file BEFORE posting the message or pushing the optimistic bubble — a failed\n // upload must never leave a broken/partial message in the thread.\n let attachments: ChatAttachmentDescriptor[] = [];\n if (fileList.length > 0) {\n try {\n attachments = await uploadFiles(fileList);\n } catch (err) {\n emit({ type: 'error', error: err as Error });\n return;\n }\n }\n messages.push({ id: uid('u'), role: 'user', text, streaming: false, attachments: attachments.length > 0 ? attachments : undefined }); emitMessages();\n try {\n await postMessage({ baseUrl: options.baseUrl, sessionId: session.sessionId, sessionToken: session.sessionToken, text, attachments, fetchImpl });\n } catch (err) {\n if (err instanceof ChatApiError && err.code === 'session_expired') {\n try {\n await open(); // fresh backend session, same UI thread\n // Re-upload against the NEW session — the old attachments' storageRefs are bound to the\n // stale interactionId and would 403 (attachment_cross_session) if re-posted as-is.\n const freshAttachments = fileList.length ? await uploadFiles(fileList) : [];\n await postMessage({ baseUrl: options.baseUrl, sessionId: session!.sessionId, sessionToken: session!.sessionToken, text, attachments: freshAttachments, fetchImpl });\n } catch (retryErr) {\n emit({ type: 'error', error: retryErr as Error });\n }\n } else { emit({ type: 'error', error: err as Error }); }\n }\n },\n async end() {\n closed = true; clearReconnect();\n if (session) await endSession({ baseUrl: options.baseUrl, sessionId: session.sessionId, sessionToken: session.sessionToken, fetchImpl });\n es?.close(); es = null; setState('ended');\n },\n };\n}\n","import { createChatClient, type ChatClient, type ChatMessage, type ChatClientState, type ChatToolHandler, type HandoffState } from './client';\nimport type { ChatAttachmentDescriptor } from './protocol';\n\nconst HANDOFF_STATUS_TEXT: Record<HandoffState, string | null> = {\n ai: null,\n awaiting_human: 'Connecting you to a person…',\n human: \"You're chatting with a person\",\n};\n\nconst ATTACHMENT_ACCEPT = 'image/*,application/pdf,text/plain,text/csv';\nconst AGENT_TYPING_TEXT = 'The agent is typing…';\n\nexport class OyehelloChatElement extends HTMLElement {\n static observedAttributes = ['api-key', 'agent-id', 'base-url', 'title'];\n private client: ChatClient | null = null;\n private off: (() => void) | null = null;\n private messages: ChatMessage[] = [];\n private state: ChatClientState = 'idle';\n private agentName: string | null = null;\n private handoffState: HandoffState = 'ai';\n // Transient \"agent is typing…\" affordance (Phase 7 followups) - never a message, only rendered\n // while a handoff is active (human/awaiting_human).\n private agentTyping = false;\n // Last connection/runtime error message (client emits an 'error' event on a failed start() or\n // send). Surfaced as a visible banner so a disabled composer always shows WHY, instead of sitting\n // dead. Cleared when the client reaches a healthy state again.\n private lastError: string | null = null;\n // registerTools() may be called before connectedCallback creates the client (e.g. right after\n // document.createElement, before the element is attached). Buffer until the client exists.\n private pendingTools: Record<string, ChatToolHandler> = {};\n // Files picked in the file input, staged until the form submits alongside the text.\n private pendingFiles: File[] = [];\n // Best-effort local thumbnail cache for images THIS widget instance just sent, keyed by filename -\n // an instant blob src, no round-trip needed.\n private imagePreviewCache = new Map<string, string>();\n // Read-back URLs resolved lazily (via client.getAttachmentUrl) for images with no local blob (a\n // reconnect, or an `attachment` SSE echo), keyed by storageRef. Cached across re-renders so the\n // same image isn't re-fetched on every render() call.\n private resolvedUrlCache = new Map<string, string>();\n\n connectedCallback() {\n if (!this.shadowRoot) this.attachShadow({ mode: 'open' });\n const apiKey = this.getAttribute('api-key');\n const agentId = this.getAttribute('agent-id');\n const baseUrl = this.getAttribute('base-url');\n if (!apiKey || !agentId || !baseUrl) { this.renderError('oyehello-chat: api-key, agent-id and base-url are required'); return; }\n this.client = createChatClient({ apiKey, agentId, baseUrl });\n if (Object.keys(this.pendingTools).length > 0) { this.client.registerTools(this.pendingTools); this.pendingTools = {}; }\n this.off = this.client.on((e) => {\n if (e.type === 'messages') this.messages = e.messages;\n else if (e.type === 'state') { this.state = e.state; if (e.state === 'ready' || e.state === 'opening') this.lastError = null; }\n else if (e.type === 'agent') this.agentName = e.agent.name;\n else if (e.type === 'handoff') this.handoffState = e.state;\n else if (e.type === 'agentTyping') this.agentTyping = e.active;\n else if (e.type === 'error') this.lastError = e.error.message;\n this.render();\n });\n this.render();\n void this.client.start();\n }\n disconnectedCallback() {\n this.off?.(); void this.client?.end();\n for (const url of this.imagePreviewCache.values()) { if (typeof URL.revokeObjectURL === 'function') URL.revokeObjectURL(url); }\n this.imagePreviewCache.clear();\n }\n\n registerTools(handlers: Record<string, ChatToolHandler>) {\n if (this.client) this.client.registerTools(handlers);\n else Object.assign(this.pendingTools, handlers);\n }\n\n private send(text: string, files: File[]) {\n if (!text.trim()) return;\n for (const f of files) {\n if (f.type.startsWith('image/') && typeof URL.createObjectURL === 'function' && !this.imagePreviewCache.has(f.name)) {\n this.imagePreviewCache.set(f.name, URL.createObjectURL(f));\n }\n }\n void this.client?.sendMessage(text, files.length > 0 ? files : undefined);\n }\n private renderError(msg: string) {\n if (!this.shadowRoot) this.attachShadow({ mode: 'open' });\n this.shadowRoot!.innerHTML = `<div style=\"color:#b91c1c;font:13px system-ui;padding:12px\">${escapeHtml(msg)}</div>`;\n }\n private renderAttachment(a: ChatAttachmentDescriptor): string {\n if (a.contentType.startsWith('image/')) {\n // Instant src when a local blob (just sent by this widget instance) or a previously-resolved\n // read-back URL is cached. Otherwise render the placeholder with a data-oc-ref marker and no\n // src attribute (an empty src=\"\" would make the browser (re)request the current page) -\n // hydrateAttachmentImages() resolves it lazily right after this markup is attached to the DOM.\n const cached = (a.name ? this.imagePreviewCache.get(a.name) : undefined) ?? this.resolvedUrlCache.get(a.storageRef);\n const srcAttr = cached ? ` src=\"${cached}\"` : '';\n return `<img class=\"att-thumb\" data-oc-ref=\"${escapeHtml(a.storageRef)}\"${srcAttr} alt=\"${escapeHtml(a.name ?? 'image')}\"/>`;\n }\n return `<div class=\"att-chip\">📎 ${escapeHtml(a.name ?? a.contentType)}</div>`;\n }\n private renderSource(s: { id: string; title: string; snippet: string }): string {\n return `<div class=\"src-chip\" title=\"${escapeHtml(s.snippet)}\">${escapeHtml(s.title)}</div>`;\n }\n\n // After render() attaches the markup, resolve a read-back URL (via the client) for every image\n // placeholder that has no src yet - a local blob or a previously-resolved URL already set one, so\n // those are left untouched (no redundant network call).\n private hydrateAttachmentImages() {\n if (!this.client) return;\n const imgs = this.shadowRoot!.querySelectorAll<HTMLImageElement>('img.att-thumb[data-oc-ref]');\n imgs.forEach((img) => {\n if (img.hasAttribute('src')) return;\n const ref = img.getAttribute('data-oc-ref');\n if (!ref) return;\n void this.client!.getAttachmentUrl(ref)\n .then((url) => { this.resolvedUrlCache.set(ref, url); img.src = url; })\n .catch(() => { /* leave unresolved - no thumbnail is an acceptable degrade, not fatal */ });\n });\n }\n\n private render() {\n const title = this.getAttribute('title') ?? this.agentName ?? 'Chat';\n const bubbles = this.messages.map((m) => {\n const atts = (m.attachments ?? []).map((a) => this.renderAttachment(a)).join('');\n const label = m.role === 'human' ? '<div class=\"human-label\">Support</div>' : '';\n const bubble = `<div class=\"b ${m.role}\">${label}${atts}${m.text ? escapeHtml(m.text) : ''}${m.streaming ? '…' : ''}</div>`;\n const sources = m.sources && m.sources.length > 0 ? `<div class=\"src-row\">${m.sources.map((s) => this.renderSource(s)).join('')}</div>` : '';\n return bubble + sources;\n }).join('');\n const statusText = HANDOFF_STATUS_TEXT[this.handoffState];\n const status = statusText ? `<div class=\"status\">${escapeHtml(statusText)}</div>` : '';\n const errBanner = this.state === 'error' && this.lastError\n ? `<div class=\"err\">Couldn't start chat: ${escapeHtml(this.lastError)}</div>`\n : '';\n const showTyping = this.agentTyping && (this.handoffState === 'human' || this.handoffState === 'awaiting_human');\n const typingIndicator = showTyping ? `<div class=\"b assistant typing\">${escapeHtml(AGENT_TYPING_TEXT)}</div>` : '';\n const disabled = this.state !== 'ready' ? 'disabled' : '';\n // Rebuilding innerHTML replaces the input node, which would otherwise drop the user's\n // in-progress text + caret on every streamed token. Capture and restore across the rebuild.\n const prevInput = this.shadowRoot!.querySelector<HTMLInputElement>('input[aria-label=\"message\"]');\n const prevValue = prevInput?.value ?? '';\n const prevSelectionStart = prevInput?.selectionStart ?? null;\n const prevSelectionEnd = prevInput?.selectionEnd ?? null;\n const hadFocus = !!prevInput && this.shadowRoot!.activeElement === prevInput;\n this.shadowRoot!.innerHTML = `\n <style>\n :host{display:block;height:100%;min-height:320px;font-family:system-ui,sans-serif;--oc-accent:#2563eb}\n .wrap{display:flex;flex-direction:column;height:100%;border:1px solid #e5e7eb;border-radius:12px;overflow:hidden}\n .hd{padding:10px 14px;border-bottom:1px solid #e5e7eb;font-weight:600}\n .body{flex:1;overflow-y:auto;padding:12px;display:flex;flex-direction:column;gap:8px}\n .b{max-width:80%;padding:8px 12px;border-radius:12px;white-space:pre-wrap;word-break:break-word}\n .b.user{align-self:flex-end;background:var(--oc-accent);color:#fff}\n .b.assistant{align-self:flex-start;background:#f3f4f6;color:#111}\n .b.human{align-self:flex-start;background:#dbeafe;color:#111}\n .b.typing{font-style:italic;color:#6b7280;opacity:.85}\n .human-label{font-size:11px;font-weight:600;opacity:.7;margin-bottom:2px}\n .status{padding:6px 14px;font-size:12px;color:#6b7280;background:#f9fafb;border-bottom:1px solid #e5e7eb}\n .err{padding:8px 14px;font-size:12px;color:#b91c1c;background:#fef2f2;border-bottom:1px solid #fecaca}\n .att-thumb{display:block;max-width:160px;max-height:160px;border-radius:8px;margin-bottom:6px}\n .att-chip{display:inline-block;font-size:12px;background:rgba(0,0,0,.08);border-radius:6px;padding:2px 8px;margin:0 0 6px}\n .b.user .att-chip{background:rgba(255,255,255,.25)}\n .src-row{align-self:flex-start;display:flex;flex-wrap:wrap;gap:6px;max-width:80%}\n .src-chip{display:inline-block;font-size:11px;background:rgba(0,0,0,.06);color:#374151;border-radius:6px;padding:2px 8px;cursor:default}\n form{display:flex;gap:8px;padding:10px;border-top:1px solid #e5e7eb;align-items:center}\n input[aria-label=\"message\"]{flex:1;padding:8px 10px;border-radius:8px;border:1px solid #d1d5db;font:inherit}\n input[type=\"file\"]{max-width:120px;font-size:12px}\n button{padding:8px 14px;border-radius:8px;border:none;background:var(--oc-accent);color:#fff;font-weight:600;cursor:pointer}\n button:disabled,input:disabled{opacity:.6;cursor:not-allowed}\n </style>\n <div class=\"wrap\">\n <div class=\"hd\">${escapeHtml(title)}</div>\n ${status}${errBanner}\n <div class=\"body\">${bubbles}${typingIndicator}</div>\n <form>\n <input aria-label=\"message\" placeholder=\"Type a message…\" ${disabled}/>\n <input type=\"file\" accept=\"${ATTACHMENT_ACCEPT}\" multiple ${disabled}/>\n <button type=\"submit\" ${disabled}>Send</button>\n </form>\n </div>`;\n const form = this.shadowRoot!.querySelector('form')!;\n const input = this.shadowRoot!.querySelector<HTMLInputElement>('input[aria-label=\"message\"]')!;\n const fileInput = this.shadowRoot!.querySelector<HTMLInputElement>('input[type=\"file\"]')!;\n fileInput.addEventListener('change', () => { this.pendingFiles = fileInput.files ? Array.from(fileInput.files) : []; });\n form.addEventListener('submit', (e) => {\n e.preventDefault();\n const files = this.pendingFiles;\n this.pendingFiles = [];\n this.send(input.value, files);\n input.value = '';\n });\n if (prevValue) {\n input.value = prevValue;\n if (prevSelectionStart !== null && prevSelectionEnd !== null) input.setSelectionRange(prevSelectionStart, prevSelectionEnd);\n }\n if (hadFocus) input.focus();\n const body = this.shadowRoot!.querySelector('.body')!;\n body.scrollTop = body.scrollHeight;\n this.hydrateAttachmentImages();\n }\n}\nfunction escapeHtml(s: string) { return s.replace(/[&<>\"]/g, (c) => ({ '&': '&amp;', '<': '&lt;', '>': '&gt;', '\"': '&quot;' }[c]!)); }\n","export { ChatApiError } from './errors';\nexport type { ChatEvent, OpenSessionResponse, ChatClientOptions, ChatAttachmentDescriptor } from './protocol';\nexport { createChatClient } from './client';\nexport type { ChatClient, ChatMessage, ChatClientState, ChatClientEvent, ChatToolHandler } from './client';\nexport { OyehelloChatElement } from './element';\n\nimport { OyehelloChatElement } from './element';\n// Side effect: registering the element is why the package is sideEffects:true.\nif (typeof customElements !== 'undefined' && !customElements.get('oyehello-chat')) {\n customElements.define('oyehello-chat', OyehelloChatElement);\n}\n"]}
package/dist/index.js CHANGED
@@ -103,7 +103,7 @@ async function uploadToPresigned(uploadUrl, file, fetchImpl) {
103
103
  var seq = 0;
104
104
  var uid = (p) => `${p}_${Date.now().toString(36)}_${(seq++).toString(36)}`;
105
105
  function createChatClient(options) {
106
- const fetchImpl = options.fetch ?? globalThis.fetch;
106
+ const fetchImpl = options.fetch ?? globalThis.fetch.bind(globalThis);
107
107
  const ES = options.eventSource ?? globalThis.EventSource;
108
108
  const maxAttachments = options.maxAttachments ?? 4;
109
109
  const maxAttachmentBytes = options.maxAttachmentBytes ?? 1e7;
@@ -361,6 +361,10 @@ var OyehelloChatElement = class extends HTMLElement {
361
361
  // Transient "agent is typing…" affordance (Phase 7 followups) - never a message, only rendered
362
362
  // while a handoff is active (human/awaiting_human).
363
363
  agentTyping = false;
364
+ // Last connection/runtime error message (client emits an 'error' event on a failed start() or
365
+ // send). Surfaced as a visible banner so a disabled composer always shows WHY, instead of sitting
366
+ // dead. Cleared when the client reaches a healthy state again.
367
+ lastError = null;
364
368
  // registerTools() may be called before connectedCallback creates the client (e.g. right after
365
369
  // document.createElement, before the element is attached). Buffer until the client exists.
366
370
  pendingTools = {};
@@ -389,10 +393,13 @@ var OyehelloChatElement = class extends HTMLElement {
389
393
  }
390
394
  this.off = this.client.on((e) => {
391
395
  if (e.type === "messages") this.messages = e.messages;
392
- else if (e.type === "state") this.state = e.state;
393
- else if (e.type === "agent") this.agentName = e.agent.name;
396
+ else if (e.type === "state") {
397
+ this.state = e.state;
398
+ if (e.state === "ready" || e.state === "opening") this.lastError = null;
399
+ } else if (e.type === "agent") this.agentName = e.agent.name;
394
400
  else if (e.type === "handoff") this.handoffState = e.state;
395
401
  else if (e.type === "agentTyping") this.agentTyping = e.active;
402
+ else if (e.type === "error") this.lastError = e.error.message;
396
403
  this.render();
397
404
  });
398
405
  this.render();
@@ -462,6 +469,7 @@ var OyehelloChatElement = class extends HTMLElement {
462
469
  }).join("");
463
470
  const statusText = HANDOFF_STATUS_TEXT[this.handoffState];
464
471
  const status = statusText ? `<div class="status">${escapeHtml(statusText)}</div>` : "";
472
+ const errBanner = this.state === "error" && this.lastError ? `<div class="err">Couldn't start chat: ${escapeHtml(this.lastError)}</div>` : "";
465
473
  const showTyping = this.agentTyping && (this.handoffState === "human" || this.handoffState === "awaiting_human");
466
474
  const typingIndicator = showTyping ? `<div class="b assistant typing">${escapeHtml(AGENT_TYPING_TEXT)}</div>` : "";
467
475
  const disabled = this.state !== "ready" ? "disabled" : "";
@@ -483,6 +491,7 @@ var OyehelloChatElement = class extends HTMLElement {
483
491
  .b.typing{font-style:italic;color:#6b7280;opacity:.85}
484
492
  .human-label{font-size:11px;font-weight:600;opacity:.7;margin-bottom:2px}
485
493
  .status{padding:6px 14px;font-size:12px;color:#6b7280;background:#f9fafb;border-bottom:1px solid #e5e7eb}
494
+ .err{padding:8px 14px;font-size:12px;color:#b91c1c;background:#fef2f2;border-bottom:1px solid #fecaca}
486
495
  .att-thumb{display:block;max-width:160px;max-height:160px;border-radius:8px;margin-bottom:6px}
487
496
  .att-chip{display:inline-block;font-size:12px;background:rgba(0,0,0,.08);border-radius:6px;padding:2px 8px;margin:0 0 6px}
488
497
  .b.user .att-chip{background:rgba(255,255,255,.25)}
@@ -496,7 +505,7 @@ var OyehelloChatElement = class extends HTMLElement {
496
505
  </style>
497
506
  <div class="wrap">
498
507
  <div class="hd">${escapeHtml(title)}</div>
499
- ${status}
508
+ ${status}${errBanner}
500
509
  <div class="body">${bubbles}${typingIndicator}</div>
501
510
  <form>
502
511
  <input aria-label="message" placeholder="Type a message\u2026" ${disabled}/>
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/errors.ts","../src/transport.ts","../src/client.ts","../src/element.ts","../src/index.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["export class ChatApiError extends Error {\n constructor(message: string, readonly status: number, readonly code?: string, readonly meta?: Record<string, unknown>) {\n super(message);\n this.name = 'ChatApiError';\n }\n}\n","import { ChatApiError } from './errors';\nimport type { ChatAttachmentDescriptor, OpenSessionResponse, StreamTicket } from './protocol';\n\nasync function asError(res: Response, fallbackCode?: string): Promise<ChatApiError> {\n let body: { error?: string; code?: string; meta?: Record<string, unknown> } = {};\n try { body = (await res.json()) as { error?: string; code?: string; meta?: Record<string, unknown> }; } catch { /* non-json */ }\n return new ChatApiError(body.error ?? `HTTP ${res.status}`, res.status, body.code ?? fallbackCode, body.meta);\n}\n\nexport async function openSession(opts: { baseUrl: string; apiKey: string; agentId: string; user?: { id?: string }; clientTools?: string[]; fetchImpl: typeof fetch }): Promise<OpenSessionResponse> {\n const body: Record<string, unknown> = { agentId: opts.agentId };\n if (opts.user) body.user = opts.user;\n if (opts.clientTools && opts.clientTools.length > 0) body.clientTools = opts.clientTools;\n const res = await opts.fetchImpl(`${opts.baseUrl}/chat/sessions`, {\n method: 'POST', credentials: 'omit',\n headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${opts.apiKey}` },\n body: JSON.stringify(body),\n });\n if (!res.ok) throw await asError(res);\n return (await res.json()) as OpenSessionResponse;\n}\n\nexport async function postMessage(opts: { baseUrl: string; sessionId: string; sessionToken: string; text: string; attachments?: ChatAttachmentDescriptor[]; fetchImpl: typeof fetch }): Promise<void> {\n const body: Record<string, unknown> = { text: opts.text };\n if (opts.attachments && opts.attachments.length > 0) body.attachments = opts.attachments;\n const res = await opts.fetchImpl(`${opts.baseUrl}/chat/sessions/${opts.sessionId}/messages`, {\n method: 'POST', credentials: 'omit',\n headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${opts.sessionToken}` },\n body: JSON.stringify(body),\n });\n // A 401 here means the 15-min session token expired (no refresh endpoint) — surface a stable code\n // so the client can transparently re-open a session and retry.\n if (!res.ok) throw await asError(res, res.status === 401 ? 'session_expired' : undefined);\n}\n\nexport async function endSession(opts: { baseUrl: string; sessionId: string; sessionToken: string; fetchImpl: typeof fetch }): Promise<void> {\n await opts.fetchImpl(`${opts.baseUrl}/chat/sessions/${opts.sessionId}/end`, {\n method: 'POST', credentials: 'omit',\n headers: { Authorization: `Bearer ${opts.sessionToken}` },\n }).catch(() => {}); // best-effort teardown\n}\n\nexport async function postToolResult(opts: { baseUrl: string; sessionId: string; sessionToken: string; callId: string; ok: boolean; result: unknown; fetchImpl: typeof fetch }): Promise<void> {\n await opts.fetchImpl(`${opts.baseUrl}/chat/sessions/${opts.sessionId}/tool-results`, {\n method: 'POST', credentials: 'omit',\n headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${opts.sessionToken}` },\n body: JSON.stringify({ callId: opts.callId, ok: opts.ok, result: opts.result }),\n }).catch(() => {}); // best-effort; a dropped result times out server-side and the model recovers\n}\n\nexport async function mintStreamTicket(opts: { baseUrl: string; sessionId: string; sessionToken: string; fetchImpl: typeof fetch }): Promise<StreamTicket> {\n const res = await opts.fetchImpl(`${opts.baseUrl}/chat/sessions/${opts.sessionId}/stream-ticket`, {\n method: 'POST', credentials: 'omit',\n headers: { Authorization: `Bearer ${opts.sessionToken}` },\n });\n // A 401 here means the session token is invalid/expired — surface a stable code so the client\n // can distinguish this from a transient failure (mirrors postMessage's 401 mapping).\n if (!res.ok) throw await asError(res, res.status === 401 ? 'session_expired' : undefined);\n return (await res.json()) as StreamTicket;\n}\n\nexport function streamUrl(baseUrl: string, sessionId: string, ticket: string): string {\n return `${baseUrl}/chat/sessions/${sessionId}/stream?ticket=${encodeURIComponent(ticket)}`;\n}\n\n// POST /chat/sessions/:id/attachments — mints a presigned S3 PUT for a visitor upload. Bearer session\n// token auth, mirrors mintStreamTicket's shape/error-mapping exactly.\nexport async function presignAttachment(opts: { baseUrl: string; sessionId: string; sessionToken: string; contentType: string; fetchImpl: typeof fetch }): Promise<{ storageRef: string; uploadUrl: string }> {\n const res = await opts.fetchImpl(`${opts.baseUrl}/chat/sessions/${opts.sessionId}/attachments`, {\n method: 'POST', credentials: 'omit',\n headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${opts.sessionToken}` },\n body: JSON.stringify({ contentType: opts.contentType }),\n });\n // A 401 here means the session token is invalid/expired — surface a stable code so the client\n // can distinguish this from a transient failure (mirrors postMessage's 401 mapping).\n if (!res.ok) throw await asError(res, res.status === 401 ? 'session_expired' : undefined);\n return (await res.json()) as { storageRef: string; uploadUrl: string };\n}\n\n// POST /chat/sessions/:id/attachment-url — mints a presigned S3 GET so an already-uploaded\n// attachment can be read back (e.g. rendering an image thumbnail on reconnect, when no local blob\n// is cached). Bearer session token auth, mirrors presignAttachment's shape/error-mapping exactly.\nexport async function getAttachmentUrl(opts: { baseUrl: string; sessionId: string; sessionToken: string; storageRef: string; fetchImpl: typeof fetch }): Promise<string> {\n const res = await opts.fetchImpl(`${opts.baseUrl}/chat/sessions/${opts.sessionId}/attachment-url`, {\n method: 'POST', credentials: 'omit',\n headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${opts.sessionToken}` },\n body: JSON.stringify({ storageRef: opts.storageRef }),\n });\n // A 401 here means the session token is invalid/expired — surface a stable code so the client\n // can distinguish this from a transient failure (mirrors postMessage's 401 mapping).\n if (!res.ok) throw await asError(res, res.status === 401 ? 'session_expired' : undefined);\n return ((await res.json()) as { url: string }).url;\n}\n\n// Uploads a file directly to the presigned S3 URL. The URL is already absolute and fully signed —\n// NO baseUrl prefix, NO Authorization header (would break the signature), just a bare PUT with the\n// file's own content type (Task 4 dropped SSE from the presign so this needs no extra headers).\nexport async function uploadToPresigned(uploadUrl: string, file: File, fetchImpl: typeof fetch): Promise<void> {\n const res = await fetchImpl(uploadUrl, { method: 'PUT', body: file, headers: { 'Content-Type': file.type } });\n if (!res.ok) throw new ChatApiError(`attachment upload failed with HTTP ${res.status}`, res.status);\n}\n","import { openSession, postMessage, endSession, streamUrl, mintStreamTicket, postToolResult, presignAttachment, uploadToPresigned, getAttachmentUrl } from './transport';\nimport { ChatApiError } from './errors';\nimport type { ChatAttachmentDescriptor, ChatClientOptions, ChatEvent, OpenSessionResponse } from './protocol';\n\nexport interface ChatMessage { id: string; role: 'user' | 'assistant' | 'human'; text: string; streaming: boolean; attachments?: ChatAttachmentDescriptor[]; sources?: { id: string; title: string; snippet: string }[]; turnId?: string }\nexport type ChatClientState = 'idle' | 'opening' | 'ready' | 'ended' | 'error';\n// Handoff status of the session, driven by the backend's `state` SSE event (Phase 7). 'ai' = the\n// AI is answering (default/no handoff), 'awaiting_human' = a handoff was requested and no human\n// has taken over yet, 'human' = a human agent is answering.\nexport type HandoffState = 'ai' | 'awaiting_human' | 'human';\nexport type ChatClientEvent =\n | { type: 'state'; state: ChatClientState }\n | { type: 'messages'; messages: ChatMessage[] }\n | { type: 'error'; error: Error }\n | { type: 'agent'; agent: { id: string; name: string } }\n // Handoff status changed (Phase 7) - the widget uses this to show a status line.\n | { type: 'handoff'; state: HandoffState }\n // A human agent is (or stopped) typing in the console during a handoff (Phase 7 followups). The\n // widget uses this to show a transient \"agent is typing…\" affordance - never a message.\n | { type: 'agentTyping'; active: boolean };\nexport type ChatToolHandler = (args: Record<string, unknown>) => unknown | Promise<unknown>;\nexport interface ChatClient {\n start(): Promise<void>;\n sendMessage(text: string, files?: File[]): Promise<void>;\n end(): Promise<void>;\n getMessages(): ChatMessage[];\n getState(): ChatClientState;\n on(listener: (e: ChatClientEvent) => void): () => void;\n // Register browser-side tool handlers the server may call mid-conversation. Register BEFORE\n // start() — the handler names are sent as `clientTools` on session open so the server knows\n // which tools this session can execute.\n registerTools(handlers: Record<string, ChatToolHandler>): void;\n // Resolves a read-back URL for an already-uploaded attachment (e.g. an image thumbnail with no\n // local blob cached — a reconnect, or an `attachment` SSE echo). Requires start() to have been\n // called (a live session).\n getAttachmentUrl(storageRef: string): Promise<string>;\n}\n\nlet seq = 0;\nconst uid = (p: string) => `${p}_${Date.now().toString(36)}_${(seq++).toString(36)}`;\n\nexport function createChatClient(options: ChatClientOptions): ChatClient {\n const fetchImpl = options.fetch ?? globalThis.fetch;\n const ES = options.eventSource ?? globalThis.EventSource;\n // Mirrors the server's CHAT_ATTACHMENT_MAX_PER_MESSAGE default (apps/api/src/config/env.ts).\n const maxAttachments = options.maxAttachments ?? 4;\n // Mirrors the server's CHAT_ATTACHMENT_MAX_BYTES default (apps/api/src/config/env.ts). UX-only\n // fast pre-check - the server is authoritative (message-time HeadObject size enforcement).\n const maxAttachmentBytes = options.maxAttachmentBytes ?? 10_000_000;\n const listeners = new Set<(e: ChatClientEvent) => void>();\n let state: ChatClientState = 'idle';\n const messages: ChatMessage[] = [];\n let streamingId: string | null = null;\n let session: OpenSessionResponse | null = null;\n let es: EventSource | null = null;\n const seenTurnIds = new Set<string>();\n const seenCallIds = new Set<string>();\n let handoffState: HandoffState = 'ai';\n let reconnectTimer: ReturnType<typeof setTimeout> | null = null;\n let reconnectAttempts = 0;\n let closed = false;\n const toolHandlers = new Map<string, ChatToolHandler>();\n const clearReconnect = () => { if (reconnectTimer) { clearTimeout(reconnectTimer); reconnectTimer = null; } };\n\n const emit = (e: ChatClientEvent) => { for (const l of listeners) l(e); };\n const setState = (s: ChatClientState) => { state = s; emit({ type: 'state', state: s }); };\n const emitMessages = () => emit({ type: 'messages', messages: messages.slice() });\n\n const onEvent = (ev: ChatEvent) => {\n if (ev.type === 'token') {\n let m = streamingId ? messages.find((x) => x.id === streamingId) : undefined;\n if (!m) { m = { id: uid('m'), role: 'assistant', text: '', streaming: true }; messages.push(m); streamingId = m.id; }\n m.text += ev.text; emitMessages();\n } else if (ev.type === 'message') {\n if (seenTurnIds.has(ev.turnId)) {\n // Replay of an already-finalized turn (EventSource reconnect replays the session's\n // event buffer). Discard it, and drop any partial streaming bubble its replayed\n // tokens built up, without emitting a duplicate assistant message.\n if (streamingId) {\n const idx = messages.findIndex((x) => x.id === streamingId);\n if (idx !== -1) messages.splice(idx, 1);\n streamingId = null;\n emitMessages();\n }\n return;\n }\n seenTurnIds.add(ev.turnId);\n const m = streamingId ? messages.find((x) => x.id === streamingId) : undefined;\n if (m) { m.text = ev.text; m.streaming = false; m.turnId = ev.turnId; } else { messages.push({ id: uid('m'), role: 'assistant', text: ev.text, streaming: false, turnId: ev.turnId }); }\n streamingId = null; emitMessages();\n } else if (ev.type === 'citations') {\n // Arrives AFTER `message` (streamingId already cleared) so the target message is located by\n // the turnId stamped above, not by streamingId. Ignore an unknown turnId (reconnect-safe: a\n // stale/duplicate citations replay for a turn we don't have never crashes or creates a bubble).\n const m = messages.find((x) => x.turnId === ev.turnId);\n if (m) { m.sources = ev.sources; emitMessages(); }\n } else if (ev.type === 'error') {\n emit({ type: 'error', error: new Error(ev.message) });\n } else if (ev.type === 'tool_call') {\n if (seenCallIds.has(ev.callId)) return; // replayed on EventSource reconnect — dispatch once\n seenCallIds.add(ev.callId);\n const handler = toolHandlers.get(ev.name);\n void (async () => {\n if (!session) return;\n const base = { baseUrl: options.baseUrl, sessionId: session.sessionId, sessionToken: session.sessionToken, callId: ev.callId, fetchImpl };\n if (!handler) {\n await postToolResult({ ...base, ok: false, result: `no handler registered for ${ev.name}` });\n return;\n }\n try {\n const out = await handler(ev.args);\n await postToolResult({ ...base, ok: true, result: typeof out === 'string' ? out : JSON.stringify(out ?? { ok: true }) });\n } catch (err) {\n await postToolResult({ ...base, ok: false, result: (err as Error).message });\n }\n })();\n } else if (ev.type === 'attachment') {\n // The runtime re-publishes a visitor's message attachments over this event (Phase 5\n // follow-up) so a reconnecting client (buffer replay) or a future second viewer can render\n // them, now that a read-back URL exists (getAttachmentUrl / element.ts's lazy image src).\n // Hardened so it can never double-render on the SENDING client itself, which already rendered\n // these optimistically from its own sendMessage(): if any existing message already carries an\n // attachment with one of these storageRefs, the event is a stale/duplicate echo of something\n // already rendered — ignore it entirely instead of guessing which message to attach to (a\n // \"most recent attachment-less user message\" heuristic misattaches when a second image-first\n // message is sent before the echo of the first one arrives).\n const items = ev.items;\n const alreadyRendered = messages.some((m) => m.attachments?.some((a) => items.some((i) => i.storageRef === a.storageRef)));\n if (alreadyRendered) return;\n const target = [...messages].reverse().find((m) => m.role === 'user' && !m.attachments);\n if (target) target.attachments = items;\n else messages.push({ id: uid('u'), role: 'user', text: '', streaming: false, attachments: items });\n emitMessages();\n } else if (ev.type === 'human_message') {\n // A human agent's reply from the console inbox (Phase 7 handoff) - render as a distinct bubble.\n // Dedup by turnId (shared with the `message` branch's seenTurnIds) - EventSource reconnect\n // replays the session's buffered events, and human_message turnIds (newId('tn')) are distinct\n // from message turnIds, so sharing the Set is safe.\n if (seenTurnIds.has(ev.turnId)) return;\n seenTurnIds.add(ev.turnId);\n messages.push({ id: uid('m'), role: 'human', text: ev.text, streaming: false });\n emitMessages();\n } else if (ev.type === 'visitor_message') {\n // Echo of the visitor's own message, published so the console inbox sees it live. The widget\n // already rendered this optimistically in sendMessage() - ignore the echo entirely.\n } else if (ev.type === 'state') {\n // Handoff status transition (Phase 7): 'ai' | 'awaiting_human' | 'human'. Ignore any other/\n // future state string - forward-compat, no status line for an unrecognized value.\n if (ev.state === 'ai' || ev.state === 'awaiting_human' || ev.state === 'human') {\n handoffState = ev.state;\n emit({ type: 'handoff', state: handoffState });\n }\n } else if (ev.type === 'agent_typing') {\n // Transient signal only - never pushed as a message, never touches dedup/streaming state.\n emit({ type: 'agentTyping', active: !!ev.active });\n }\n // 'done' and any future unknown types are ignored (forward-compat).\n };\n\n // Tickets are single-use and short-lived: a fresh one must be minted for every (re)connect.\n // Native EventSource auto-reconnect would retry the SAME url whose ticket is already consumed\n // (→ 401 forever), so on error we close it ourselves and drive reconnection here instead.\n const openStream = async () => {\n if (!session || closed) return;\n es?.close();\n const { ticket } = await mintStreamTicket({ baseUrl: options.baseUrl, sessionId: session.sessionId, sessionToken: session.sessionToken, fetchImpl });\n if (closed) return;\n es = new ES(streamUrl(options.baseUrl, session.sessionId, ticket));\n es.onopen = () => { reconnectAttempts = 0; };\n es.onmessage = (e: MessageEvent) => { try { onEvent(JSON.parse(e.data) as ChatEvent); } catch { /* ignore malformed */ } };\n es.onerror = () => { es?.close(); es = null; scheduleReconnect(); };\n };\n\n const scheduleReconnect = () => {\n if (closed) return;\n clearReconnect();\n const delay = Math.min(30_000, 500 * 2 ** reconnectAttempts);\n reconnectAttempts += 1;\n reconnectTimer = setTimeout(() => {\n openStream().catch((err) => {\n if (err instanceof ChatApiError && (err as ChatApiError).code === 'session_expired') {\n open().catch((e) => { emit({ type: 'error', error: e as Error }); scheduleReconnect(); });\n } else {\n scheduleReconnect();\n }\n });\n }, delay);\n };\n\n const open = async () => {\n session = await openSession({ baseUrl: options.baseUrl, apiKey: options.apiKey, agentId: options.agentId, user: options.user, clientTools: Array.from(toolHandlers.keys()), fetchImpl });\n emit({ type: 'agent', agent: session.agent });\n await openStream();\n };\n\n // Presign + PUT every file against the CURRENT session. Called from the main sendMessage path and,\n // after a session_expired reopen, from the retry — a storageRef presigned against the old\n // interactionId is rejected cross-session (403 attachment_cross_session) if reused post-reopen.\n const uploadFiles = async (files: File[]): Promise<ChatAttachmentDescriptor[]> => {\n return Promise.all(files.map(async (file): Promise<ChatAttachmentDescriptor> => {\n const { storageRef, uploadUrl } = await presignAttachment({ baseUrl: options.baseUrl, sessionId: session!.sessionId, sessionToken: session!.sessionToken, contentType: file.type, fetchImpl });\n await uploadToPresigned(uploadUrl, file, fetchImpl);\n return { storageRef, contentType: file.type, name: file.name };\n }));\n };\n\n return {\n getMessages: () => messages.slice(),\n getState: () => state,\n on(listener) { listeners.add(listener); return () => listeners.delete(listener); },\n registerTools(handlers) { for (const [name, fn] of Object.entries(handlers)) toolHandlers.set(name, fn); },\n async getAttachmentUrl(storageRef) {\n if (!session) throw new Error('call start() before getAttachmentUrl');\n return getAttachmentUrl({ baseUrl: options.baseUrl, sessionId: session.sessionId, sessionToken: session.sessionToken, storageRef, fetchImpl });\n },\n async start() {\n if (state !== 'idle') return;\n setState('opening');\n try { await open(); setState('ready'); }\n catch (err) { setState('error'); emit({ type: 'error', error: err as Error }); }\n },\n async sendMessage(text, files) {\n if (!session) { emit({ type: 'error', error: new Error('call start() before sendMessage') }); return; }\n const fileList = files ?? [];\n if (fileList.length > maxAttachments) {\n emit({ type: 'error', error: new Error(`too many attachments: max ${maxAttachments} per message`) });\n return;\n }\n const oversized = fileList.find((f) => f.size > maxAttachmentBytes);\n if (oversized) {\n emit({ type: 'error', error: new Error(`attachment too large: ${oversized.name} exceeds ${maxAttachmentBytes} bytes`) });\n return;\n }\n // Upload every file BEFORE posting the message or pushing the optimistic bubble — a failed\n // upload must never leave a broken/partial message in the thread.\n let attachments: ChatAttachmentDescriptor[] = [];\n if (fileList.length > 0) {\n try {\n attachments = await uploadFiles(fileList);\n } catch (err) {\n emit({ type: 'error', error: err as Error });\n return;\n }\n }\n messages.push({ id: uid('u'), role: 'user', text, streaming: false, attachments: attachments.length > 0 ? attachments : undefined }); emitMessages();\n try {\n await postMessage({ baseUrl: options.baseUrl, sessionId: session.sessionId, sessionToken: session.sessionToken, text, attachments, fetchImpl });\n } catch (err) {\n if (err instanceof ChatApiError && err.code === 'session_expired') {\n try {\n await open(); // fresh backend session, same UI thread\n // Re-upload against the NEW session — the old attachments' storageRefs are bound to the\n // stale interactionId and would 403 (attachment_cross_session) if re-posted as-is.\n const freshAttachments = fileList.length ? await uploadFiles(fileList) : [];\n await postMessage({ baseUrl: options.baseUrl, sessionId: session!.sessionId, sessionToken: session!.sessionToken, text, attachments: freshAttachments, fetchImpl });\n } catch (retryErr) {\n emit({ type: 'error', error: retryErr as Error });\n }\n } else { emit({ type: 'error', error: err as Error }); }\n }\n },\n async end() {\n closed = true; clearReconnect();\n if (session) await endSession({ baseUrl: options.baseUrl, sessionId: session.sessionId, sessionToken: session.sessionToken, fetchImpl });\n es?.close(); es = null; setState('ended');\n },\n };\n}\n","import { createChatClient, type ChatClient, type ChatMessage, type ChatClientState, type ChatToolHandler, type HandoffState } from './client';\nimport type { ChatAttachmentDescriptor } from './protocol';\n\nconst HANDOFF_STATUS_TEXT: Record<HandoffState, string | null> = {\n ai: null,\n awaiting_human: 'Connecting you to a person…',\n human: \"You're chatting with a person\",\n};\n\nconst ATTACHMENT_ACCEPT = 'image/*,application/pdf,text/plain,text/csv';\nconst AGENT_TYPING_TEXT = 'The agent is typing…';\n\nexport class OyehelloChatElement extends HTMLElement {\n static observedAttributes = ['api-key', 'agent-id', 'base-url', 'title'];\n private client: ChatClient | null = null;\n private off: (() => void) | null = null;\n private messages: ChatMessage[] = [];\n private state: ChatClientState = 'idle';\n private agentName: string | null = null;\n private handoffState: HandoffState = 'ai';\n // Transient \"agent is typing…\" affordance (Phase 7 followups) - never a message, only rendered\n // while a handoff is active (human/awaiting_human).\n private agentTyping = false;\n // registerTools() may be called before connectedCallback creates the client (e.g. right after\n // document.createElement, before the element is attached). Buffer until the client exists.\n private pendingTools: Record<string, ChatToolHandler> = {};\n // Files picked in the file input, staged until the form submits alongside the text.\n private pendingFiles: File[] = [];\n // Best-effort local thumbnail cache for images THIS widget instance just sent, keyed by filename -\n // an instant blob src, no round-trip needed.\n private imagePreviewCache = new Map<string, string>();\n // Read-back URLs resolved lazily (via client.getAttachmentUrl) for images with no local blob (a\n // reconnect, or an `attachment` SSE echo), keyed by storageRef. Cached across re-renders so the\n // same image isn't re-fetched on every render() call.\n private resolvedUrlCache = new Map<string, string>();\n\n connectedCallback() {\n if (!this.shadowRoot) this.attachShadow({ mode: 'open' });\n const apiKey = this.getAttribute('api-key');\n const agentId = this.getAttribute('agent-id');\n const baseUrl = this.getAttribute('base-url');\n if (!apiKey || !agentId || !baseUrl) { this.renderError('oyehello-chat: api-key, agent-id and base-url are required'); return; }\n this.client = createChatClient({ apiKey, agentId, baseUrl });\n if (Object.keys(this.pendingTools).length > 0) { this.client.registerTools(this.pendingTools); this.pendingTools = {}; }\n this.off = this.client.on((e) => {\n if (e.type === 'messages') this.messages = e.messages;\n else if (e.type === 'state') this.state = e.state;\n else if (e.type === 'agent') this.agentName = e.agent.name;\n else if (e.type === 'handoff') this.handoffState = e.state;\n else if (e.type === 'agentTyping') this.agentTyping = e.active;\n this.render();\n });\n this.render();\n void this.client.start();\n }\n disconnectedCallback() {\n this.off?.(); void this.client?.end();\n for (const url of this.imagePreviewCache.values()) { if (typeof URL.revokeObjectURL === 'function') URL.revokeObjectURL(url); }\n this.imagePreviewCache.clear();\n }\n\n registerTools(handlers: Record<string, ChatToolHandler>) {\n if (this.client) this.client.registerTools(handlers);\n else Object.assign(this.pendingTools, handlers);\n }\n\n private send(text: string, files: File[]) {\n if (!text.trim()) return;\n for (const f of files) {\n if (f.type.startsWith('image/') && typeof URL.createObjectURL === 'function' && !this.imagePreviewCache.has(f.name)) {\n this.imagePreviewCache.set(f.name, URL.createObjectURL(f));\n }\n }\n void this.client?.sendMessage(text, files.length > 0 ? files : undefined);\n }\n private renderError(msg: string) {\n if (!this.shadowRoot) this.attachShadow({ mode: 'open' });\n this.shadowRoot!.innerHTML = `<div style=\"color:#b91c1c;font:13px system-ui;padding:12px\">${escapeHtml(msg)}</div>`;\n }\n private renderAttachment(a: ChatAttachmentDescriptor): string {\n if (a.contentType.startsWith('image/')) {\n // Instant src when a local blob (just sent by this widget instance) or a previously-resolved\n // read-back URL is cached. Otherwise render the placeholder with a data-oc-ref marker and no\n // src attribute (an empty src=\"\" would make the browser (re)request the current page) -\n // hydrateAttachmentImages() resolves it lazily right after this markup is attached to the DOM.\n const cached = (a.name ? this.imagePreviewCache.get(a.name) : undefined) ?? this.resolvedUrlCache.get(a.storageRef);\n const srcAttr = cached ? ` src=\"${cached}\"` : '';\n return `<img class=\"att-thumb\" data-oc-ref=\"${escapeHtml(a.storageRef)}\"${srcAttr} alt=\"${escapeHtml(a.name ?? 'image')}\"/>`;\n }\n return `<div class=\"att-chip\">📎 ${escapeHtml(a.name ?? a.contentType)}</div>`;\n }\n private renderSource(s: { id: string; title: string; snippet: string }): string {\n return `<div class=\"src-chip\" title=\"${escapeHtml(s.snippet)}\">${escapeHtml(s.title)}</div>`;\n }\n\n // After render() attaches the markup, resolve a read-back URL (via the client) for every image\n // placeholder that has no src yet - a local blob or a previously-resolved URL already set one, so\n // those are left untouched (no redundant network call).\n private hydrateAttachmentImages() {\n if (!this.client) return;\n const imgs = this.shadowRoot!.querySelectorAll<HTMLImageElement>('img.att-thumb[data-oc-ref]');\n imgs.forEach((img) => {\n if (img.hasAttribute('src')) return;\n const ref = img.getAttribute('data-oc-ref');\n if (!ref) return;\n void this.client!.getAttachmentUrl(ref)\n .then((url) => { this.resolvedUrlCache.set(ref, url); img.src = url; })\n .catch(() => { /* leave unresolved - no thumbnail is an acceptable degrade, not fatal */ });\n });\n }\n\n private render() {\n const title = this.getAttribute('title') ?? this.agentName ?? 'Chat';\n const bubbles = this.messages.map((m) => {\n const atts = (m.attachments ?? []).map((a) => this.renderAttachment(a)).join('');\n const label = m.role === 'human' ? '<div class=\"human-label\">Support</div>' : '';\n const bubble = `<div class=\"b ${m.role}\">${label}${atts}${m.text ? escapeHtml(m.text) : ''}${m.streaming ? '…' : ''}</div>`;\n const sources = m.sources && m.sources.length > 0 ? `<div class=\"src-row\">${m.sources.map((s) => this.renderSource(s)).join('')}</div>` : '';\n return bubble + sources;\n }).join('');\n const statusText = HANDOFF_STATUS_TEXT[this.handoffState];\n const status = statusText ? `<div class=\"status\">${escapeHtml(statusText)}</div>` : '';\n const showTyping = this.agentTyping && (this.handoffState === 'human' || this.handoffState === 'awaiting_human');\n const typingIndicator = showTyping ? `<div class=\"b assistant typing\">${escapeHtml(AGENT_TYPING_TEXT)}</div>` : '';\n const disabled = this.state !== 'ready' ? 'disabled' : '';\n // Rebuilding innerHTML replaces the input node, which would otherwise drop the user's\n // in-progress text + caret on every streamed token. Capture and restore across the rebuild.\n const prevInput = this.shadowRoot!.querySelector<HTMLInputElement>('input[aria-label=\"message\"]');\n const prevValue = prevInput?.value ?? '';\n const prevSelectionStart = prevInput?.selectionStart ?? null;\n const prevSelectionEnd = prevInput?.selectionEnd ?? null;\n const hadFocus = !!prevInput && this.shadowRoot!.activeElement === prevInput;\n this.shadowRoot!.innerHTML = `\n <style>\n :host{display:block;height:100%;min-height:320px;font-family:system-ui,sans-serif;--oc-accent:#2563eb}\n .wrap{display:flex;flex-direction:column;height:100%;border:1px solid #e5e7eb;border-radius:12px;overflow:hidden}\n .hd{padding:10px 14px;border-bottom:1px solid #e5e7eb;font-weight:600}\n .body{flex:1;overflow-y:auto;padding:12px;display:flex;flex-direction:column;gap:8px}\n .b{max-width:80%;padding:8px 12px;border-radius:12px;white-space:pre-wrap;word-break:break-word}\n .b.user{align-self:flex-end;background:var(--oc-accent);color:#fff}\n .b.assistant{align-self:flex-start;background:#f3f4f6;color:#111}\n .b.human{align-self:flex-start;background:#dbeafe;color:#111}\n .b.typing{font-style:italic;color:#6b7280;opacity:.85}\n .human-label{font-size:11px;font-weight:600;opacity:.7;margin-bottom:2px}\n .status{padding:6px 14px;font-size:12px;color:#6b7280;background:#f9fafb;border-bottom:1px solid #e5e7eb}\n .att-thumb{display:block;max-width:160px;max-height:160px;border-radius:8px;margin-bottom:6px}\n .att-chip{display:inline-block;font-size:12px;background:rgba(0,0,0,.08);border-radius:6px;padding:2px 8px;margin:0 0 6px}\n .b.user .att-chip{background:rgba(255,255,255,.25)}\n .src-row{align-self:flex-start;display:flex;flex-wrap:wrap;gap:6px;max-width:80%}\n .src-chip{display:inline-block;font-size:11px;background:rgba(0,0,0,.06);color:#374151;border-radius:6px;padding:2px 8px;cursor:default}\n form{display:flex;gap:8px;padding:10px;border-top:1px solid #e5e7eb;align-items:center}\n input[aria-label=\"message\"]{flex:1;padding:8px 10px;border-radius:8px;border:1px solid #d1d5db;font:inherit}\n input[type=\"file\"]{max-width:120px;font-size:12px}\n button{padding:8px 14px;border-radius:8px;border:none;background:var(--oc-accent);color:#fff;font-weight:600;cursor:pointer}\n button:disabled,input:disabled{opacity:.6;cursor:not-allowed}\n </style>\n <div class=\"wrap\">\n <div class=\"hd\">${escapeHtml(title)}</div>\n ${status}\n <div class=\"body\">${bubbles}${typingIndicator}</div>\n <form>\n <input aria-label=\"message\" placeholder=\"Type a message…\" ${disabled}/>\n <input type=\"file\" accept=\"${ATTACHMENT_ACCEPT}\" multiple ${disabled}/>\n <button type=\"submit\" ${disabled}>Send</button>\n </form>\n </div>`;\n const form = this.shadowRoot!.querySelector('form')!;\n const input = this.shadowRoot!.querySelector<HTMLInputElement>('input[aria-label=\"message\"]')!;\n const fileInput = this.shadowRoot!.querySelector<HTMLInputElement>('input[type=\"file\"]')!;\n fileInput.addEventListener('change', () => { this.pendingFiles = fileInput.files ? Array.from(fileInput.files) : []; });\n form.addEventListener('submit', (e) => {\n e.preventDefault();\n const files = this.pendingFiles;\n this.pendingFiles = [];\n this.send(input.value, files);\n input.value = '';\n });\n if (prevValue) {\n input.value = prevValue;\n if (prevSelectionStart !== null && prevSelectionEnd !== null) input.setSelectionRange(prevSelectionStart, prevSelectionEnd);\n }\n if (hadFocus) input.focus();\n const body = this.shadowRoot!.querySelector('.body')!;\n body.scrollTop = body.scrollHeight;\n this.hydrateAttachmentImages();\n }\n}\nfunction escapeHtml(s: string) { return s.replace(/[&<>\"]/g, (c) => ({ '&': '&amp;', '<': '&lt;', '>': '&gt;', '\"': '&quot;' }[c]!)); }\n","export { ChatApiError } from './errors';\nexport type { ChatEvent, OpenSessionResponse, ChatClientOptions, ChatAttachmentDescriptor } from './protocol';\nexport { createChatClient } from './client';\nexport type { ChatClient, ChatMessage, ChatClientState, ChatClientEvent, ChatToolHandler } from './client';\nexport { OyehelloChatElement } from './element';\n\nimport { OyehelloChatElement } from './element';\n// Side effect: registering the element is why the package is sideEffects:true.\nif (typeof customElements !== 'undefined' && !customElements.get('oyehello-chat')) {\n customElements.define('oyehello-chat', OyehelloChatElement);\n}\n"]}
1
+ {"version":3,"sources":["../src/errors.ts","../src/transport.ts","../src/client.ts","../src/element.ts","../src/index.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["export class ChatApiError extends Error {\n constructor(message: string, readonly status: number, readonly code?: string, readonly meta?: Record<string, unknown>) {\n super(message);\n this.name = 'ChatApiError';\n }\n}\n","import { ChatApiError } from './errors';\nimport type { ChatAttachmentDescriptor, OpenSessionResponse, StreamTicket } from './protocol';\n\nasync function asError(res: Response, fallbackCode?: string): Promise<ChatApiError> {\n let body: { error?: string; code?: string; meta?: Record<string, unknown> } = {};\n try { body = (await res.json()) as { error?: string; code?: string; meta?: Record<string, unknown> }; } catch { /* non-json */ }\n return new ChatApiError(body.error ?? `HTTP ${res.status}`, res.status, body.code ?? fallbackCode, body.meta);\n}\n\nexport async function openSession(opts: { baseUrl: string; apiKey: string; agentId: string; user?: { id?: string }; clientTools?: string[]; fetchImpl: typeof fetch }): Promise<OpenSessionResponse> {\n const body: Record<string, unknown> = { agentId: opts.agentId };\n if (opts.user) body.user = opts.user;\n if (opts.clientTools && opts.clientTools.length > 0) body.clientTools = opts.clientTools;\n const res = await opts.fetchImpl(`${opts.baseUrl}/chat/sessions`, {\n method: 'POST', credentials: 'omit',\n headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${opts.apiKey}` },\n body: JSON.stringify(body),\n });\n if (!res.ok) throw await asError(res);\n return (await res.json()) as OpenSessionResponse;\n}\n\nexport async function postMessage(opts: { baseUrl: string; sessionId: string; sessionToken: string; text: string; attachments?: ChatAttachmentDescriptor[]; fetchImpl: typeof fetch }): Promise<void> {\n const body: Record<string, unknown> = { text: opts.text };\n if (opts.attachments && opts.attachments.length > 0) body.attachments = opts.attachments;\n const res = await opts.fetchImpl(`${opts.baseUrl}/chat/sessions/${opts.sessionId}/messages`, {\n method: 'POST', credentials: 'omit',\n headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${opts.sessionToken}` },\n body: JSON.stringify(body),\n });\n // A 401 here means the 15-min session token expired (no refresh endpoint) — surface a stable code\n // so the client can transparently re-open a session and retry.\n if (!res.ok) throw await asError(res, res.status === 401 ? 'session_expired' : undefined);\n}\n\nexport async function endSession(opts: { baseUrl: string; sessionId: string; sessionToken: string; fetchImpl: typeof fetch }): Promise<void> {\n await opts.fetchImpl(`${opts.baseUrl}/chat/sessions/${opts.sessionId}/end`, {\n method: 'POST', credentials: 'omit',\n headers: { Authorization: `Bearer ${opts.sessionToken}` },\n }).catch(() => {}); // best-effort teardown\n}\n\nexport async function postToolResult(opts: { baseUrl: string; sessionId: string; sessionToken: string; callId: string; ok: boolean; result: unknown; fetchImpl: typeof fetch }): Promise<void> {\n await opts.fetchImpl(`${opts.baseUrl}/chat/sessions/${opts.sessionId}/tool-results`, {\n method: 'POST', credentials: 'omit',\n headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${opts.sessionToken}` },\n body: JSON.stringify({ callId: opts.callId, ok: opts.ok, result: opts.result }),\n }).catch(() => {}); // best-effort; a dropped result times out server-side and the model recovers\n}\n\nexport async function mintStreamTicket(opts: { baseUrl: string; sessionId: string; sessionToken: string; fetchImpl: typeof fetch }): Promise<StreamTicket> {\n const res = await opts.fetchImpl(`${opts.baseUrl}/chat/sessions/${opts.sessionId}/stream-ticket`, {\n method: 'POST', credentials: 'omit',\n headers: { Authorization: `Bearer ${opts.sessionToken}` },\n });\n // A 401 here means the session token is invalid/expired — surface a stable code so the client\n // can distinguish this from a transient failure (mirrors postMessage's 401 mapping).\n if (!res.ok) throw await asError(res, res.status === 401 ? 'session_expired' : undefined);\n return (await res.json()) as StreamTicket;\n}\n\nexport function streamUrl(baseUrl: string, sessionId: string, ticket: string): string {\n return `${baseUrl}/chat/sessions/${sessionId}/stream?ticket=${encodeURIComponent(ticket)}`;\n}\n\n// POST /chat/sessions/:id/attachments — mints a presigned S3 PUT for a visitor upload. Bearer session\n// token auth, mirrors mintStreamTicket's shape/error-mapping exactly.\nexport async function presignAttachment(opts: { baseUrl: string; sessionId: string; sessionToken: string; contentType: string; fetchImpl: typeof fetch }): Promise<{ storageRef: string; uploadUrl: string }> {\n const res = await opts.fetchImpl(`${opts.baseUrl}/chat/sessions/${opts.sessionId}/attachments`, {\n method: 'POST', credentials: 'omit',\n headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${opts.sessionToken}` },\n body: JSON.stringify({ contentType: opts.contentType }),\n });\n // A 401 here means the session token is invalid/expired — surface a stable code so the client\n // can distinguish this from a transient failure (mirrors postMessage's 401 mapping).\n if (!res.ok) throw await asError(res, res.status === 401 ? 'session_expired' : undefined);\n return (await res.json()) as { storageRef: string; uploadUrl: string };\n}\n\n// POST /chat/sessions/:id/attachment-url — mints a presigned S3 GET so an already-uploaded\n// attachment can be read back (e.g. rendering an image thumbnail on reconnect, when no local blob\n// is cached). Bearer session token auth, mirrors presignAttachment's shape/error-mapping exactly.\nexport async function getAttachmentUrl(opts: { baseUrl: string; sessionId: string; sessionToken: string; storageRef: string; fetchImpl: typeof fetch }): Promise<string> {\n const res = await opts.fetchImpl(`${opts.baseUrl}/chat/sessions/${opts.sessionId}/attachment-url`, {\n method: 'POST', credentials: 'omit',\n headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${opts.sessionToken}` },\n body: JSON.stringify({ storageRef: opts.storageRef }),\n });\n // A 401 here means the session token is invalid/expired — surface a stable code so the client\n // can distinguish this from a transient failure (mirrors postMessage's 401 mapping).\n if (!res.ok) throw await asError(res, res.status === 401 ? 'session_expired' : undefined);\n return ((await res.json()) as { url: string }).url;\n}\n\n// Uploads a file directly to the presigned S3 URL. The URL is already absolute and fully signed —\n// NO baseUrl prefix, NO Authorization header (would break the signature), just a bare PUT with the\n// file's own content type (Task 4 dropped SSE from the presign so this needs no extra headers).\nexport async function uploadToPresigned(uploadUrl: string, file: File, fetchImpl: typeof fetch): Promise<void> {\n const res = await fetchImpl(uploadUrl, { method: 'PUT', body: file, headers: { 'Content-Type': file.type } });\n if (!res.ok) throw new ChatApiError(`attachment upload failed with HTTP ${res.status}`, res.status);\n}\n","import { openSession, postMessage, endSession, streamUrl, mintStreamTicket, postToolResult, presignAttachment, uploadToPresigned, getAttachmentUrl } from './transport';\nimport { ChatApiError } from './errors';\nimport type { ChatAttachmentDescriptor, ChatClientOptions, ChatEvent, OpenSessionResponse } from './protocol';\n\nexport interface ChatMessage { id: string; role: 'user' | 'assistant' | 'human'; text: string; streaming: boolean; attachments?: ChatAttachmentDescriptor[]; sources?: { id: string; title: string; snippet: string }[]; turnId?: string }\nexport type ChatClientState = 'idle' | 'opening' | 'ready' | 'ended' | 'error';\n// Handoff status of the session, driven by the backend's `state` SSE event (Phase 7). 'ai' = the\n// AI is answering (default/no handoff), 'awaiting_human' = a handoff was requested and no human\n// has taken over yet, 'human' = a human agent is answering.\nexport type HandoffState = 'ai' | 'awaiting_human' | 'human';\nexport type ChatClientEvent =\n | { type: 'state'; state: ChatClientState }\n | { type: 'messages'; messages: ChatMessage[] }\n | { type: 'error'; error: Error }\n | { type: 'agent'; agent: { id: string; name: string } }\n // Handoff status changed (Phase 7) - the widget uses this to show a status line.\n | { type: 'handoff'; state: HandoffState }\n // A human agent is (or stopped) typing in the console during a handoff (Phase 7 followups). The\n // widget uses this to show a transient \"agent is typing…\" affordance - never a message.\n | { type: 'agentTyping'; active: boolean };\nexport type ChatToolHandler = (args: Record<string, unknown>) => unknown | Promise<unknown>;\nexport interface ChatClient {\n start(): Promise<void>;\n sendMessage(text: string, files?: File[]): Promise<void>;\n end(): Promise<void>;\n getMessages(): ChatMessage[];\n getState(): ChatClientState;\n on(listener: (e: ChatClientEvent) => void): () => void;\n // Register browser-side tool handlers the server may call mid-conversation. Register BEFORE\n // start() — the handler names are sent as `clientTools` on session open so the server knows\n // which tools this session can execute.\n registerTools(handlers: Record<string, ChatToolHandler>): void;\n // Resolves a read-back URL for an already-uploaded attachment (e.g. an image thumbnail with no\n // local blob cached — a reconnect, or an `attachment` SSE echo). Requires start() to have been\n // called (a live session).\n getAttachmentUrl(storageRef: string): Promise<string>;\n}\n\nlet seq = 0;\nconst uid = (p: string) => `${p}_${Date.now().toString(36)}_${(seq++).toString(36)}`;\n\nexport function createChatClient(options: ChatClientOptions): ChatClient {\n // Native fetch must be invoked with `this === window`; the transport calls this as\n // `opts.fetchImpl(...)`, so a bare `globalThis.fetch` reference throws \"Illegal invocation\".\n // Bind the default to the global. A caller-supplied fetch is used as-is.\n const fetchImpl = options.fetch ?? globalThis.fetch.bind(globalThis);\n const ES = options.eventSource ?? globalThis.EventSource;\n // Mirrors the server's CHAT_ATTACHMENT_MAX_PER_MESSAGE default (apps/api/src/config/env.ts).\n const maxAttachments = options.maxAttachments ?? 4;\n // Mirrors the server's CHAT_ATTACHMENT_MAX_BYTES default (apps/api/src/config/env.ts). UX-only\n // fast pre-check - the server is authoritative (message-time HeadObject size enforcement).\n const maxAttachmentBytes = options.maxAttachmentBytes ?? 10_000_000;\n const listeners = new Set<(e: ChatClientEvent) => void>();\n let state: ChatClientState = 'idle';\n const messages: ChatMessage[] = [];\n let streamingId: string | null = null;\n let session: OpenSessionResponse | null = null;\n let es: EventSource | null = null;\n const seenTurnIds = new Set<string>();\n const seenCallIds = new Set<string>();\n let handoffState: HandoffState = 'ai';\n let reconnectTimer: ReturnType<typeof setTimeout> | null = null;\n let reconnectAttempts = 0;\n let closed = false;\n const toolHandlers = new Map<string, ChatToolHandler>();\n const clearReconnect = () => { if (reconnectTimer) { clearTimeout(reconnectTimer); reconnectTimer = null; } };\n\n const emit = (e: ChatClientEvent) => { for (const l of listeners) l(e); };\n const setState = (s: ChatClientState) => { state = s; emit({ type: 'state', state: s }); };\n const emitMessages = () => emit({ type: 'messages', messages: messages.slice() });\n\n const onEvent = (ev: ChatEvent) => {\n if (ev.type === 'token') {\n let m = streamingId ? messages.find((x) => x.id === streamingId) : undefined;\n if (!m) { m = { id: uid('m'), role: 'assistant', text: '', streaming: true }; messages.push(m); streamingId = m.id; }\n m.text += ev.text; emitMessages();\n } else if (ev.type === 'message') {\n if (seenTurnIds.has(ev.turnId)) {\n // Replay of an already-finalized turn (EventSource reconnect replays the session's\n // event buffer). Discard it, and drop any partial streaming bubble its replayed\n // tokens built up, without emitting a duplicate assistant message.\n if (streamingId) {\n const idx = messages.findIndex((x) => x.id === streamingId);\n if (idx !== -1) messages.splice(idx, 1);\n streamingId = null;\n emitMessages();\n }\n return;\n }\n seenTurnIds.add(ev.turnId);\n const m = streamingId ? messages.find((x) => x.id === streamingId) : undefined;\n if (m) { m.text = ev.text; m.streaming = false; m.turnId = ev.turnId; } else { messages.push({ id: uid('m'), role: 'assistant', text: ev.text, streaming: false, turnId: ev.turnId }); }\n streamingId = null; emitMessages();\n } else if (ev.type === 'citations') {\n // Arrives AFTER `message` (streamingId already cleared) so the target message is located by\n // the turnId stamped above, not by streamingId. Ignore an unknown turnId (reconnect-safe: a\n // stale/duplicate citations replay for a turn we don't have never crashes or creates a bubble).\n const m = messages.find((x) => x.turnId === ev.turnId);\n if (m) { m.sources = ev.sources; emitMessages(); }\n } else if (ev.type === 'error') {\n emit({ type: 'error', error: new Error(ev.message) });\n } else if (ev.type === 'tool_call') {\n if (seenCallIds.has(ev.callId)) return; // replayed on EventSource reconnect — dispatch once\n seenCallIds.add(ev.callId);\n const handler = toolHandlers.get(ev.name);\n void (async () => {\n if (!session) return;\n const base = { baseUrl: options.baseUrl, sessionId: session.sessionId, sessionToken: session.sessionToken, callId: ev.callId, fetchImpl };\n if (!handler) {\n await postToolResult({ ...base, ok: false, result: `no handler registered for ${ev.name}` });\n return;\n }\n try {\n const out = await handler(ev.args);\n await postToolResult({ ...base, ok: true, result: typeof out === 'string' ? out : JSON.stringify(out ?? { ok: true }) });\n } catch (err) {\n await postToolResult({ ...base, ok: false, result: (err as Error).message });\n }\n })();\n } else if (ev.type === 'attachment') {\n // The runtime re-publishes a visitor's message attachments over this event (Phase 5\n // follow-up) so a reconnecting client (buffer replay) or a future second viewer can render\n // them, now that a read-back URL exists (getAttachmentUrl / element.ts's lazy image src).\n // Hardened so it can never double-render on the SENDING client itself, which already rendered\n // these optimistically from its own sendMessage(): if any existing message already carries an\n // attachment with one of these storageRefs, the event is a stale/duplicate echo of something\n // already rendered — ignore it entirely instead of guessing which message to attach to (a\n // \"most recent attachment-less user message\" heuristic misattaches when a second image-first\n // message is sent before the echo of the first one arrives).\n const items = ev.items;\n const alreadyRendered = messages.some((m) => m.attachments?.some((a) => items.some((i) => i.storageRef === a.storageRef)));\n if (alreadyRendered) return;\n const target = [...messages].reverse().find((m) => m.role === 'user' && !m.attachments);\n if (target) target.attachments = items;\n else messages.push({ id: uid('u'), role: 'user', text: '', streaming: false, attachments: items });\n emitMessages();\n } else if (ev.type === 'human_message') {\n // A human agent's reply from the console inbox (Phase 7 handoff) - render as a distinct bubble.\n // Dedup by turnId (shared with the `message` branch's seenTurnIds) - EventSource reconnect\n // replays the session's buffered events, and human_message turnIds (newId('tn')) are distinct\n // from message turnIds, so sharing the Set is safe.\n if (seenTurnIds.has(ev.turnId)) return;\n seenTurnIds.add(ev.turnId);\n messages.push({ id: uid('m'), role: 'human', text: ev.text, streaming: false });\n emitMessages();\n } else if (ev.type === 'visitor_message') {\n // Echo of the visitor's own message, published so the console inbox sees it live. The widget\n // already rendered this optimistically in sendMessage() - ignore the echo entirely.\n } else if (ev.type === 'state') {\n // Handoff status transition (Phase 7): 'ai' | 'awaiting_human' | 'human'. Ignore any other/\n // future state string - forward-compat, no status line for an unrecognized value.\n if (ev.state === 'ai' || ev.state === 'awaiting_human' || ev.state === 'human') {\n handoffState = ev.state;\n emit({ type: 'handoff', state: handoffState });\n }\n } else if (ev.type === 'agent_typing') {\n // Transient signal only - never pushed as a message, never touches dedup/streaming state.\n emit({ type: 'agentTyping', active: !!ev.active });\n }\n // 'done' and any future unknown types are ignored (forward-compat).\n };\n\n // Tickets are single-use and short-lived: a fresh one must be minted for every (re)connect.\n // Native EventSource auto-reconnect would retry the SAME url whose ticket is already consumed\n // (→ 401 forever), so on error we close it ourselves and drive reconnection here instead.\n const openStream = async () => {\n if (!session || closed) return;\n es?.close();\n const { ticket } = await mintStreamTicket({ baseUrl: options.baseUrl, sessionId: session.sessionId, sessionToken: session.sessionToken, fetchImpl });\n if (closed) return;\n es = new ES(streamUrl(options.baseUrl, session.sessionId, ticket));\n es.onopen = () => { reconnectAttempts = 0; };\n es.onmessage = (e: MessageEvent) => { try { onEvent(JSON.parse(e.data) as ChatEvent); } catch { /* ignore malformed */ } };\n es.onerror = () => { es?.close(); es = null; scheduleReconnect(); };\n };\n\n const scheduleReconnect = () => {\n if (closed) return;\n clearReconnect();\n const delay = Math.min(30_000, 500 * 2 ** reconnectAttempts);\n reconnectAttempts += 1;\n reconnectTimer = setTimeout(() => {\n openStream().catch((err) => {\n if (err instanceof ChatApiError && (err as ChatApiError).code === 'session_expired') {\n open().catch((e) => { emit({ type: 'error', error: e as Error }); scheduleReconnect(); });\n } else {\n scheduleReconnect();\n }\n });\n }, delay);\n };\n\n const open = async () => {\n session = await openSession({ baseUrl: options.baseUrl, apiKey: options.apiKey, agentId: options.agentId, user: options.user, clientTools: Array.from(toolHandlers.keys()), fetchImpl });\n emit({ type: 'agent', agent: session.agent });\n await openStream();\n };\n\n // Presign + PUT every file against the CURRENT session. Called from the main sendMessage path and,\n // after a session_expired reopen, from the retry — a storageRef presigned against the old\n // interactionId is rejected cross-session (403 attachment_cross_session) if reused post-reopen.\n const uploadFiles = async (files: File[]): Promise<ChatAttachmentDescriptor[]> => {\n return Promise.all(files.map(async (file): Promise<ChatAttachmentDescriptor> => {\n const { storageRef, uploadUrl } = await presignAttachment({ baseUrl: options.baseUrl, sessionId: session!.sessionId, sessionToken: session!.sessionToken, contentType: file.type, fetchImpl });\n await uploadToPresigned(uploadUrl, file, fetchImpl);\n return { storageRef, contentType: file.type, name: file.name };\n }));\n };\n\n return {\n getMessages: () => messages.slice(),\n getState: () => state,\n on(listener) { listeners.add(listener); return () => listeners.delete(listener); },\n registerTools(handlers) { for (const [name, fn] of Object.entries(handlers)) toolHandlers.set(name, fn); },\n async getAttachmentUrl(storageRef) {\n if (!session) throw new Error('call start() before getAttachmentUrl');\n return getAttachmentUrl({ baseUrl: options.baseUrl, sessionId: session.sessionId, sessionToken: session.sessionToken, storageRef, fetchImpl });\n },\n async start() {\n if (state !== 'idle') return;\n setState('opening');\n try { await open(); setState('ready'); }\n catch (err) { setState('error'); emit({ type: 'error', error: err as Error }); }\n },\n async sendMessage(text, files) {\n if (!session) { emit({ type: 'error', error: new Error('call start() before sendMessage') }); return; }\n const fileList = files ?? [];\n if (fileList.length > maxAttachments) {\n emit({ type: 'error', error: new Error(`too many attachments: max ${maxAttachments} per message`) });\n return;\n }\n const oversized = fileList.find((f) => f.size > maxAttachmentBytes);\n if (oversized) {\n emit({ type: 'error', error: new Error(`attachment too large: ${oversized.name} exceeds ${maxAttachmentBytes} bytes`) });\n return;\n }\n // Upload every file BEFORE posting the message or pushing the optimistic bubble — a failed\n // upload must never leave a broken/partial message in the thread.\n let attachments: ChatAttachmentDescriptor[] = [];\n if (fileList.length > 0) {\n try {\n attachments = await uploadFiles(fileList);\n } catch (err) {\n emit({ type: 'error', error: err as Error });\n return;\n }\n }\n messages.push({ id: uid('u'), role: 'user', text, streaming: false, attachments: attachments.length > 0 ? attachments : undefined }); emitMessages();\n try {\n await postMessage({ baseUrl: options.baseUrl, sessionId: session.sessionId, sessionToken: session.sessionToken, text, attachments, fetchImpl });\n } catch (err) {\n if (err instanceof ChatApiError && err.code === 'session_expired') {\n try {\n await open(); // fresh backend session, same UI thread\n // Re-upload against the NEW session — the old attachments' storageRefs are bound to the\n // stale interactionId and would 403 (attachment_cross_session) if re-posted as-is.\n const freshAttachments = fileList.length ? await uploadFiles(fileList) : [];\n await postMessage({ baseUrl: options.baseUrl, sessionId: session!.sessionId, sessionToken: session!.sessionToken, text, attachments: freshAttachments, fetchImpl });\n } catch (retryErr) {\n emit({ type: 'error', error: retryErr as Error });\n }\n } else { emit({ type: 'error', error: err as Error }); }\n }\n },\n async end() {\n closed = true; clearReconnect();\n if (session) await endSession({ baseUrl: options.baseUrl, sessionId: session.sessionId, sessionToken: session.sessionToken, fetchImpl });\n es?.close(); es = null; setState('ended');\n },\n };\n}\n","import { createChatClient, type ChatClient, type ChatMessage, type ChatClientState, type ChatToolHandler, type HandoffState } from './client';\nimport type { ChatAttachmentDescriptor } from './protocol';\n\nconst HANDOFF_STATUS_TEXT: Record<HandoffState, string | null> = {\n ai: null,\n awaiting_human: 'Connecting you to a person…',\n human: \"You're chatting with a person\",\n};\n\nconst ATTACHMENT_ACCEPT = 'image/*,application/pdf,text/plain,text/csv';\nconst AGENT_TYPING_TEXT = 'The agent is typing…';\n\nexport class OyehelloChatElement extends HTMLElement {\n static observedAttributes = ['api-key', 'agent-id', 'base-url', 'title'];\n private client: ChatClient | null = null;\n private off: (() => void) | null = null;\n private messages: ChatMessage[] = [];\n private state: ChatClientState = 'idle';\n private agentName: string | null = null;\n private handoffState: HandoffState = 'ai';\n // Transient \"agent is typing…\" affordance (Phase 7 followups) - never a message, only rendered\n // while a handoff is active (human/awaiting_human).\n private agentTyping = false;\n // Last connection/runtime error message (client emits an 'error' event on a failed start() or\n // send). Surfaced as a visible banner so a disabled composer always shows WHY, instead of sitting\n // dead. Cleared when the client reaches a healthy state again.\n private lastError: string | null = null;\n // registerTools() may be called before connectedCallback creates the client (e.g. right after\n // document.createElement, before the element is attached). Buffer until the client exists.\n private pendingTools: Record<string, ChatToolHandler> = {};\n // Files picked in the file input, staged until the form submits alongside the text.\n private pendingFiles: File[] = [];\n // Best-effort local thumbnail cache for images THIS widget instance just sent, keyed by filename -\n // an instant blob src, no round-trip needed.\n private imagePreviewCache = new Map<string, string>();\n // Read-back URLs resolved lazily (via client.getAttachmentUrl) for images with no local blob (a\n // reconnect, or an `attachment` SSE echo), keyed by storageRef. Cached across re-renders so the\n // same image isn't re-fetched on every render() call.\n private resolvedUrlCache = new Map<string, string>();\n\n connectedCallback() {\n if (!this.shadowRoot) this.attachShadow({ mode: 'open' });\n const apiKey = this.getAttribute('api-key');\n const agentId = this.getAttribute('agent-id');\n const baseUrl = this.getAttribute('base-url');\n if (!apiKey || !agentId || !baseUrl) { this.renderError('oyehello-chat: api-key, agent-id and base-url are required'); return; }\n this.client = createChatClient({ apiKey, agentId, baseUrl });\n if (Object.keys(this.pendingTools).length > 0) { this.client.registerTools(this.pendingTools); this.pendingTools = {}; }\n this.off = this.client.on((e) => {\n if (e.type === 'messages') this.messages = e.messages;\n else if (e.type === 'state') { this.state = e.state; if (e.state === 'ready' || e.state === 'opening') this.lastError = null; }\n else if (e.type === 'agent') this.agentName = e.agent.name;\n else if (e.type === 'handoff') this.handoffState = e.state;\n else if (e.type === 'agentTyping') this.agentTyping = e.active;\n else if (e.type === 'error') this.lastError = e.error.message;\n this.render();\n });\n this.render();\n void this.client.start();\n }\n disconnectedCallback() {\n this.off?.(); void this.client?.end();\n for (const url of this.imagePreviewCache.values()) { if (typeof URL.revokeObjectURL === 'function') URL.revokeObjectURL(url); }\n this.imagePreviewCache.clear();\n }\n\n registerTools(handlers: Record<string, ChatToolHandler>) {\n if (this.client) this.client.registerTools(handlers);\n else Object.assign(this.pendingTools, handlers);\n }\n\n private send(text: string, files: File[]) {\n if (!text.trim()) return;\n for (const f of files) {\n if (f.type.startsWith('image/') && typeof URL.createObjectURL === 'function' && !this.imagePreviewCache.has(f.name)) {\n this.imagePreviewCache.set(f.name, URL.createObjectURL(f));\n }\n }\n void this.client?.sendMessage(text, files.length > 0 ? files : undefined);\n }\n private renderError(msg: string) {\n if (!this.shadowRoot) this.attachShadow({ mode: 'open' });\n this.shadowRoot!.innerHTML = `<div style=\"color:#b91c1c;font:13px system-ui;padding:12px\">${escapeHtml(msg)}</div>`;\n }\n private renderAttachment(a: ChatAttachmentDescriptor): string {\n if (a.contentType.startsWith('image/')) {\n // Instant src when a local blob (just sent by this widget instance) or a previously-resolved\n // read-back URL is cached. Otherwise render the placeholder with a data-oc-ref marker and no\n // src attribute (an empty src=\"\" would make the browser (re)request the current page) -\n // hydrateAttachmentImages() resolves it lazily right after this markup is attached to the DOM.\n const cached = (a.name ? this.imagePreviewCache.get(a.name) : undefined) ?? this.resolvedUrlCache.get(a.storageRef);\n const srcAttr = cached ? ` src=\"${cached}\"` : '';\n return `<img class=\"att-thumb\" data-oc-ref=\"${escapeHtml(a.storageRef)}\"${srcAttr} alt=\"${escapeHtml(a.name ?? 'image')}\"/>`;\n }\n return `<div class=\"att-chip\">📎 ${escapeHtml(a.name ?? a.contentType)}</div>`;\n }\n private renderSource(s: { id: string; title: string; snippet: string }): string {\n return `<div class=\"src-chip\" title=\"${escapeHtml(s.snippet)}\">${escapeHtml(s.title)}</div>`;\n }\n\n // After render() attaches the markup, resolve a read-back URL (via the client) for every image\n // placeholder that has no src yet - a local blob or a previously-resolved URL already set one, so\n // those are left untouched (no redundant network call).\n private hydrateAttachmentImages() {\n if (!this.client) return;\n const imgs = this.shadowRoot!.querySelectorAll<HTMLImageElement>('img.att-thumb[data-oc-ref]');\n imgs.forEach((img) => {\n if (img.hasAttribute('src')) return;\n const ref = img.getAttribute('data-oc-ref');\n if (!ref) return;\n void this.client!.getAttachmentUrl(ref)\n .then((url) => { this.resolvedUrlCache.set(ref, url); img.src = url; })\n .catch(() => { /* leave unresolved - no thumbnail is an acceptable degrade, not fatal */ });\n });\n }\n\n private render() {\n const title = this.getAttribute('title') ?? this.agentName ?? 'Chat';\n const bubbles = this.messages.map((m) => {\n const atts = (m.attachments ?? []).map((a) => this.renderAttachment(a)).join('');\n const label = m.role === 'human' ? '<div class=\"human-label\">Support</div>' : '';\n const bubble = `<div class=\"b ${m.role}\">${label}${atts}${m.text ? escapeHtml(m.text) : ''}${m.streaming ? '…' : ''}</div>`;\n const sources = m.sources && m.sources.length > 0 ? `<div class=\"src-row\">${m.sources.map((s) => this.renderSource(s)).join('')}</div>` : '';\n return bubble + sources;\n }).join('');\n const statusText = HANDOFF_STATUS_TEXT[this.handoffState];\n const status = statusText ? `<div class=\"status\">${escapeHtml(statusText)}</div>` : '';\n const errBanner = this.state === 'error' && this.lastError\n ? `<div class=\"err\">Couldn't start chat: ${escapeHtml(this.lastError)}</div>`\n : '';\n const showTyping = this.agentTyping && (this.handoffState === 'human' || this.handoffState === 'awaiting_human');\n const typingIndicator = showTyping ? `<div class=\"b assistant typing\">${escapeHtml(AGENT_TYPING_TEXT)}</div>` : '';\n const disabled = this.state !== 'ready' ? 'disabled' : '';\n // Rebuilding innerHTML replaces the input node, which would otherwise drop the user's\n // in-progress text + caret on every streamed token. Capture and restore across the rebuild.\n const prevInput = this.shadowRoot!.querySelector<HTMLInputElement>('input[aria-label=\"message\"]');\n const prevValue = prevInput?.value ?? '';\n const prevSelectionStart = prevInput?.selectionStart ?? null;\n const prevSelectionEnd = prevInput?.selectionEnd ?? null;\n const hadFocus = !!prevInput && this.shadowRoot!.activeElement === prevInput;\n this.shadowRoot!.innerHTML = `\n <style>\n :host{display:block;height:100%;min-height:320px;font-family:system-ui,sans-serif;--oc-accent:#2563eb}\n .wrap{display:flex;flex-direction:column;height:100%;border:1px solid #e5e7eb;border-radius:12px;overflow:hidden}\n .hd{padding:10px 14px;border-bottom:1px solid #e5e7eb;font-weight:600}\n .body{flex:1;overflow-y:auto;padding:12px;display:flex;flex-direction:column;gap:8px}\n .b{max-width:80%;padding:8px 12px;border-radius:12px;white-space:pre-wrap;word-break:break-word}\n .b.user{align-self:flex-end;background:var(--oc-accent);color:#fff}\n .b.assistant{align-self:flex-start;background:#f3f4f6;color:#111}\n .b.human{align-self:flex-start;background:#dbeafe;color:#111}\n .b.typing{font-style:italic;color:#6b7280;opacity:.85}\n .human-label{font-size:11px;font-weight:600;opacity:.7;margin-bottom:2px}\n .status{padding:6px 14px;font-size:12px;color:#6b7280;background:#f9fafb;border-bottom:1px solid #e5e7eb}\n .err{padding:8px 14px;font-size:12px;color:#b91c1c;background:#fef2f2;border-bottom:1px solid #fecaca}\n .att-thumb{display:block;max-width:160px;max-height:160px;border-radius:8px;margin-bottom:6px}\n .att-chip{display:inline-block;font-size:12px;background:rgba(0,0,0,.08);border-radius:6px;padding:2px 8px;margin:0 0 6px}\n .b.user .att-chip{background:rgba(255,255,255,.25)}\n .src-row{align-self:flex-start;display:flex;flex-wrap:wrap;gap:6px;max-width:80%}\n .src-chip{display:inline-block;font-size:11px;background:rgba(0,0,0,.06);color:#374151;border-radius:6px;padding:2px 8px;cursor:default}\n form{display:flex;gap:8px;padding:10px;border-top:1px solid #e5e7eb;align-items:center}\n input[aria-label=\"message\"]{flex:1;padding:8px 10px;border-radius:8px;border:1px solid #d1d5db;font:inherit}\n input[type=\"file\"]{max-width:120px;font-size:12px}\n button{padding:8px 14px;border-radius:8px;border:none;background:var(--oc-accent);color:#fff;font-weight:600;cursor:pointer}\n button:disabled,input:disabled{opacity:.6;cursor:not-allowed}\n </style>\n <div class=\"wrap\">\n <div class=\"hd\">${escapeHtml(title)}</div>\n ${status}${errBanner}\n <div class=\"body\">${bubbles}${typingIndicator}</div>\n <form>\n <input aria-label=\"message\" placeholder=\"Type a message…\" ${disabled}/>\n <input type=\"file\" accept=\"${ATTACHMENT_ACCEPT}\" multiple ${disabled}/>\n <button type=\"submit\" ${disabled}>Send</button>\n </form>\n </div>`;\n const form = this.shadowRoot!.querySelector('form')!;\n const input = this.shadowRoot!.querySelector<HTMLInputElement>('input[aria-label=\"message\"]')!;\n const fileInput = this.shadowRoot!.querySelector<HTMLInputElement>('input[type=\"file\"]')!;\n fileInput.addEventListener('change', () => { this.pendingFiles = fileInput.files ? Array.from(fileInput.files) : []; });\n form.addEventListener('submit', (e) => {\n e.preventDefault();\n const files = this.pendingFiles;\n this.pendingFiles = [];\n this.send(input.value, files);\n input.value = '';\n });\n if (prevValue) {\n input.value = prevValue;\n if (prevSelectionStart !== null && prevSelectionEnd !== null) input.setSelectionRange(prevSelectionStart, prevSelectionEnd);\n }\n if (hadFocus) input.focus();\n const body = this.shadowRoot!.querySelector('.body')!;\n body.scrollTop = body.scrollHeight;\n this.hydrateAttachmentImages();\n }\n}\nfunction escapeHtml(s: string) { return s.replace(/[&<>\"]/g, (c) => ({ '&': '&amp;', '<': '&lt;', '>': '&gt;', '\"': '&quot;' }[c]!)); }\n","export { ChatApiError } from './errors';\nexport type { ChatEvent, OpenSessionResponse, ChatClientOptions, ChatAttachmentDescriptor } from './protocol';\nexport { createChatClient } from './client';\nexport type { ChatClient, ChatMessage, ChatClientState, ChatClientEvent, ChatToolHandler } from './client';\nexport { OyehelloChatElement } from './element';\n\nimport { OyehelloChatElement } from './element';\n// Side effect: registering the element is why the package is sideEffects:true.\nif (typeof customElements !== 'undefined' && !customElements.get('oyehello-chat')) {\n customElements.define('oyehello-chat', OyehelloChatElement);\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@oyehello/chat",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "description": "Framework-agnostic embeddable chat SDK for oyehello agents. Web component + headless client.",
5
5
  "license": "SEE LICENSE IN LICENSE",
6
6
  "type": "module",
@@ -10,9 +10,23 @@
10
10
  "types": "./dist/index.d.ts",
11
11
  "unpkg": "./dist/index.global.js",
12
12
  "exports": {
13
- ".": { "types": "./dist/index.d.ts", "import": "./dist/index.js", "require": "./dist/index.cjs" }
13
+ ".": {
14
+ "types": "./dist/index.d.ts",
15
+ "import": "./dist/index.js",
16
+ "require": "./dist/index.cjs"
17
+ }
14
18
  },
15
- "files": ["dist", "LICENSE", "README.md"],
16
- "publishConfig": { "access": "public" },
17
- "scripts": { "build": "tsup", "typecheck": "tsc --noEmit" }
19
+ "files": [
20
+ "dist",
21
+ "LICENSE",
22
+ "README.md"
23
+ ],
24
+ "publishConfig": {
25
+ "access": "public"
26
+ },
27
+ "scripts": {
28
+ "build": "tsup",
29
+ "typecheck": "tsc --noEmit",
30
+ "prepare": "tsup"
31
+ }
18
32
  }