@paramms/chat-widget 1.6.2 → 1.6.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1 @@
1
+ {"version":3,"file":"chatlist2.js","sources":["../src/history.ts","../src/theme-tokens.ts","../src/chatlist.styles.ts","../src/uid.ts","../node_modules/@msgpack/msgpack/dist.esm/utils/utf8.mjs","../node_modules/@msgpack/msgpack/dist.esm/ExtData.mjs","../node_modules/@msgpack/msgpack/dist.esm/DecodeError.mjs","../node_modules/@msgpack/msgpack/dist.esm/utils/int.mjs","../node_modules/@msgpack/msgpack/dist.esm/timestamp.mjs","../node_modules/@msgpack/msgpack/dist.esm/ExtensionCodec.mjs","../node_modules/@msgpack/msgpack/dist.esm/utils/typedArrays.mjs","../node_modules/@msgpack/msgpack/dist.esm/Encoder.mjs","../node_modules/@msgpack/msgpack/dist.esm/encode.mjs","../node_modules/@msgpack/msgpack/dist.esm/utils/prettyByte.mjs","../node_modules/@msgpack/msgpack/dist.esm/CachedKeyDecoder.mjs","../node_modules/@msgpack/msgpack/dist.esm/Decoder.mjs","../node_modules/@msgpack/msgpack/dist.esm/decode.mjs","../src/protocol/codec.ts","../src/chatlist.ts"],"sourcesContent":["// history.ts — shared REST history-fetch logic for both the guest widget\n// (index.ts) and the agent dashboard (operate.ts).\n//\n// Strategy:\n// • On open: fetch the latest 20 messages. Fast, cheap, covers most chats.\n// • hasMore=true → show a sentinel div at the top of the scroll area.\n// • When the user scrolls near the top (scrollTop < 80px) fetch the next\n// 20 older messages and prepend — no button click required.\n// • This is the same infinite-scroll-upward pattern used by WhatsApp/Telegram.\n\nimport type { ChatStore } from './store.js'\nimport type { Message, ConversationId } from './protocol/index.js'\nimport type { Renderer } from './renderer.js'\n\nconst PAGE = 20 // messages per fetch — fast first load, smooth pagination\n\n/** Resolve a single user-supplied relay URL into the concrete WebSocket URL and\n * HTTP(S) base the client needs.\n *\n * Accepts any scheme — `https://`, `http://`, `wss://`, or `ws://` — and any of\n * these shapes: bare origin (`https://api.example.com`), origin with `/ws`\n * (`wss://api.example.com/ws`), or a sub-path (`https://api.example.com/relay`).\n *\n * https://api.example.com → ws wss://api.example.com/ws · http https://api.example.com\n * wss://api.example.com/ws → ws wss://api.example.com/ws · http https://api.example.com\n * http://localhost:3000 → ws ws://localhost:3000/ws · http http://localhost:3000\n *\n * `https`/`wss` map to a secure socket (`wss`); `http`/`ws` map to `ws`. A bare\n * host with no scheme is assumed secure. Pass `apiBaseOverride` only when the\n * REST API lives on a different origin than the socket. */\nexport function resolveRelayUrls(input: string, apiBaseOverride?: string): { wsUrl: string; httpBase: string } {\n const trimmed = input.trim().replace(/\\/+$/, '')\n const scheme = trimmed.match(/^(https|http|wss|ws):\\/\\//)?.[1]\n const secure = scheme ? scheme === 'https' || scheme === 'wss' : true\n const authorityAndPath = (scheme ? trimmed.slice(scheme.length + 3) : trimmed).replace(/\\/ws$/, '')\n const httpBase = apiBaseOverride\n ? apiBaseOverride.trim().replace(/\\/+$/, '')\n : `${secure ? 'https' : 'http'}://${authorityAndPath}`\n const wsUrl = `${secure ? 'wss' : 'ws'}://${authorityAndPath}/ws`\n return { wsUrl, httpBase }\n}\n\n/** Derive the HTTP(S) base origin from a ws(s):// URL.\n * @deprecated prefer {@link resolveRelayUrls}; kept for back-compat. */\nexport function httpBaseFromWsUrl(wsUrl: string): string {\n return resolveRelayUrls(wsUrl).httpBase\n}\n\n/** Build the best history URL for the given token context.\n * Staff tokens use /messages (full access); guest tokens use /history. */\nfunction historyUrl(httpBase: string, conversationId: string, beforeSeq: number, limit: number): string[] {\n const qs = `beforeSeq=${beforeSeq}&limit=${limit}`\n return [\n `${httpBase}/conversations/${conversationId}/messages?${qs}`,\n `${httpBase}/conversations/${conversationId}/history?${qs}`,\n ]\n}\n\n/** Fetch one page of history. Tries staff endpoint first, falls back to guest.\n *\n * Returns `null` ONLY when every attempt failed. That case used to be\n * indistinguishable from \"no history\" and was swallowed without a word:\n * `catch { }` here, `if (!page) return` in the caller. When the REST calls\n * were being CORS-rejected from a customer domain (the WebSocket is not\n * subject to CORS, so live chat kept working) the visible symptom was\n * \"my messages disappear when I refresh\" with NOTHING in the console to\n * explain it. A transport failure is now reported. */\nasync function fetchPage(\n httpBase: string,\n conversationId: string,\n token: string,\n beforeSeq: number,\n limit = PAGE,\n): Promise<{ messages: Message[]; hasMore: boolean } | null> {\n let lastError: unknown\n let sawResponse = false\n for (const url of historyUrl(httpBase, conversationId, beforeSeq, limit)) {\n try {\n const res = await fetch(url, { headers: { authorization: `Bearer ${token}` } })\n sawResponse = true // reached the server; this endpoint just said no\n if (!res.ok) continue\n const data = await res.json() as { messages?: Message[]; hasMore?: boolean }\n return { messages: data.messages ?? [], hasMore: data.hasMore ?? false }\n } catch (e) { lastError = e }\n }\n // A thrown fetch (as opposed to an HTTP error) is a TRANSPORT failure —\n // overwhelmingly CORS, occasionally DNS/offline. Name it, because the user\n // just watched their history vanish.\n if (!sawResponse) {\n console.error(\n `[chat-widget] could not load history from ${httpBase} — the request never reached the server. `\n + 'This is almost always CORS: add this site\\'s origin to the chatroom\\'s allowed origins '\n + '(dashboard → chatroom → allowed origins) or to the server\\'s CORS_ORIGINS.',\n lastError,\n )\n } else {\n console.error(`[chat-widget] history request to ${httpBase} was rejected for conversation ${conversationId}.`)\n }\n return null\n}\n\n/** Initial history restore on conversation open.\n *\n * Fetches the latest PAGE messages and sets up scroll-triggered loading for\n * older messages: a `scroll` listener on the container's own scrollTop (see\n * below), not an IntersectionObserver sentinel. No buttons — scrolling up\n * loads more automatically.\n *\n * Does NOT return a cleanup function — the scroll-listener teardown is\n * registered internally via `renderer.setScrollCleanup()` and runs whenever\n * the renderer tears down the conversation view. Callers just `void` this\n * call (see index.ts). */\nexport async function restoreHistory(\n wsUrl: string,\n token: string,\n conversationId: ConversationId,\n store: ChatStore,\n renderer: Renderer,\n apiBase?: string,\n): Promise<void> {\n const httpBase = apiBase ? apiBase.replace(/\\/+$/, '') : httpBaseFromWsUrl(wsUrl)\n\n const page = await fetchPage(httpBase, conversationId as string, token, Number.MAX_SAFE_INTEGER)\n if (!page) return\n\n if (page.messages.length) {\n store.apply({ type: 'sync', conversationId, messages: page.messages })\n // Always set hasMore from the response\n store.apply({ type: 'history', conversationId, messages: [], hasMore: page.hasMore })\n renderer.render(store)\n } else {\n // No messages — still record hasMore=false so the sentinel doesn't show\n store.apply({ type: 'history', conversationId, messages: [], hasMore: false })\n }\n\n if (!page.hasMore) return\n\n // ── Scroll-triggered load-more ────────────────────────────────────────────\n // The renderer shows a sentinel div (\"↑ Loading earlier messages…\") at the\n // top of the scroll area whenever hasMoreHistory is true (visual only, not\n // observed) — the trigger is this scroll listener on the container itself:\n // when scrollTop < 80px, load more.\n let loading = false\n\n const loadOlder = async () => {\n if (loading || !store.hasMoreHistory) return\n loading = true\n const oldest = store.messages()[0]\n if (!oldest) { loading = false; return }\n const page2 = await fetchPage(httpBase, conversationId as string, token, oldest.seq)\n if (page2) {\n store.apply({ type: 'history', conversationId, messages: page2.messages, hasMore: page2.hasMore })\n renderer.render(store)\n }\n loading = false\n }\n\n // Use IntersectionObserver to detect when the user scrolls to the top.\n // We observe the scroll container itself — when scrollTop < 40px, load more.\n const scrollEl = renderer.getScrollEl()\n if (!scrollEl) return\n\n // Wait 300ms before arming the scroll listener — the initial render scrolls\n // to the bottom, which briefly passes through scrollTop=0 and could trigger\n // a spurious load before the user actually scrolls up.\n let armed = false\n setTimeout(() => { armed = true }, 300)\n\n const onScroll = () => {\n if (!armed) return\n if (scrollEl.scrollTop < 80 && store.hasMoreHistory && !loading) {\n void loadOlder()\n }\n }\n scrollEl.addEventListener('scroll', onScroll, { passive: true })\n renderer.setScrollCleanup(() => scrollEl.removeEventListener('scroll', onScroll))\n}\n","// Single source of truth for the widget's design tokens (colours, shadow, fonts).\n// Both the chatroom (`.ocw`, renderer.ts) and the chat list (`.ocl`, chatlist.ts)\n// build their CSS custom-property blocks from these, so the palette — light and\n// dark — lives in exactly one place. Change a colour here and every surface,\n// in both light and dark mode, updates together.\n\nconst LIGHT: Record<string, string> = {\n accent: '#6c5ce7', accent2: '#4c6fff', bg: '#f4f3fb', card: '#fff', tint: '#eeecfb',\n line: '#e6e2f5', ink: '#221d3a', mut: '#8f8aa8', onaccent: '#fff', rowhover: '#e7e3f8',\n shadow: '0 12px 32px rgba(108,92,231,.14)',\n}\n\nconst DARK: Record<string, string> = {\n accent: '#a99cf2', accent2: '#6f8cff', bg: '#221d3a', card: '#2b2550', tint: '#2f2853',\n line: '#3a3363', ink: '#eceafc', mut: '#9b93c9', onaccent: '#221d3a', rowhover: '#39325e',\n shadow: '0 12px 32px rgba(0,0,0,.4)',\n}\n\nconst FB = \"'Nunito',-apple-system,BlinkMacSystemFont,'Segoe UI',system-ui,sans-serif\"\n\nfunction vars(prefix: string, t: Record<string, string>): string {\n return Object.entries(t).map(([k, v]) => `--${prefix}-${k}:${v};`).join(' ')\n}\n\n/** Light-mode token declarations for a prefix ('ocw' | 'ocl'), incl. font tokens. */\nexport function lightTokens(prefix: string): string {\n return `${vars(prefix, LIGHT)} --${prefix}-fb:${FB}; --${prefix}-fh:'Baloo 2',var(--${prefix}-fb);`\n}\n\n/** Dark-mode token overrides for a prefix (fonts are unchanged in dark). */\nexport function darkTokens(prefix: string): string {\n return vars(prefix, DARK)\n}\n","// Injected stylesheet for the chat list (`.ocl`). Extracted from chatlist.ts.\n// Tokens come from theme-tokens.ts (single source of truth).\nimport { lightTokens, darkTokens } from './theme-tokens.js'\n\nexport const CSS = `\n.ocl { ${lightTokens('ocl')}\n display:flex; flex-direction:column; height:100%; background:var(--ocl-bg);\n font-family:var(--ocl-fb); color:var(--ocl-ink); overflow:hidden; }\n@media (prefers-color-scheme: dark) { .ocl[data-theme=\"auto\"] { ${darkTokens('ocl')} } }\n.ocl[data-theme=\"dark\"] { ${darkTokens('ocl')} }\n.ocl-head { display:flex; align-items:center; padding:16px 16px 10px; background:var(--ocl-bg); }\n.ocl-title { flex:1; display:flex; align-items:center; font-family:var(--ocl-fh); font-weight:700; font-size:18px; color:var(--ocl-ink); }\n.ocl-retry { margin-top:14px; border:none; background:var(--ocl-accent); color:var(--ocl-onaccent); border-radius:20px; padding:8px 20px; font:inherit; font-size:13px; font-weight:600; cursor:pointer; }\n.ocl-search-wrap { padding:4px 12px 8px; background:var(--ocl-bg); }\n.ocl-search { width:100%; box-sizing:border-box; border:none; background:var(--ocl-tint); border-radius:20px; padding:9px 14px; font:inherit; font-size:14px; outline:none; }\n.ocl-body { flex:1; overflow-y:auto; }\n.ocl-section { padding:10px 18px 4px; font-family:var(--ocl-fh); font-size:11px; font-weight:600; color:var(--ocl-mut); text-transform:uppercase; letter-spacing:.5px; background:transparent; }\n.ocl-empty { padding:40px 20px; text-align:center; color:var(--ocl-mut); font-size:14px; }\n.ocl-row { display:flex; align-items:center; gap:12px; padding:10px 12px; margin:6px 12px; background:var(--ocl-tint); border:none; width:calc(100% - 24px); box-sizing:border-box; border-radius:16px; text-align:left; cursor:pointer; transition:background .12s; }\n.ocl-row:hover { background:var(--ocl-rowhover); }\n.ocl-row.unread { background:var(--ocl-rowhover); }\n.ocl-av { width:40px; height:40px; border-radius:50%; background:var(--ocl-accent); color:var(--ocl-onaccent); font-family:var(--ocl-fh); font-size:15px; font-weight:600; display:flex; align-items:center; justify-content:center; flex:none; }\n.ocl-info { flex:1; min-width:0; }\n.ocl-name { font-family:var(--ocl-fh); font-size:14px; font-weight:600; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; margin-bottom:2px; }\n.ocl-row.unread .ocl-name { font-weight:700; }\n.ocl-preview { font-size:11.5px; color:var(--ocl-mut); white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }\n.ocl-row.unread .ocl-preview { color:var(--ocl-ink); }\n.ocl-right { display:flex; flex-direction:column; align-items:flex-end; gap:4px; flex:none; }\n.ocl-time { font-size:10px; color:var(--ocl-mut); }\n.ocl-row.unread .ocl-time { color:var(--ocl-accent); font-weight:600; }\n.ocl-badge { background:var(--ocl-accent); color:var(--ocl-onaccent); border-radius:999px; font-size:11px; font-weight:700; min-width:20px; height:20px; padding:0 5px; display:flex; align-items:center; justify-content:center; }\n.ocl-status { font-size:10px; font-weight:600; padding:2px 8px; border-radius:20px; white-space:nowrap; }\n.ocl-status.open { background:#dff3e6; color:#2f8a52; }\n.ocl-status.waiting { background:var(--ocl-tint); color:var(--ocl-accent); border:1px solid var(--ocl-accent); }\n.ocl-status.done { background:#eee; color:#777; }\n.ocl[data-theme=\"dark\"] .ocl-status.done { background:#39325e; color:#b3abd6; }\n@media (prefers-color-scheme: dark) { .ocl[data-theme=\"auto\"] .ocl-status.done { background:#39325e; color:#b3abd6; } }\n.ocl-spinner { padding:24px; text-align:center; color:var(--ocl-mut); font-size:13px; }\n.ocl-compose { border:none; background:var(--ocl-accent); color:var(--ocl-onaccent); width:32px; height:32px; border-radius:50%; font-size:18px; line-height:1; cursor:pointer; box-shadow:var(--ocl-shadow); }\n.ocl-compose:hover { filter:brightness(1.08); }\n/* When the HOST overlays a ✕ (ChatApp's onClose / embed's inbox stack), it is\n absolutely positioned at top-right and used to land straight on top of the ✎\n compose button. Reserve the space instead of stacking them. */\n.ocl-has-close .ocl-head { padding-right:52px; }\n.ocl-start { margin-top:12px; border:none; background:var(--ocl-accent); color:var(--ocl-onaccent); border-radius:20px; padding:8px 18px; font:inherit; font-size:13px; font-weight:600; cursor:pointer; }\n/* Compact sizing keyed on the LIST'S OWN width (ResizeObserver toggles\n * .ocl-compact below 400px) — covers phones and narrow desktop embeds alike.\n * Search must be ≥16px in compact or iOS zooms the page on focus. */\n.ocl-compact .ocl-row { padding:13px 14px; }\n.ocl-compact .ocl-search { font-size:16px; }\n.ocl-compact .ocl-compose { width:36px; height:36px; }\n.ocl-row:focus-visible, .ocl button:focus-visible, .ocl input:focus-visible { outline:2px solid var(--ocl-accent); outline-offset:2px; border-radius:12px; }\n`\n","/** Persistent anonymous identity, reused across reloads.\n *\n * Persists through BOTH localStorage and a first-party cookie. On a top-level\n * page (e.g. a standalone hosted widget at relay.example.com) the cookie\n * survives even if localStorage is unavailable or cleared, so a guest keeps\n * the same id across refreshes — which is what lets the server resolve their\n * existing conversation and load history. (In a cross-origin iframe both may\n * be partitioned; pass an explicit `userId`/`token` for that case.)\n */\nconst KEY = 'oc_uid'\n\nfunction readCookie(name: string): string | null {\n try {\n const m = document.cookie.match(new RegExp(`(?:^|; )${name}=([^;]*)`))\n return m ? decodeURIComponent(m[1]!) : null\n } catch { return null }\n}\n\nfunction writeCookie(name: string, value: string): void {\n try {\n const maxAge = 60 * 60 * 24 * 365 // 1 year\n const secure = location.protocol === 'https:' ? '; Secure' : ''\n document.cookie = `${name}=${encodeURIComponent(value)}; Max-Age=${maxAge}; Path=/; SameSite=Lax${secure}`\n } catch { /* cookies disabled — best effort */ }\n}\n\nfunction newId(): string {\n return `g_${Math.random().toString(36).slice(2)}${Date.now().toString(36)}`\n}\n\nexport function persistentUid(): string {\n let existing: string | null = null\n try { existing = localStorage.getItem(KEY) } catch { /* unavailable */ }\n if (!existing) existing = readCookie(KEY)\n\n const id = existing ?? newId()\n\n // Write through to both stores so whichever is available carries it forward.\n try { localStorage.setItem(KEY, id) } catch { /* unavailable */ }\n writeCookie(KEY, id)\n\n return id\n}\n","export function utf8Count(str) {\n const strLength = str.length;\n let byteLength = 0;\n let pos = 0;\n while (pos < strLength) {\n let value = str.charCodeAt(pos++);\n if ((value & 0xffffff80) === 0) {\n // 1-byte\n byteLength++;\n continue;\n }\n else if ((value & 0xfffff800) === 0) {\n // 2-bytes\n byteLength += 2;\n }\n else {\n // handle surrogate pair\n if (value >= 0xd800 && value <= 0xdbff) {\n // high surrogate\n if (pos < strLength) {\n const extra = str.charCodeAt(pos);\n if ((extra & 0xfc00) === 0xdc00) {\n ++pos;\n value = ((value & 0x3ff) << 10) + (extra & 0x3ff) + 0x10000;\n }\n }\n }\n if ((value & 0xffff0000) === 0) {\n // 3-byte\n byteLength += 3;\n }\n else {\n // 4-byte\n byteLength += 4;\n }\n }\n }\n return byteLength;\n}\nexport function utf8EncodeJs(str, output, outputOffset) {\n const strLength = str.length;\n let offset = outputOffset;\n let pos = 0;\n while (pos < strLength) {\n let value = str.charCodeAt(pos++);\n if ((value & 0xffffff80) === 0) {\n // 1-byte\n output[offset++] = value;\n continue;\n }\n else if ((value & 0xfffff800) === 0) {\n // 2-bytes\n output[offset++] = ((value >> 6) & 0x1f) | 0xc0;\n }\n else {\n // handle surrogate pair\n if (value >= 0xd800 && value <= 0xdbff) {\n // high surrogate\n if (pos < strLength) {\n const extra = str.charCodeAt(pos);\n if ((extra & 0xfc00) === 0xdc00) {\n ++pos;\n value = ((value & 0x3ff) << 10) + (extra & 0x3ff) + 0x10000;\n }\n }\n }\n if ((value & 0xffff0000) === 0) {\n // 3-byte\n output[offset++] = ((value >> 12) & 0x0f) | 0xe0;\n output[offset++] = ((value >> 6) & 0x3f) | 0x80;\n }\n else {\n // 4-byte\n output[offset++] = ((value >> 18) & 0x07) | 0xf0;\n output[offset++] = ((value >> 12) & 0x3f) | 0x80;\n output[offset++] = ((value >> 6) & 0x3f) | 0x80;\n }\n }\n output[offset++] = (value & 0x3f) | 0x80;\n }\n}\n// TextEncoder and TextDecoder are standardized in whatwg encoding:\n// https://encoding.spec.whatwg.org/\n// and available in all the modern browsers:\n// https://caniuse.com/textencoder\n// They are available in Node.js since v12 LTS as well:\n// https://nodejs.org/api/globals.html#textencoder\nconst sharedTextEncoder = new TextEncoder();\n// This threshold should be determined by benchmarking, which might vary in engines and input data.\n// Run `npx ts-node benchmark/encode-string.ts` for details.\nconst TEXT_ENCODER_THRESHOLD = 50;\nexport function utf8EncodeTE(str, output, outputOffset) {\n sharedTextEncoder.encodeInto(str, output.subarray(outputOffset));\n}\nexport function utf8Encode(str, output, outputOffset) {\n if (str.length > TEXT_ENCODER_THRESHOLD) {\n utf8EncodeTE(str, output, outputOffset);\n }\n else {\n utf8EncodeJs(str, output, outputOffset);\n }\n}\nconst CHUNK_SIZE = 4096;\nexport function utf8DecodeJs(bytes, inputOffset, byteLength) {\n let offset = inputOffset;\n const end = offset + byteLength;\n const units = [];\n let result = \"\";\n while (offset < end) {\n const byte1 = bytes[offset++];\n if ((byte1 & 0x80) === 0) {\n // 1 byte\n units.push(byte1);\n }\n else if ((byte1 & 0xe0) === 0xc0) {\n // 2 bytes\n const byte2 = bytes[offset++] & 0x3f;\n units.push(((byte1 & 0x1f) << 6) | byte2);\n }\n else if ((byte1 & 0xf0) === 0xe0) {\n // 3 bytes\n const byte2 = bytes[offset++] & 0x3f;\n const byte3 = bytes[offset++] & 0x3f;\n units.push(((byte1 & 0x1f) << 12) | (byte2 << 6) | byte3);\n }\n else if ((byte1 & 0xf8) === 0xf0) {\n // 4 bytes\n const byte2 = bytes[offset++] & 0x3f;\n const byte3 = bytes[offset++] & 0x3f;\n const byte4 = bytes[offset++] & 0x3f;\n let unit = ((byte1 & 0x07) << 0x12) | (byte2 << 0x0c) | (byte3 << 0x06) | byte4;\n if (unit > 0xffff) {\n unit -= 0x10000;\n units.push(((unit >>> 10) & 0x3ff) | 0xd800);\n unit = 0xdc00 | (unit & 0x3ff);\n }\n units.push(unit);\n }\n else {\n units.push(byte1);\n }\n if (units.length >= CHUNK_SIZE) {\n result += String.fromCharCode(...units);\n units.length = 0;\n }\n }\n if (units.length > 0) {\n result += String.fromCharCode(...units);\n }\n return result;\n}\nconst sharedTextDecoder = new TextDecoder();\n// This threshold should be determined by benchmarking, which might vary in engines and input data.\n// Run `npx ts-node benchmark/decode-string.ts` for details.\nconst TEXT_DECODER_THRESHOLD = 200;\nexport function utf8DecodeTD(bytes, inputOffset, byteLength) {\n const stringBytes = bytes.subarray(inputOffset, inputOffset + byteLength);\n return sharedTextDecoder.decode(stringBytes);\n}\nexport function utf8Decode(bytes, inputOffset, byteLength) {\n if (byteLength > TEXT_DECODER_THRESHOLD) {\n return utf8DecodeTD(bytes, inputOffset, byteLength);\n }\n else {\n return utf8DecodeJs(bytes, inputOffset, byteLength);\n }\n}\n//# sourceMappingURL=utf8.mjs.map","/**\n * ExtData is used to handle Extension Types that are not registered to ExtensionCodec.\n */\nexport class ExtData {\n type;\n data;\n constructor(type, data) {\n this.type = type;\n this.data = data;\n }\n}\n//# sourceMappingURL=ExtData.mjs.map","export class DecodeError extends Error {\n constructor(message) {\n super(message);\n // fix the prototype chain in a cross-platform way\n const proto = Object.create(DecodeError.prototype);\n Object.setPrototypeOf(this, proto);\n Object.defineProperty(this, \"name\", {\n configurable: true,\n enumerable: false,\n value: DecodeError.name,\n });\n }\n}\n//# sourceMappingURL=DecodeError.mjs.map","// Integer Utility\nexport const UINT32_MAX = 4294967295;\n// DataView extension to handle int64 / uint64,\n// where the actual range is 53-bits integer (a.k.a. safe integer)\nexport function setUint64(view, offset, value) {\n const high = value / 4294967296;\n const low = value; // high bits are truncated by DataView\n view.setUint32(offset, high);\n view.setUint32(offset + 4, low);\n}\nexport function setInt64(view, offset, value) {\n const high = Math.floor(value / 4294967296);\n const low = value; // high bits are truncated by DataView\n view.setUint32(offset, high);\n view.setUint32(offset + 4, low);\n}\nexport function getInt64(view, offset) {\n const high = view.getInt32(offset);\n const low = view.getUint32(offset + 4);\n return high * 4294967296 + low;\n}\nexport function getUint64(view, offset) {\n const high = view.getUint32(offset);\n const low = view.getUint32(offset + 4);\n return high * 4294967296 + low;\n}\n//# sourceMappingURL=int.mjs.map","// https://github.com/msgpack/msgpack/blob/master/spec.md#timestamp-extension-type\nimport { DecodeError } from \"./DecodeError.mjs\";\nimport { getInt64, setInt64 } from \"./utils/int.mjs\";\nexport const EXT_TIMESTAMP = -1;\nconst TIMESTAMP32_MAX_SEC = 0x100000000 - 1; // 32-bit unsigned int\nconst TIMESTAMP64_MAX_SEC = 0x400000000 - 1; // 34-bit unsigned int\nexport function encodeTimeSpecToTimestamp({ sec, nsec }) {\n if (sec >= 0 && nsec >= 0 && sec <= TIMESTAMP64_MAX_SEC) {\n // Here sec >= 0 && nsec >= 0\n if (nsec === 0 && sec <= TIMESTAMP32_MAX_SEC) {\n // timestamp 32 = { sec32 (unsigned) }\n const rv = new Uint8Array(4);\n const view = new DataView(rv.buffer);\n view.setUint32(0, sec);\n return rv;\n }\n else {\n // timestamp 64 = { nsec30 (unsigned), sec34 (unsigned) }\n const secHigh = sec / 0x100000000;\n const secLow = sec & 0xffffffff;\n const rv = new Uint8Array(8);\n const view = new DataView(rv.buffer);\n // nsec30 | secHigh2\n view.setUint32(0, (nsec << 2) | (secHigh & 0x3));\n // secLow32\n view.setUint32(4, secLow);\n return rv;\n }\n }\n else {\n // timestamp 96 = { nsec32 (unsigned), sec64 (signed) }\n const rv = new Uint8Array(12);\n const view = new DataView(rv.buffer);\n view.setUint32(0, nsec);\n setInt64(view, 4, sec);\n return rv;\n }\n}\nexport function encodeDateToTimeSpec(date) {\n const msec = date.getTime();\n const sec = Math.floor(msec / 1e3);\n const nsec = (msec - sec * 1e3) * 1e6;\n // Normalizes { sec, nsec } to ensure nsec is unsigned.\n const nsecInSec = Math.floor(nsec / 1e9);\n return {\n sec: sec + nsecInSec,\n nsec: nsec - nsecInSec * 1e9,\n };\n}\nexport function encodeTimestampExtension(object) {\n if (object instanceof Date) {\n const timeSpec = encodeDateToTimeSpec(object);\n return encodeTimeSpecToTimestamp(timeSpec);\n }\n else {\n return null;\n }\n}\nexport function decodeTimestampToTimeSpec(data) {\n const view = new DataView(data.buffer, data.byteOffset, data.byteLength);\n // data may be 32, 64, or 96 bits\n switch (data.byteLength) {\n case 4: {\n // timestamp 32 = { sec32 }\n const sec = view.getUint32(0);\n const nsec = 0;\n return { sec, nsec };\n }\n case 8: {\n // timestamp 64 = { nsec30, sec34 }\n const nsec30AndSecHigh2 = view.getUint32(0);\n const secLow32 = view.getUint32(4);\n const sec = (nsec30AndSecHigh2 & 0x3) * 0x100000000 + secLow32;\n const nsec = nsec30AndSecHigh2 >>> 2;\n return { sec, nsec };\n }\n case 12: {\n // timestamp 96 = { nsec32 (unsigned), sec64 (signed) }\n const sec = getInt64(view, 4);\n const nsec = view.getUint32(0);\n return { sec, nsec };\n }\n default:\n throw new DecodeError(`Unrecognized data size for timestamp (expected 4, 8, or 12): ${data.length}`);\n }\n}\nexport function decodeTimestampExtension(data) {\n const timeSpec = decodeTimestampToTimeSpec(data);\n return new Date(timeSpec.sec * 1e3 + timeSpec.nsec / 1e6);\n}\nexport const timestampExtension = {\n type: EXT_TIMESTAMP,\n encode: encodeTimestampExtension,\n decode: decodeTimestampExtension,\n};\n//# sourceMappingURL=timestamp.mjs.map","// ExtensionCodec to handle MessagePack extensions\nimport { ExtData } from \"./ExtData.mjs\";\nimport { timestampExtension } from \"./timestamp.mjs\";\nexport class ExtensionCodec {\n static defaultCodec = new ExtensionCodec();\n // ensures ExtensionCodecType<X> matches ExtensionCodec<X>\n // this will make type errors a lot more clear\n // eslint-disable-next-line @typescript-eslint/naming-convention\n __brand;\n // built-in extensions\n builtInEncoders = [];\n builtInDecoders = [];\n // custom extensions\n encoders = [];\n decoders = [];\n constructor() {\n this.register(timestampExtension);\n }\n register({ type, encode, decode, }) {\n if (type >= 0) {\n // custom extensions\n this.encoders[type] = encode;\n this.decoders[type] = decode;\n }\n else {\n // built-in extensions\n const index = -1 - type;\n this.builtInEncoders[index] = encode;\n this.builtInDecoders[index] = decode;\n }\n }\n tryToEncode(object, context) {\n // built-in extensions\n for (let i = 0; i < this.builtInEncoders.length; i++) {\n const encodeExt = this.builtInEncoders[i];\n if (encodeExt != null) {\n const data = encodeExt(object, context);\n if (data != null) {\n const type = -1 - i;\n return new ExtData(type, data);\n }\n }\n }\n // custom extensions\n for (let i = 0; i < this.encoders.length; i++) {\n const encodeExt = this.encoders[i];\n if (encodeExt != null) {\n const data = encodeExt(object, context);\n if (data != null) {\n const type = i;\n return new ExtData(type, data);\n }\n }\n }\n if (object instanceof ExtData) {\n // to keep ExtData as is\n return object;\n }\n return null;\n }\n decode(data, type, context) {\n const decodeExt = type < 0 ? this.builtInDecoders[-1 - type] : this.decoders[type];\n if (decodeExt) {\n return decodeExt(data, type, context);\n }\n else {\n // decode() does not fail, returns ExtData instead.\n return new ExtData(type, data);\n }\n }\n}\n//# sourceMappingURL=ExtensionCodec.mjs.map","function isArrayBufferLike(buffer) {\n return (buffer instanceof ArrayBuffer || (typeof SharedArrayBuffer !== \"undefined\" && buffer instanceof SharedArrayBuffer));\n}\nexport function ensureUint8Array(buffer) {\n if (buffer instanceof Uint8Array) {\n return buffer;\n }\n else if (ArrayBuffer.isView(buffer)) {\n return new Uint8Array(buffer.buffer, buffer.byteOffset, buffer.byteLength);\n }\n else if (isArrayBufferLike(buffer)) {\n return new Uint8Array(buffer);\n }\n else {\n // ArrayLike<number>\n return Uint8Array.from(buffer);\n }\n}\n//# sourceMappingURL=typedArrays.mjs.map","import { utf8Count, utf8Encode } from \"./utils/utf8.mjs\";\nimport { ExtensionCodec } from \"./ExtensionCodec.mjs\";\nimport { setInt64, setUint64 } from \"./utils/int.mjs\";\nimport { ensureUint8Array } from \"./utils/typedArrays.mjs\";\nexport const DEFAULT_MAX_DEPTH = 100;\nexport const DEFAULT_INITIAL_BUFFER_SIZE = 2048;\nexport class Encoder {\n extensionCodec;\n context;\n useBigInt64;\n maxDepth;\n initialBufferSize;\n sortKeys;\n forceFloat32;\n ignoreUndefined;\n forceIntegerToFloat;\n pos;\n view;\n bytes;\n entered = false;\n constructor(options) {\n this.extensionCodec = options?.extensionCodec ?? ExtensionCodec.defaultCodec;\n this.context = options?.context; // needs a type assertion because EncoderOptions has no context property when ContextType is undefined\n this.useBigInt64 = options?.useBigInt64 ?? false;\n this.maxDepth = options?.maxDepth ?? DEFAULT_MAX_DEPTH;\n this.initialBufferSize = options?.initialBufferSize ?? DEFAULT_INITIAL_BUFFER_SIZE;\n this.sortKeys = options?.sortKeys ?? false;\n this.forceFloat32 = options?.forceFloat32 ?? false;\n this.ignoreUndefined = options?.ignoreUndefined ?? false;\n this.forceIntegerToFloat = options?.forceIntegerToFloat ?? false;\n this.pos = 0;\n this.view = new DataView(new ArrayBuffer(this.initialBufferSize));\n this.bytes = new Uint8Array(this.view.buffer);\n }\n clone() {\n // Because of slightly special argument `context`,\n // type assertion is needed.\n // eslint-disable-next-line @typescript-eslint/no-unsafe-argument\n return new Encoder({\n extensionCodec: this.extensionCodec,\n context: this.context,\n useBigInt64: this.useBigInt64,\n maxDepth: this.maxDepth,\n initialBufferSize: this.initialBufferSize,\n sortKeys: this.sortKeys,\n forceFloat32: this.forceFloat32,\n ignoreUndefined: this.ignoreUndefined,\n forceIntegerToFloat: this.forceIntegerToFloat,\n });\n }\n reinitializeState() {\n this.pos = 0;\n }\n /**\n * This is almost equivalent to {@link Encoder#encode}, but it returns an reference of the encoder's internal buffer and thus much faster than {@link Encoder#encode}.\n *\n * @returns Encodes the object and returns a shared reference the encoder's internal buffer.\n */\n encodeSharedRef(object) {\n if (this.entered) {\n const instance = this.clone();\n return instance.encodeSharedRef(object);\n }\n try {\n this.entered = true;\n this.reinitializeState();\n this.doEncode(object, 1);\n return this.bytes.subarray(0, this.pos);\n }\n finally {\n this.entered = false;\n }\n }\n /**\n * @returns Encodes the object and returns a copy of the encoder's internal buffer.\n */\n encode(object) {\n if (this.entered) {\n const instance = this.clone();\n return instance.encode(object);\n }\n try {\n this.entered = true;\n this.reinitializeState();\n this.doEncode(object, 1);\n return this.bytes.slice(0, this.pos);\n }\n finally {\n this.entered = false;\n }\n }\n doEncode(object, depth) {\n if (depth > this.maxDepth) {\n throw new Error(`Too deep objects in depth ${depth}`);\n }\n if (object == null) {\n this.encodeNil();\n }\n else if (typeof object === \"boolean\") {\n this.encodeBoolean(object);\n }\n else if (typeof object === \"number\") {\n if (!this.forceIntegerToFloat) {\n this.encodeNumber(object);\n }\n else {\n this.encodeNumberAsFloat(object);\n }\n }\n else if (typeof object === \"string\") {\n this.encodeString(object);\n }\n else if (this.useBigInt64 && typeof object === \"bigint\") {\n this.encodeBigInt64(object);\n }\n else {\n this.encodeObject(object, depth);\n }\n }\n ensureBufferSizeToWrite(sizeToWrite) {\n const requiredSize = this.pos + sizeToWrite;\n if (this.view.byteLength < requiredSize) {\n this.resizeBuffer(requiredSize * 2);\n }\n }\n resizeBuffer(newSize) {\n const newBuffer = new ArrayBuffer(newSize);\n const newBytes = new Uint8Array(newBuffer);\n const newView = new DataView(newBuffer);\n newBytes.set(this.bytes);\n this.view = newView;\n this.bytes = newBytes;\n }\n encodeNil() {\n this.writeU8(0xc0);\n }\n encodeBoolean(object) {\n if (object === false) {\n this.writeU8(0xc2);\n }\n else {\n this.writeU8(0xc3);\n }\n }\n encodeNumber(object) {\n if (!this.forceIntegerToFloat && Number.isSafeInteger(object)) {\n if (object >= 0) {\n if (object < 0x80) {\n // positive fixint\n this.writeU8(object);\n }\n else if (object < 0x100) {\n // uint 8\n this.writeU8(0xcc);\n this.writeU8(object);\n }\n else if (object < 0x10000) {\n // uint 16\n this.writeU8(0xcd);\n this.writeU16(object);\n }\n else if (object < 0x100000000) {\n // uint 32\n this.writeU8(0xce);\n this.writeU32(object);\n }\n else if (!this.useBigInt64) {\n // uint 64\n this.writeU8(0xcf);\n this.writeU64(object);\n }\n else {\n this.encodeNumberAsFloat(object);\n }\n }\n else {\n if (object >= -0x20) {\n // negative fixint\n this.writeU8(0xe0 | (object + 0x20));\n }\n else if (object >= -0x80) {\n // int 8\n this.writeU8(0xd0);\n this.writeI8(object);\n }\n else if (object >= -0x8000) {\n // int 16\n this.writeU8(0xd1);\n this.writeI16(object);\n }\n else if (object >= -0x80000000) {\n // int 32\n this.writeU8(0xd2);\n this.writeI32(object);\n }\n else if (!this.useBigInt64) {\n // int 64\n this.writeU8(0xd3);\n this.writeI64(object);\n }\n else {\n this.encodeNumberAsFloat(object);\n }\n }\n }\n else {\n this.encodeNumberAsFloat(object);\n }\n }\n encodeNumberAsFloat(object) {\n if (this.forceFloat32) {\n // float 32\n this.writeU8(0xca);\n this.writeF32(object);\n }\n else {\n // float 64\n this.writeU8(0xcb);\n this.writeF64(object);\n }\n }\n encodeBigInt64(object) {\n if (object >= BigInt(0)) {\n // uint 64\n this.writeU8(0xcf);\n this.writeBigUint64(object);\n }\n else {\n // int 64\n this.writeU8(0xd3);\n this.writeBigInt64(object);\n }\n }\n writeStringHeader(byteLength) {\n if (byteLength < 32) {\n // fixstr\n this.writeU8(0xa0 + byteLength);\n }\n else if (byteLength < 0x100) {\n // str 8\n this.writeU8(0xd9);\n this.writeU8(byteLength);\n }\n else if (byteLength < 0x10000) {\n // str 16\n this.writeU8(0xda);\n this.writeU16(byteLength);\n }\n else if (byteLength < 0x100000000) {\n // str 32\n this.writeU8(0xdb);\n this.writeU32(byteLength);\n }\n else {\n throw new Error(`Too long string: ${byteLength} bytes in UTF-8`);\n }\n }\n encodeString(object) {\n const maxHeaderSize = 1 + 4;\n const byteLength = utf8Count(object);\n this.ensureBufferSizeToWrite(maxHeaderSize + byteLength);\n this.writeStringHeader(byteLength);\n utf8Encode(object, this.bytes, this.pos);\n this.pos += byteLength;\n }\n encodeObject(object, depth) {\n // try to encode objects with custom codec first of non-primitives\n const ext = this.extensionCodec.tryToEncode(object, this.context);\n if (ext != null) {\n this.encodeExtension(ext);\n }\n else if (Array.isArray(object)) {\n this.encodeArray(object, depth);\n }\n else if (ArrayBuffer.isView(object)) {\n this.encodeBinary(object);\n }\n else if (typeof object === \"object\") {\n this.encodeMap(object, depth);\n }\n else {\n // symbol, function and other special object come here unless extensionCodec handles them.\n throw new Error(`Unrecognized object: ${Object.prototype.toString.apply(object)}`);\n }\n }\n encodeBinary(object) {\n const size = object.byteLength;\n if (size < 0x100) {\n // bin 8\n this.writeU8(0xc4);\n this.writeU8(size);\n }\n else if (size < 0x10000) {\n // bin 16\n this.writeU8(0xc5);\n this.writeU16(size);\n }\n else if (size < 0x100000000) {\n // bin 32\n this.writeU8(0xc6);\n this.writeU32(size);\n }\n else {\n throw new Error(`Too large binary: ${size}`);\n }\n const bytes = ensureUint8Array(object);\n this.writeU8a(bytes);\n }\n encodeArray(object, depth) {\n const size = object.length;\n if (size < 16) {\n // fixarray\n this.writeU8(0x90 + size);\n }\n else if (size < 0x10000) {\n // array 16\n this.writeU8(0xdc);\n this.writeU16(size);\n }\n else if (size < 0x100000000) {\n // array 32\n this.writeU8(0xdd);\n this.writeU32(size);\n }\n else {\n throw new Error(`Too large array: ${size}`);\n }\n for (const item of object) {\n this.doEncode(item, depth + 1);\n }\n }\n countWithoutUndefined(object, keys) {\n let count = 0;\n for (const key of keys) {\n if (object[key] !== undefined) {\n count++;\n }\n }\n return count;\n }\n encodeMap(object, depth) {\n const keys = Object.keys(object);\n if (this.sortKeys) {\n keys.sort();\n }\n const size = this.ignoreUndefined ? this.countWithoutUndefined(object, keys) : keys.length;\n if (size < 16) {\n // fixmap\n this.writeU8(0x80 + size);\n }\n else if (size < 0x10000) {\n // map 16\n this.writeU8(0xde);\n this.writeU16(size);\n }\n else if (size < 0x100000000) {\n // map 32\n this.writeU8(0xdf);\n this.writeU32(size);\n }\n else {\n throw new Error(`Too large map object: ${size}`);\n }\n for (const key of keys) {\n const value = object[key];\n if (!(this.ignoreUndefined && value === undefined)) {\n this.encodeString(key);\n this.doEncode(value, depth + 1);\n }\n }\n }\n encodeExtension(ext) {\n if (typeof ext.data === \"function\") {\n const data = ext.data(this.pos + 6);\n const size = data.length;\n if (size >= 0x100000000) {\n throw new Error(`Too large extension object: ${size}`);\n }\n this.writeU8(0xc9);\n this.writeU32(size);\n this.writeI8(ext.type);\n this.writeU8a(data);\n return;\n }\n const size = ext.data.length;\n if (size === 1) {\n // fixext 1\n this.writeU8(0xd4);\n }\n else if (size === 2) {\n // fixext 2\n this.writeU8(0xd5);\n }\n else if (size === 4) {\n // fixext 4\n this.writeU8(0xd6);\n }\n else if (size === 8) {\n // fixext 8\n this.writeU8(0xd7);\n }\n else if (size === 16) {\n // fixext 16\n this.writeU8(0xd8);\n }\n else if (size < 0x100) {\n // ext 8\n this.writeU8(0xc7);\n this.writeU8(size);\n }\n else if (size < 0x10000) {\n // ext 16\n this.writeU8(0xc8);\n this.writeU16(size);\n }\n else if (size < 0x100000000) {\n // ext 32\n this.writeU8(0xc9);\n this.writeU32(size);\n }\n else {\n throw new Error(`Too large extension object: ${size}`);\n }\n this.writeI8(ext.type);\n this.writeU8a(ext.data);\n }\n writeU8(value) {\n this.ensureBufferSizeToWrite(1);\n this.view.setUint8(this.pos, value);\n this.pos++;\n }\n writeU8a(values) {\n const size = values.length;\n this.ensureBufferSizeToWrite(size);\n this.bytes.set(values, this.pos);\n this.pos += size;\n }\n writeI8(value) {\n this.ensureBufferSizeToWrite(1);\n this.view.setInt8(this.pos, value);\n this.pos++;\n }\n writeU16(value) {\n this.ensureBufferSizeToWrite(2);\n this.view.setUint16(this.pos, value);\n this.pos += 2;\n }\n writeI16(value) {\n this.ensureBufferSizeToWrite(2);\n this.view.setInt16(this.pos, value);\n this.pos += 2;\n }\n writeU32(value) {\n this.ensureBufferSizeToWrite(4);\n this.view.setUint32(this.pos, value);\n this.pos += 4;\n }\n writeI32(value) {\n this.ensureBufferSizeToWrite(4);\n this.view.setInt32(this.pos, value);\n this.pos += 4;\n }\n writeF32(value) {\n this.ensureBufferSizeToWrite(4);\n this.view.setFloat32(this.pos, value);\n this.pos += 4;\n }\n writeF64(value) {\n this.ensureBufferSizeToWrite(8);\n this.view.setFloat64(this.pos, value);\n this.pos += 8;\n }\n writeU64(value) {\n this.ensureBufferSizeToWrite(8);\n setUint64(this.view, this.pos, value);\n this.pos += 8;\n }\n writeI64(value) {\n this.ensureBufferSizeToWrite(8);\n setInt64(this.view, this.pos, value);\n this.pos += 8;\n }\n writeBigUint64(value) {\n this.ensureBufferSizeToWrite(8);\n this.view.setBigUint64(this.pos, value);\n this.pos += 8;\n }\n writeBigInt64(value) {\n this.ensureBufferSizeToWrite(8);\n this.view.setBigInt64(this.pos, value);\n this.pos += 8;\n }\n}\n//# sourceMappingURL=Encoder.mjs.map","import { Encoder } from \"./Encoder.mjs\";\n/**\n * It encodes `value` in the MessagePack format and\n * returns a byte buffer.\n *\n * The returned buffer is a slice of a larger `ArrayBuffer`, so you have to use its `#byteOffset` and `#byteLength` in order to convert it to another typed arrays including NodeJS `Buffer`.\n */\nexport function encode(value, options) {\n const encoder = new Encoder(options);\n return encoder.encodeSharedRef(value);\n}\n//# sourceMappingURL=encode.mjs.map","export function prettyByte(byte) {\n return `${byte < 0 ? \"-\" : \"\"}0x${Math.abs(byte).toString(16).padStart(2, \"0\")}`;\n}\n//# sourceMappingURL=prettyByte.mjs.map","import { utf8DecodeJs } from \"./utils/utf8.mjs\";\nconst DEFAULT_MAX_KEY_LENGTH = 16;\nconst DEFAULT_MAX_LENGTH_PER_KEY = 16;\nexport class CachedKeyDecoder {\n hit = 0;\n miss = 0;\n caches;\n maxKeyLength;\n maxLengthPerKey;\n constructor(maxKeyLength = DEFAULT_MAX_KEY_LENGTH, maxLengthPerKey = DEFAULT_MAX_LENGTH_PER_KEY) {\n this.maxKeyLength = maxKeyLength;\n this.maxLengthPerKey = maxLengthPerKey;\n // avoid `new Array(N)`, which makes a sparse array,\n // because a sparse array is typically slower than a non-sparse array.\n this.caches = [];\n for (let i = 0; i < this.maxKeyLength; i++) {\n this.caches.push([]);\n }\n }\n canBeCached(byteLength) {\n return byteLength > 0 && byteLength <= this.maxKeyLength;\n }\n find(bytes, inputOffset, byteLength) {\n const records = this.caches[byteLength - 1];\n FIND_CHUNK: for (const record of records) {\n const recordBytes = record.bytes;\n for (let j = 0; j < byteLength; j++) {\n if (recordBytes[j] !== bytes[inputOffset + j]) {\n continue FIND_CHUNK;\n }\n }\n return record.str;\n }\n return null;\n }\n store(bytes, value) {\n const records = this.caches[bytes.length - 1];\n const record = { bytes, str: value };\n if (records.length >= this.maxLengthPerKey) {\n // `records` are full!\n // Set `record` to an arbitrary position.\n records[(Math.random() * records.length) | 0] = record;\n }\n else {\n records.push(record);\n }\n }\n decode(bytes, inputOffset, byteLength) {\n const cachedValue = this.find(bytes, inputOffset, byteLength);\n if (cachedValue != null) {\n this.hit++;\n return cachedValue;\n }\n this.miss++;\n const str = utf8DecodeJs(bytes, inputOffset, byteLength);\n // Ensure to copy a slice of bytes because the bytes may be a NodeJS Buffer and Buffer#slice() returns a reference to its internal ArrayBuffer.\n const slicedCopyOfBytes = Uint8Array.prototype.slice.call(bytes, inputOffset, inputOffset + byteLength);\n this.store(slicedCopyOfBytes, str);\n return str;\n }\n}\n//# sourceMappingURL=CachedKeyDecoder.mjs.map","import { prettyByte } from \"./utils/prettyByte.mjs\";\nimport { ExtensionCodec } from \"./ExtensionCodec.mjs\";\nimport { getInt64, getUint64, UINT32_MAX } from \"./utils/int.mjs\";\nimport { utf8Decode } from \"./utils/utf8.mjs\";\nimport { ensureUint8Array } from \"./utils/typedArrays.mjs\";\nimport { CachedKeyDecoder } from \"./CachedKeyDecoder.mjs\";\nimport { DecodeError } from \"./DecodeError.mjs\";\nconst STATE_ARRAY = \"array\";\nconst STATE_MAP_KEY = \"map_key\";\nconst STATE_MAP_VALUE = \"map_value\";\nconst mapKeyConverter = (key) => {\n if (typeof key === \"string\" || typeof key === \"number\") {\n return key;\n }\n throw new DecodeError(\"The type of key must be string or number but \" + typeof key);\n};\nclass StackPool {\n stack = [];\n stackHeadPosition = -1;\n get length() {\n return this.stackHeadPosition + 1;\n }\n top() {\n return this.stack[this.stackHeadPosition];\n }\n pushArrayState(size) {\n const state = this.getUninitializedStateFromPool();\n state.type = STATE_ARRAY;\n state.position = 0;\n state.size = size;\n state.array = new Array(size);\n }\n pushMapState(size) {\n const state = this.getUninitializedStateFromPool();\n state.type = STATE_MAP_KEY;\n state.readCount = 0;\n state.size = size;\n state.map = {};\n }\n getUninitializedStateFromPool() {\n this.stackHeadPosition++;\n if (this.stackHeadPosition === this.stack.length) {\n const partialState = {\n type: undefined,\n size: 0,\n array: undefined,\n position: 0,\n readCount: 0,\n map: undefined,\n key: null,\n };\n this.stack.push(partialState);\n }\n return this.stack[this.stackHeadPosition];\n }\n release(state) {\n const topStackState = this.stack[this.stackHeadPosition];\n if (topStackState !== state) {\n throw new Error(\"Invalid stack state. Released state is not on top of the stack.\");\n }\n if (state.type === STATE_ARRAY) {\n const partialState = state;\n partialState.size = 0;\n partialState.array = undefined;\n partialState.position = 0;\n partialState.type = undefined;\n }\n if (state.type === STATE_MAP_KEY || state.type === STATE_MAP_VALUE) {\n const partialState = state;\n partialState.size = 0;\n partialState.map = undefined;\n partialState.readCount = 0;\n partialState.type = undefined;\n }\n this.stackHeadPosition--;\n }\n reset() {\n this.stack.length = 0;\n this.stackHeadPosition = -1;\n }\n}\nconst HEAD_BYTE_REQUIRED = -1;\nconst EMPTY_VIEW = new DataView(new ArrayBuffer(0));\nconst EMPTY_BYTES = new Uint8Array(EMPTY_VIEW.buffer);\ntry {\n // IE11: The spec says it should throw RangeError,\n // IE11: but in IE11 it throws TypeError.\n EMPTY_VIEW.getInt8(0);\n}\ncatch (e) {\n if (!(e instanceof RangeError)) {\n throw new Error(\"This module is not supported in the current JavaScript engine because DataView does not throw RangeError on out-of-bounds access\");\n }\n}\nconst MORE_DATA = new RangeError(\"Insufficient data\");\nconst sharedCachedKeyDecoder = new CachedKeyDecoder();\nexport class Decoder {\n extensionCodec;\n context;\n useBigInt64;\n rawStrings;\n maxStrLength;\n maxBinLength;\n maxArrayLength;\n maxMapLength;\n maxExtLength;\n keyDecoder;\n mapKeyConverter;\n totalPos = 0;\n pos = 0;\n view = EMPTY_VIEW;\n bytes = EMPTY_BYTES;\n headByte = HEAD_BYTE_REQUIRED;\n stack = new StackPool();\n entered = false;\n constructor(options) {\n this.extensionCodec = options?.extensionCodec ?? ExtensionCodec.defaultCodec;\n this.context = options?.context; // needs a type assertion because EncoderOptions has no context property when ContextType is undefined\n this.useBigInt64 = options?.useBigInt64 ?? false;\n this.rawStrings = options?.rawStrings ?? false;\n this.maxStrLength = options?.maxStrLength ?? UINT32_MAX;\n this.maxBinLength = options?.maxBinLength ?? UINT32_MAX;\n this.maxArrayLength = options?.maxArrayLength ?? UINT32_MAX;\n this.maxMapLength = options?.maxMapLength ?? UINT32_MAX;\n this.maxExtLength = options?.maxExtLength ?? UINT32_MAX;\n this.keyDecoder = options?.keyDecoder !== undefined ? options.keyDecoder : sharedCachedKeyDecoder;\n this.mapKeyConverter = options?.mapKeyConverter ?? mapKeyConverter;\n }\n clone() {\n // eslint-disable-next-line @typescript-eslint/no-unsafe-argument\n return new Decoder({\n extensionCodec: this.extensionCodec,\n context: this.context,\n useBigInt64: this.useBigInt64,\n rawStrings: this.rawStrings,\n maxStrLength: this.maxStrLength,\n maxBinLength: this.maxBinLength,\n maxArrayLength: this.maxArrayLength,\n maxMapLength: this.maxMapLength,\n maxExtLength: this.maxExtLength,\n keyDecoder: this.keyDecoder,\n });\n }\n reinitializeState() {\n this.totalPos = 0;\n this.headByte = HEAD_BYTE_REQUIRED;\n this.stack.reset();\n // view, bytes, and pos will be re-initialized in setBuffer()\n }\n setBuffer(buffer) {\n const bytes = ensureUint8Array(buffer);\n this.bytes = bytes;\n this.view = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);\n this.pos = 0;\n }\n appendBuffer(buffer) {\n if (this.headByte === HEAD_BYTE_REQUIRED && !this.hasRemaining(1)) {\n this.setBuffer(buffer);\n }\n else {\n const remainingData = this.bytes.subarray(this.pos);\n const newData = ensureUint8Array(buffer);\n // concat remainingData + newData\n const newBuffer = new Uint8Array(remainingData.length + newData.length);\n newBuffer.set(remainingData);\n newBuffer.set(newData, remainingData.length);\n this.setBuffer(newBuffer);\n }\n }\n hasRemaining(size) {\n return this.view.byteLength - this.pos >= size;\n }\n createExtraByteError(posToShow) {\n const { view, pos } = this;\n return new RangeError(`Extra ${view.byteLength - pos} of ${view.byteLength} byte(s) found at buffer[${posToShow}]`);\n }\n /**\n * @throws {@link DecodeError}\n * @throws {@link RangeError}\n */\n decode(buffer) {\n if (this.entered) {\n const instance = this.clone();\n return instance.decode(buffer);\n }\n try {\n this.entered = true;\n this.reinitializeState();\n this.setBuffer(buffer);\n const object = this.doDecodeSync();\n if (this.hasRemaining(1)) {\n throw this.createExtraByteError(this.pos);\n }\n return object;\n }\n finally {\n this.entered = false;\n }\n }\n *decodeMulti(buffer) {\n if (this.entered) {\n const instance = this.clone();\n yield* instance.decodeMulti(buffer);\n return;\n }\n try {\n this.entered = true;\n this.reinitializeState();\n this.setBuffer(buffer);\n while (this.hasRemaining(1)) {\n yield this.doDecodeSync();\n }\n }\n finally {\n this.entered = false;\n }\n }\n async decodeAsync(stream) {\n if (this.entered) {\n const instance = this.clone();\n return instance.decodeAsync(stream);\n }\n try {\n this.entered = true;\n let decoded = false;\n let object;\n for await (const buffer of stream) {\n if (decoded) {\n this.entered = false;\n throw this.createExtraByteError(this.totalPos);\n }\n this.appendBuffer(buffer);\n try {\n object = this.doDecodeSync();\n decoded = true;\n }\n catch (e) {\n if (!(e instanceof RangeError)) {\n throw e; // rethrow\n }\n // fallthrough\n }\n this.totalPos += this.pos;\n }\n if (decoded) {\n if (this.hasRemaining(1)) {\n throw this.createExtraByteError(this.totalPos);\n }\n return object;\n }\n const { headByte, pos, totalPos } = this;\n throw new RangeError(`Insufficient data in parsing ${prettyByte(headByte)} at ${totalPos} (${pos} in the current buffer)`);\n }\n finally {\n this.entered = false;\n }\n }\n decodeArrayStream(stream) {\n return this.decodeMultiAsync(stream, true);\n }\n decodeStream(stream) {\n return this.decodeMultiAsync(stream, false);\n }\n async *decodeMultiAsync(stream, isArray) {\n if (this.entered) {\n const instance = this.clone();\n yield* instance.decodeMultiAsync(stream, isArray);\n return;\n }\n try {\n this.entered = true;\n let isArrayHeaderRequired = isArray;\n let arrayItemsLeft = -1;\n for await (const buffer of stream) {\n if (isArray && arrayItemsLeft === 0) {\n throw this.createExtraByteError(this.totalPos);\n }\n this.appendBuffer(buffer);\n if (isArrayHeaderRequired) {\n arrayItemsLeft = this.readArraySize();\n isArrayHeaderRequired = false;\n this.complete();\n }\n try {\n while (true) {\n yield this.doDecodeSync();\n if (--arrayItemsLeft === 0) {\n break;\n }\n }\n }\n catch (e) {\n if (!(e instanceof RangeError)) {\n throw e; // rethrow\n }\n // fallthrough\n }\n this.totalPos += this.pos;\n }\n }\n finally {\n this.entered = false;\n }\n }\n doDecodeSync() {\n DECODE: while (true) {\n const headByte = this.readHeadByte();\n let object;\n if (headByte >= 0xe0) {\n // negative fixint (111x xxxx) 0xe0 - 0xff\n object = headByte - 0x100;\n }\n else if (headByte < 0xc0) {\n if (headByte < 0x80) {\n // positive fixint (0xxx xxxx) 0x00 - 0x7f\n object = headByte;\n }\n else if (headByte < 0x90) {\n // fixmap (1000 xxxx) 0x80 - 0x8f\n const size = headByte - 0x80;\n if (size !== 0) {\n this.pushMapState(size);\n this.complete();\n continue DECODE;\n }\n else {\n object = {};\n }\n }\n else if (headByte < 0xa0) {\n // fixarray (1001 xxxx) 0x90 - 0x9f\n const size = headByte - 0x90;\n if (size !== 0) {\n this.pushArrayState(size);\n this.complete();\n continue DECODE;\n }\n else {\n object = [];\n }\n }\n else {\n // fixstr (101x xxxx) 0xa0 - 0xbf\n const byteLength = headByte - 0xa0;\n object = this.decodeString(byteLength, 0);\n }\n }\n else if (headByte === 0xc0) {\n // nil\n object = null;\n }\n else if (headByte === 0xc2) {\n // false\n object = false;\n }\n else if (headByte === 0xc3) {\n // true\n object = true;\n }\n else if (headByte === 0xca) {\n // float 32\n object = this.readF32();\n }\n else if (headByte === 0xcb) {\n // float 64\n object = this.readF64();\n }\n else if (headByte === 0xcc) {\n // uint 8\n object = this.readU8();\n }\n else if (headByte === 0xcd) {\n // uint 16\n object = this.readU16();\n }\n else if (headByte === 0xce) {\n // uint 32\n object = this.readU32();\n }\n else if (headByte === 0xcf) {\n // uint 64\n if (this.useBigInt64) {\n object = this.readU64AsBigInt();\n }\n else {\n object = this.readU64();\n }\n }\n else if (headByte === 0xd0) {\n // int 8\n object = this.readI8();\n }\n else if (headByte === 0xd1) {\n // int 16\n object = this.readI16();\n }\n else if (headByte === 0xd2) {\n // int 32\n object = this.readI32();\n }\n else if (headByte === 0xd3) {\n // int 64\n if (this.useBigInt64) {\n object = this.readI64AsBigInt();\n }\n else {\n object = this.readI64();\n }\n }\n else if (headByte === 0xd9) {\n // str 8\n const byteLength = this.lookU8();\n object = this.decodeString(byteLength, 1);\n }\n else if (headByte === 0xda) {\n // str 16\n const byteLength = this.lookU16();\n object = this.decodeString(byteLength, 2);\n }\n else if (headByte === 0xdb) {\n // str 32\n const byteLength = this.lookU32();\n object = this.decodeString(byteLength, 4);\n }\n else if (headByte === 0xdc) {\n // array 16\n const size = this.readU16();\n if (size !== 0) {\n this.pushArrayState(size);\n this.complete();\n continue DECODE;\n }\n else {\n object = [];\n }\n }\n else if (headByte === 0xdd) {\n // array 32\n const size = this.readU32();\n if (size !== 0) {\n this.pushArrayState(size);\n this.complete();\n continue DECODE;\n }\n else {\n object = [];\n }\n }\n else if (headByte === 0xde) {\n // map 16\n const size = this.readU16();\n if (size !== 0) {\n this.pushMapState(size);\n this.complete();\n continue DECODE;\n }\n else {\n object = {};\n }\n }\n else if (headByte === 0xdf) {\n // map 32\n const size = this.readU32();\n if (size !== 0) {\n this.pushMapState(size);\n this.complete();\n continue DECODE;\n }\n else {\n object = {};\n }\n }\n else if (headByte === 0xc4) {\n // bin 8\n const size = this.lookU8();\n object = this.decodeBinary(size, 1);\n }\n else if (headByte === 0xc5) {\n // bin 16\n const size = this.lookU16();\n object = this.decodeBinary(size, 2);\n }\n else if (headByte === 0xc6) {\n // bin 32\n const size = this.lookU32();\n object = this.decodeBinary(size, 4);\n }\n else if (headByte === 0xd4) {\n // fixext 1\n object = this.decodeExtension(1, 0);\n }\n else if (headByte === 0xd5) {\n // fixext 2\n object = this.decodeExtension(2, 0);\n }\n else if (headByte === 0xd6) {\n // fixext 4\n object = this.decodeExtension(4, 0);\n }\n else if (headByte === 0xd7) {\n // fixext 8\n object = this.decodeExtension(8, 0);\n }\n else if (headByte === 0xd8) {\n // fixext 16\n object = this.decodeExtension(16, 0);\n }\n else if (headByte === 0xc7) {\n // ext 8\n const size = this.lookU8();\n object = this.decodeExtension(size, 1);\n }\n else if (headByte === 0xc8) {\n // ext 16\n const size = this.lookU16();\n object = this.decodeExtension(size, 2);\n }\n else if (headByte === 0xc9) {\n // ext 32\n const size = this.lookU32();\n object = this.decodeExtension(size, 4);\n }\n else {\n throw new DecodeError(`Unrecognized type byte: ${prettyByte(headByte)}`);\n }\n this.complete();\n const stack = this.stack;\n while (stack.length > 0) {\n // arrays and maps\n const state = stack.top();\n if (state.type === STATE_ARRAY) {\n state.array[state.position] = object;\n state.position++;\n if (state.position === state.size) {\n object = state.array;\n stack.release(state);\n }\n else {\n continue DECODE;\n }\n }\n else if (state.type === STATE_MAP_KEY) {\n if (object === \"__proto__\") {\n throw new DecodeError(\"The key __proto__ is not allowed\");\n }\n state.key = this.mapKeyConverter(object);\n state.type = STATE_MAP_VALUE;\n continue DECODE;\n }\n else {\n // it must be `state.type === State.MAP_VALUE` here\n state.map[state.key] = object;\n state.readCount++;\n if (state.readCount === state.size) {\n object = state.map;\n stack.release(state);\n }\n else {\n state.key = null;\n state.type = STATE_MAP_KEY;\n continue DECODE;\n }\n }\n }\n return object;\n }\n }\n readHeadByte() {\n if (this.headByte === HEAD_BYTE_REQUIRED) {\n this.headByte = this.readU8();\n // console.log(\"headByte\", prettyByte(this.headByte));\n }\n return this.headByte;\n }\n complete() {\n this.headByte = HEAD_BYTE_REQUIRED;\n }\n readArraySize() {\n const headByte = this.readHeadByte();\n switch (headByte) {\n case 0xdc:\n return this.readU16();\n case 0xdd:\n return this.readU32();\n default: {\n if (headByte < 0xa0) {\n return headByte - 0x90;\n }\n else {\n throw new DecodeError(`Unrecognized array type byte: ${prettyByte(headByte)}`);\n }\n }\n }\n }\n pushMapState(size) {\n if (size > this.maxMapLength) {\n throw new DecodeError(`Max length exceeded: map length (${size}) > maxMapLengthLength (${this.maxMapLength})`);\n }\n this.stack.pushMapState(size);\n }\n pushArrayState(size) {\n if (size > this.maxArrayLength) {\n throw new DecodeError(`Max length exceeded: array length (${size}) > maxArrayLength (${this.maxArrayLength})`);\n }\n this.stack.pushArrayState(size);\n }\n decodeString(byteLength, headerOffset) {\n if (!this.rawStrings || this.stateIsMapKey()) {\n return this.decodeUtf8String(byteLength, headerOffset);\n }\n return this.decodeBinary(byteLength, headerOffset);\n }\n /**\n * @throws {@link RangeError}\n */\n decodeUtf8String(byteLength, headerOffset) {\n if (byteLength > this.maxStrLength) {\n throw new DecodeError(`Max length exceeded: UTF-8 byte length (${byteLength}) > maxStrLength (${this.maxStrLength})`);\n }\n if (this.bytes.byteLength < this.pos + headerOffset + byteLength) {\n throw MORE_DATA;\n }\n const offset = this.pos + headerOffset;\n let object;\n if (this.stateIsMapKey() && this.keyDecoder?.canBeCached(byteLength)) {\n object = this.keyDecoder.decode(this.bytes, offset, byteLength);\n }\n else {\n object = utf8Decode(this.bytes, offset, byteLength);\n }\n this.pos += headerOffset + byteLength;\n return object;\n }\n stateIsMapKey() {\n if (this.stack.length > 0) {\n const state = this.stack.top();\n return state.type === STATE_MAP_KEY;\n }\n return false;\n }\n /**\n * @throws {@link RangeError}\n */\n decodeBinary(byteLength, headOffset) {\n if (byteLength > this.maxBinLength) {\n throw new DecodeError(`Max length exceeded: bin length (${byteLength}) > maxBinLength (${this.maxBinLength})`);\n }\n if (!this.hasRemaining(byteLength + headOffset)) {\n throw MORE_DATA;\n }\n const offset = this.pos + headOffset;\n const object = this.bytes.subarray(offset, offset + byteLength);\n this.pos += headOffset + byteLength;\n return object;\n }\n decodeExtension(size, headOffset) {\n if (size > this.maxExtLength) {\n throw new DecodeError(`Max length exceeded: ext length (${size}) > maxExtLength (${this.maxExtLength})`);\n }\n const extType = this.view.getInt8(this.pos + headOffset);\n const data = this.decodeBinary(size, headOffset + 1 /* extType */);\n return this.extensionCodec.decode(data, extType, this.context);\n }\n lookU8() {\n return this.view.getUint8(this.pos);\n }\n lookU16() {\n return this.view.getUint16(this.pos);\n }\n lookU32() {\n return this.view.getUint32(this.pos);\n }\n readU8() {\n const value = this.view.getUint8(this.pos);\n this.pos++;\n return value;\n }\n readI8() {\n const value = this.view.getInt8(this.pos);\n this.pos++;\n return value;\n }\n readU16() {\n const value = this.view.getUint16(this.pos);\n this.pos += 2;\n return value;\n }\n readI16() {\n const value = this.view.getInt16(this.pos);\n this.pos += 2;\n return value;\n }\n readU32() {\n const value = this.view.getUint32(this.pos);\n this.pos += 4;\n return value;\n }\n readI32() {\n const value = this.view.getInt32(this.pos);\n this.pos += 4;\n return value;\n }\n readU64() {\n const value = getUint64(this.view, this.pos);\n this.pos += 8;\n return value;\n }\n readI64() {\n const value = getInt64(this.view, this.pos);\n this.pos += 8;\n return value;\n }\n readU64AsBigInt() {\n const value = this.view.getBigUint64(this.pos);\n this.pos += 8;\n return value;\n }\n readI64AsBigInt() {\n const value = this.view.getBigInt64(this.pos);\n this.pos += 8;\n return value;\n }\n readF32() {\n const value = this.view.getFloat32(this.pos);\n this.pos += 4;\n return value;\n }\n readF64() {\n const value = this.view.getFloat64(this.pos);\n this.pos += 8;\n return value;\n }\n}\n//# sourceMappingURL=Decoder.mjs.map","import { Decoder } from \"./Decoder.mjs\";\n/**\n * It decodes a single MessagePack object in a buffer.\n *\n * This is a synchronous decoding function.\n * See other variants for asynchronous decoding: {@link decodeAsync}, {@link decodeMultiStream}, or {@link decodeArrayStream}.\n *\n * @throws {@link RangeError} if the buffer is incomplete, including the case where the buffer is empty.\n * @throws {@link DecodeError} if the buffer contains invalid data.\n */\nexport function decode(buffer, options) {\n const decoder = new Decoder(options);\n return decoder.decode(buffer);\n}\n/**\n * It decodes multiple MessagePack objects in a buffer.\n * This is corresponding to {@link decodeMultiStream}.\n *\n * @throws {@link RangeError} if the buffer is incomplete, including the case where the buffer is empty.\n * @throws {@link DecodeError} if the buffer contains invalid data.\n */\nexport function decodeMulti(buffer, options) {\n const decoder = new Decoder(options);\n return decoder.decodeMulti(buffer);\n}\n//# sourceMappingURL=decode.mjs.map","import { encode as mpEncode, decode as mpDecode } from '@msgpack/msgpack'\nimport type { ClientFrame, ServerFrame } from './frames.js'\n\nexport type AnyFrame = ClientFrame | ServerFrame\n\nconst CLIENT_FRAME_TYPES: ReadonlySet<ClientFrame['type']> = new Set([\n 'auth', 'open', 'send', 'sync', 'history', 'read', 'typing', 'react', 'edit', 'delete', 'invoke', 'pubkey', 'ping',\n 'uploadPrekeys', 'fetchPrekey', 'assign', 'tag', 'note', 'agent_status', 'subscribe_inbox', 'unsubscribe_inbox',\n])\n\n/** True if a decoded frame is one a client is allowed to send. The server uses\n * this to reject server-only frame types before dispatch, so a malicious or\n * buggy client can't reach an unexpected handler path. */\nexport function isClientFrame(frame: AnyFrame): frame is ClientFrame {\n return CLIENT_FRAME_TYPES.has(frame.type as ClientFrame['type'])\n}\n\n/** Encode a frame to a binary msgpack payload for the wire. */\nexport function encodeFrame(frame: AnyFrame): Uint8Array {\n return mpEncode(frame)\n}\n\n/** Decode a binary payload into a frame. Returns null on any malformed input or\n * anything lacking a string `type`, so a bad frame can never crash the handler\n * — the boundary validates `type` before trusting the rest. */\nexport function decodeFrame(bytes: Uint8Array): AnyFrame | null {\n let value: unknown\n try {\n value = mpDecode(bytes)\n } catch {\n return null\n }\n if (typeof value !== 'object' || value === null) return null\n if (typeof (value as { type?: unknown }).type !== 'string') return null\n return value as AnyFrame\n}\n","/**\n * chatlist.ts — standalone chat list widget.\n *\n * Completely separate from mount() / the chat widget.\n * Shows all conversations for a given userId / guest on a profile.\n * Tapping a row fires onSelect(entry) — the caller decides what to do\n * (navigate to a new page, open a ChatWidget inline, etc.)\n *\n * Usage (vanilla):\n * import { mountChatList } from '@paramms/chat-widget/chatlist'\n * const handle = mountChatList({\n * el: document.getElementById('chat-list'),\n * url: 'https://api.relay.paramms.com', // ONE url, any scheme\n * profileId: 'p_usedcars',\n * userId: currentUser.id, // optional — uses localStorage UID if omitted\n * onSelect: (entry) => {\n * window.location.href = `/listings/${entry.subjectId}#chat`\n * },\n * })\n * handle.refresh() // manually re-fetch the list\n * handle.close() // unmount and clean up\n */\n\nimport { resolveRelayUrls } from './history.js'\nimport { CSS } from './chatlist.styles.js'\nimport { persistentUid } from './uid.js'\nimport { encodeFrame, decodeFrame } from './protocol/codec.js'\n\nexport interface ChatListEntry {\n id: string\n /** Chatroom this conversation belongs to. With `scope: 'tenant'` this can\n * differ from the profileId the list was mounted with — open the chat\n * against THIS profileId. */\n profileId?: string\n /** 'support' (default) or 'direct' (user↔user DM). */\n kind?: string\n /** For direct conversations: the other participant's user id. */\n peerId?: string\n subjectId?: string\n subjectTitle?: string\n /** One-line detail — e.g. \"45,000 km · Auto\" */\n subjectMeta?: string\n /** URL of the listing/item page — stored automatically when the widget first opens */\n subjectUrl?: string\n state: string\n updatedAt: number\n lastSeq?: number\n lastMessage?: string\n}\n\nexport interface ChatListOptions {\n /** Mount target element */\n el: HTMLElement\n /** Relay URL — ONE url, any scheme (https recommended). The WebSocket URL\n * and REST base are derived automatically. */\n url: string\n /** HTTP(S) base for REST — only when REST is on a different origin.\n * @deprecated pass a single `url`; kept for back-compat. */\n apiUrl?: string\n /** Profile ID to scope conversations to */\n profileId?: string\n /** Tenant-level identification — list EVERY conversation this user has\n * with the business, across ALL of its chatrooms, without naming one\n * (e.g. a platform running a marketplace chatroom AND a general-support\n * chatroom). Provide `profileId` OR `tenantId` (profileId wins if both;\n * it also fixes where \"new conversation\" opens). With only `tenantId`,\n * the compose target is the server-reported defaultProfileId (the\n * tenant's oldest chatroom). */\n tenantId?: string\n /** A signed identity token (ES256 JWT) — the production identity tier for\n * chatrooms with signed identity enabled. Wins over `userId`. */\n token?: string\n /** Your logged-in user's stable ID. Omit for anonymous (uses localStorage UID) */\n userId?: string\n /** Which conversations to list (default 'profile'):\n * 'profile' — only this chatroom's threads.\n * 'tenant' — every conversation this user has with the chatroom's owning\n * business, across ALL of its chatrooms (a real chat-app inbox). Rows\n * carry `profileId` so each opens against the right chatroom. */\n scope?: 'profile' | 'tenant'\n /** Called when the user taps a conversation row */\n onSelect: (entry: ChatListEntry) => void\n /** When provided, the list shows a ✎ compose button in the header (and a\n * \"Start a conversation\" button in the empty state) that calls this —\n * wire it to open a fresh/general thread. Without it a user with no\n * conversations yet has nothing to tap. */\n onNewChat?: () => void\n /** Set when the CALLER draws its own close (✕) control overlaying the list's\n * top-right corner — reserves header space so it doesn't sit on top of the\n * ✎ compose button. */\n reserveCloseSpace?: boolean\n /** Brand colour hex — default '#6c5ce7' */\n accent?: string\n theme?: 'auto' | 'light' | 'dark'\n webfont?: boolean\n /** i18n overrides */\n i18n?: {\n title?: string // default 'Messages'\n search?: string // default '🔍 Search'\n empty?: string // default 'No conversations yet.'\n unread?: string // default 'Unread'\n all?: string // default 'All conversations'\n error?: string // default 'Could not load conversations.'\n retry?: string // default 'Retry'\n close?: string // default 'Close' (aria-label for the ✕ control)\n newChat?: string // default 'New conversation' / 'Start a conversation'\n }\n}\n\nexport interface ChatListHandle {\n /** Re-fetch and re-render the list */\n refresh(): void\n /** Unmount and clean up */\n close(): void\n /** Where \"new conversation\" should open: the configured profileId, else the\n * server-reported tenant default (oldest chatroom). Undefined until the\n * first successful fetch when only tenantId was configured. */\n defaultProfileId(): string | undefined\n}\n\n/** Map a conversation state to a status chip (label + style class). Returns null\n * for states with no meaningful badge. */\nfunction statusChip(state: string): { label: string; cls: string } | null {\n switch (state) {\n case 'open': return { label: 'Open', cls: 'open' }\n case 'awaiting_staff':return { label: 'Waiting on you', cls: 'waiting' }\n case 'resolved': return { label: 'Resolved', cls: 'done' }\n case 'closed': return { label: 'Closed', cls: 'done' }\n default: return null\n }\n}\n\nfunction timeAgo(ts: number): string {\n const s = Math.floor((Date.now() - ts) / 1000)\n if (s < 60) return 'just now'\n if (s < 3600) return `${Math.floor(s / 60)}m`\n if (s < 86400) return `${Math.floor(s / 3600)}h`\n const days = Math.floor(s / 86400)\n if (days <= 7) return `${days}d`\n // Beyond a week, a date scans better than \"43d\" (what Channel.io/Intercom do).\n try { return new Date(ts).toLocaleDateString(undefined, { month: 'short', day: 'numeric' }) }\n catch { return `${days}d` }\n}\n\n// CSS lives in chatlist.styles.ts (single source of truth for .ocl styling).\n\nfunction el(tag: string, cls?: string, text?: string): HTMLElement {\n const e = document.createElement(tag)\n if (cls) e.className = cls\n if (text !== undefined) e.textContent = text\n return e\n}\n\n// CSS lives in chatlist.styles.ts (single source of truth for .ocl styling).\n\n/** Mount a standalone chat list widget. */\nexport function mountChatList(opts: ChatListOptions): ChatListHandle {\n const token = opts.token ?? opts.userId ?? persistentUid()\n const { httpBase, wsUrl } = resolveRelayUrls(opts.url, opts.apiUrl)\n const i18n = opts.i18n ?? {}\n const accent = opts.accent ?? '#6c5ce7'\n\n // Inject the shared stylesheet ONCE, and keep it accent-FREE. The accent was\n // previously baked into this shared <style> (CSS.replace(/#f5713c/g, accent)),\n // which meant the FIRST list mounted on a page won the accent for EVERY list\n // after it (the style tag already existed, so a second list's colour was\n // ignored) — real interference when a project runs more than one widget. The\n // accent now lives in a per-instance CSS variable set on the root element\n // below, so each list keeps its own colour and the shared sheet stays static\n // (also friendlier to HTTP caching).\n if (!document.getElementById('ocl-styles')) {\n const s = document.createElement('style'); s.id = 'ocl-styles'\n s.textContent = CSS\n document.head.append(s)\n }\n // Brand webfonts (shared id with the chatroom, injected once). Opt out with webfont:false.\n if (opts.webfont !== false && typeof document !== 'undefined' && !document.getElementById('ocw-webfont')) {\n const l = document.createElement('link')\n l.id = 'ocw-webfont'; l.rel = 'stylesheet'\n l.href = 'https://fonts.googleapis.com/css2?family=Baloo+2:wght@500;600;700&family=Nunito:wght@400;500;600;700&display=swap'\n document.head.append(l)\n }\n\n // Build DOM\n const root = el('div', 'ocl')\n root.style.setProperty('--ocl-accent', accent) // per-instance accent\n // Colour scheme is opt-in, never OS-auto-detected by default (see renderer.ts):\n // unset → 'light'; 'auto' follows the OS; 'dark'/'light' force it.\n root.dataset.theme = opts.theme ?? 'light'\n if (opts.reserveCloseSpace) root.classList.add('ocl-has-close')\n const head = el('div', 'ocl-head')\n // Header shows the list title as text (the redesign's \"Your conversations\"\n // heading), host-overridable via i18n.title.\n const titleText = i18n.title ?? 'Your conversations'\n const titleEl = el('span', 'ocl-title', titleText)\n titleEl.setAttribute('aria-label', titleText)\n head.append(titleEl)\n if (opts.onNewChat) {\n const compose = el('button', 'ocl-compose', '✎') as HTMLButtonElement\n compose.title = i18n.newChat ?? 'New conversation'\n compose.addEventListener('click', () => opts.onNewChat!())\n head.append(compose)\n }\n\n const searchWrap = el('div', 'ocl-search-wrap')\n const searchIn = el('input', 'ocl-search') as HTMLInputElement\n searchIn.placeholder = i18n.search ?? '🔍 Search'; searchIn.type = 'search'\n searchWrap.append(searchIn)\n\n const body = el('div', 'ocl-body')\n body.append(el('div', 'ocl-spinner', 'Loading…'))\n root.append(head, searchWrap, body)\n opts.el.replaceChildren(root)\n\n // Container-driven compact sizing (see the CSS note). Guarded for\n // jsdom/old runtimes without ResizeObserver — they keep desktop sizing.\n const applyCompact = (w: number): void => { root.classList.toggle('ocl-compact', w > 0 && w < 400) }\n applyCompact(root.clientWidth)\n let compactObserver: ResizeObserver | null = null\n if (typeof ResizeObserver !== 'undefined') {\n compactObserver = new ResizeObserver((entries) => applyCompact(entries[0]?.contentRect.width ?? root.clientWidth))\n compactObserver.observe(root)\n }\n\n // Track seen seqs for unread counts (persisted in localStorage)\n // Key unread tracking by the STABLE id (userId beats token here: a signed\n // JWT changes every mint, which would reset unread counts on each load).\n if (!opts.profileId && !opts.tenantId) throw new Error('[relay chatlist] provide profileId or tenantId')\n let serverDefaultProfileId: string | undefined\n const seenKey = `ocl_seen_${opts.profileId ?? `t_${opts.tenantId}`}_${(opts.userId ?? token).slice(-8)}`\n let seenSeq: Record<string, number> = {}\n try { seenSeq = JSON.parse(localStorage.getItem(seenKey) ?? '{}') } catch {}\n\n const saveSeenSeq = () => {\n try { localStorage.setItem(seenKey, JSON.stringify(seenSeq)) } catch {}\n }\n\n let allEntries: ChatListEntry[] = []\n let destroyed = false\n\n // Fetch conversations from server\n const fetchEntries = async (): Promise<ChatListEntry[]> => {\n const who = opts.profileId\n ? `profileId=${encodeURIComponent(opts.profileId)}${opts.scope === 'tenant' ? '&scope=tenant' : ''}`\n : `tenantId=${encodeURIComponent(opts.tenantId!)}` // tenant-level is inherently tenant-scoped\n const url = `${httpBase}/conversations/mine?${who}`\n const headers = { authorization: `Bearer ${token}` }\n // A GET is safe to repeat. A single transient network reject — the socket\n // still warming up right after a reload, a relay that blipped — used to\n // dead-end straight to \"Could not load conversations.\" Retry once so a blip\n // self-heals; an HTTP error (4xx/5xx) is NOT a network failure and returns\n // an empty list rather than retrying or erroring.\n let res: Response\n try {\n res = await fetch(url, { headers })\n } catch {\n res = await fetch(url, { headers }) // one immediate retry\n }\n if (!res.ok) return []\n const data = await res.json() as { conversations?: ChatListEntry[]; defaultProfileId?: string }\n if (data.defaultProfileId) serverDefaultProfileId = data.defaultProfileId\n return (data.conversations ?? []).sort((a, b) => b.updatedAt - a.updatedAt)\n }\n\n // Render rows from entries, optionally filtered by search query\n const renderRows = (entries: ChatListEntry[], query: string) => {\n if (destroyed) return\n const filtered = query\n ? entries.filter(e =>\n rowName(e).toLowerCase().includes(query) ||\n (e.lastMessage ?? '').toLowerCase().includes(query)\n )\n : entries\n\n body.replaceChildren()\n\n if (!filtered.length) {\n const empty = el('div', 'ocl-empty', query ? 'No results.' : (i18n.empty ?? 'No conversations yet.'))\n if (!query && opts.onNewChat) {\n empty.append(el('br'))\n const start = el('button', 'ocl-start', i18n.newChat ?? 'Start a conversation') as HTMLButtonElement\n start.addEventListener('click', () => opts.onNewChat!())\n empty.append(start)\n }\n body.append(empty)\n return\n }\n\n const isUnread = (e: ChatListEntry) =>\n (e.lastSeq ?? 0) > (seenSeq[e.id] ?? 0)\n\n const unread = filtered.filter(isUnread)\n const read = filtered.filter(e => !isUnread(e))\n\n if (unread.length) {\n body.append(el('div', 'ocl-section', `${i18n.unread ?? 'Unread'} (${unread.length})`))\n for (const e of unread) body.append(buildRow(e, isUnread(e)))\n }\n if (read.length) {\n body.append(el('div', 'ocl-section', unread.length ? (i18n.all ?? 'All conversations') : ''))\n for (const e of read) body.append(buildRow(e, false))\n }\n }\n\n const rowName = (entry: ChatListEntry): string =>\n entry.subjectTitle ?? (entry.kind === 'direct' ? (entry.peerId ?? 'Direct message') : 'General enquiry')\n\n const buildRow = (entry: ChatListEntry, unread: boolean): HTMLElement => {\n const name = rowName(entry)\n // Prefer the first LETTER (any script), not a leading digit/symbol — a\n // listing titled \"2018 Kia K7\" should show \"K\", not \"2\", and Korean/other\n // scripts pick their first character too.\n const initial = (name.match(/\\p{L}/u)?.[0] ?? name.trim()[0] ?? '?').toUpperCase()\n const lastSeq = entry.lastSeq ?? 0\n const unreadCount = unread ? Math.max(1, lastSeq - (seenSeq[entry.id] ?? 0)) : 0\n\n const row = el('button', `ocl-row${unread ? ' unread' : ''}`) as HTMLButtonElement\n\n // Avatar\n const av = el('div', 'ocl-av', initial)\n row.append(av)\n\n // Info\n const info = el('div', 'ocl-info')\n info.append(el('div', 'ocl-name', name))\n const stateMap: Record<string, string> = {\n open: 'Open', awaiting_staff: 'Waiting for reply…',\n resolved: 'Resolved ✓', closed: 'Closed',\n }\n info.append(el('div', 'ocl-preview', entry.lastMessage ?? stateMap[entry.state] ?? entry.state))\n row.append(info)\n\n // Right: timestamp, status chip, unread badge\n const right = el('div', 'ocl-right')\n right.append(el('div', 'ocl-time', timeAgo(entry.updatedAt)))\n const chip = statusChip(entry.state)\n if (chip) right.append(el('div', `ocl-status ${chip.cls}`, chip.label))\n if (unreadCount > 0) {\n right.append(el('div', 'ocl-badge', String(unreadCount > 99 ? '99+' : unreadCount)))\n }\n row.append(right)\n\n row.addEventListener('click', () => {\n // Mark as read\n if (lastSeq > 0) { seenSeq[entry.id] = lastSeq; saveSeenSeq() }\n row.classList.remove('unread')\n right.querySelector('.ocl-badge')?.remove()\n opts.onSelect(entry)\n })\n\n return row\n }\n\n const refresh = () => {\n if (destroyed) return\n fetchEntries().then(entries => {\n if (destroyed) return\n allEntries = entries\n renderRows(entries, searchIn.value.trim().toLowerCase())\n }).catch((e) => {\n if (destroyed) return\n console.error(`[chat-widget] failed to load conversations from ${httpBase}/conversations/mine — check the apiUrl/CORS config.`, e)\n const errBox = el('div', 'ocl-empty', i18n.error ?? 'Could not load conversations.')\n errBox.append(el('br'))\n const retry = el('button', 'ocl-retry', i18n.retry ?? 'Retry') as HTMLButtonElement\n retry.addEventListener('click', () => {\n body.replaceChildren(el('div', 'ocl-spinner', 'Loading…'))\n refresh()\n })\n errBox.append(retry)\n body.replaceChildren(errBox)\n })\n }\n\n searchIn.addEventListener('input', () => renderRows(allEntries, searchIn.value.trim().toLowerCase()))\n\n // Initial fetch\n refresh()\n\n // ── Live inbox: subscribe over WS so the list updates the instant any of the\n // guest's conversations changes, instead of only on the periodic poll. The\n // server streams `inbox_event` to the guest's OWN inbox (keyed by guestId).\n // We coalesce bursts and re-fetch (the fetch already sorts/dedupes); the poll\n // stays as a backstop for a dropped socket. ────────────────────────────────\n let sock: WebSocket | null = null\n let reconnectTimer: ReturnType<typeof setTimeout> | undefined\n let refreshTimer: ReturnType<typeof setTimeout> | undefined\n let attempt = 0\n let connectedBefore = false\n const debouncedRefresh = () => {\n if (refreshTimer) return\n refreshTimer = setTimeout(() => { refreshTimer = undefined; refresh() }, 300)\n }\n const connectInbox = () => {\n if (destroyed) return\n try { sock = new WebSocket(wsUrl) } catch { scheduleReconnect(); return }\n sock.binaryType = 'arraybuffer'\n sock.onopen = () => {\n attempt = 0\n sock!.send(encodeFrame({ type: 'auth', token }))\n sock!.send(encodeFrame({ type: 'subscribe_inbox' }))\n // On a RECONNECT (not the first connect — the initial mount already\n // fetched), catch up on anything that changed while the socket was down.\n if (connectedBefore) debouncedRefresh()\n connectedBefore = true\n }\n sock.onmessage = (ev) => {\n const frame = decodeFrame(new Uint8Array(ev.data as ArrayBuffer))\n // Any inbox change for this guest → refresh the list. `new` (a freshly\n // created thread) and `update` (new message / state) both apply.\n if (frame && frame.type === 'inbox_event') debouncedRefresh()\n }\n sock.onclose = () => { sock = null; scheduleReconnect() }\n sock.onerror = () => { try { sock?.close() } catch { /* noop */ } }\n }\n const scheduleReconnect = () => {\n if (destroyed || reconnectTimer) return\n const delay = Math.min(15_000, 500 * 2 ** attempt++) + Math.random() * 250\n reconnectTimer = setTimeout(() => { reconnectTimer = undefined; connectInbox() }, delay)\n }\n connectInbox()\n\n return {\n refresh,\n close() {\n destroyed = true\n if (reconnectTimer) clearTimeout(reconnectTimer)\n if (refreshTimer) clearTimeout(refreshTimer)\n compactObserver?.disconnect()\n compactObserver = null\n try { sock?.close() } catch { /* noop */ }\n sock = null\n opts.el.replaceChildren()\n },\n defaultProfileId() { return opts.profileId ?? serverDefaultProfileId },\n }\n}\n"],"names":["resolveRelayUrls","input","apiBaseOverride","_a","trimmed","scheme","secure","authorityAndPath","httpBase","httpBaseFromWsUrl","wsUrl","historyUrl","conversationId","beforeSeq","limit","qs","fetchPage","token","lastError","sawResponse","url","res","data","e","restoreHistory","store","renderer","apiBase","page","loading","loadOlder","oldest","page2","scrollEl","armed","onScroll","LIGHT","DARK","FB","vars","prefix","t","k","v","lightTokens","darkTokens","CSS","KEY","readCookie","name","m","writeCookie","value","newId","persistentUid","existing","id","utf8Count","str","strLength","byteLength","pos","extra","utf8EncodeJs","output","outputOffset","offset","sharedTextEncoder","TEXT_ENCODER_THRESHOLD","utf8EncodeTE","utf8Encode","CHUNK_SIZE","utf8DecodeJs","bytes","inputOffset","end","units","result","byte1","byte2","byte3","byte4","unit","sharedTextDecoder","TEXT_DECODER_THRESHOLD","utf8DecodeTD","stringBytes","utf8Decode","ExtData","type","__publicField","DecodeError","message","proto","UINT32_MAX","setUint64","view","high","low","setInt64","getInt64","getUint64","EXT_TIMESTAMP","TIMESTAMP32_MAX_SEC","TIMESTAMP64_MAX_SEC","encodeTimeSpecToTimestamp","sec","nsec","rv","secHigh","secLow","encodeDateToTimeSpec","date","msec","nsecInSec","encodeTimestampExtension","object","timeSpec","decodeTimestampToTimeSpec","nsec30AndSecHigh2","secLow32","decodeTimestampExtension","timestampExtension","_ExtensionCodec","encode","decode","index","context","encodeExt","decodeExt","ExtensionCodec","isArrayBufferLike","buffer","ensureUint8Array","DEFAULT_MAX_DEPTH","DEFAULT_INITIAL_BUFFER_SIZE","Encoder","options","depth","sizeToWrite","requiredSize","newSize","newBuffer","newBytes","newView","ext","size","item","keys","count","key","values","prettyByte","byte","DEFAULT_MAX_KEY_LENGTH","DEFAULT_MAX_LENGTH_PER_KEY","CachedKeyDecoder","maxKeyLength","maxLengthPerKey","records","FIND_CHUNK","record","recordBytes","j","cachedValue","slicedCopyOfBytes","STATE_ARRAY","STATE_MAP_KEY","STATE_MAP_VALUE","mapKeyConverter","StackPool","state","partialState","HEAD_BYTE_REQUIRED","EMPTY_VIEW","EMPTY_BYTES","MORE_DATA","sharedCachedKeyDecoder","Decoder","remainingData","newData","posToShow","stream","decoded","headByte","totalPos","isArray","isArrayHeaderRequired","arrayItemsLeft","DECODE","stack","headerOffset","headOffset","extType","CLIENT_FRAME_TYPES","isClientFrame","frame","encodeFrame","mpEncode","decodeFrame","mpDecode","statusChip","timeAgo","ts","s","days","el","tag","cls","text","mountChatList","opts","i18n","accent","l","root","head","titleText","titleEl","compose","searchWrap","searchIn","body","applyCompact","w","compactObserver","entries","serverDefaultProfileId","seenKey","seenSeq","saveSeenSeq","allEntries","destroyed","fetchEntries","who","headers","a","b","renderRows","query","filtered","rowName","empty","start","isUnread","unread","read","buildRow","entry","initial","lastSeq","unreadCount","row","av","info","stateMap","right","chip","refresh","errBox","retry","sock","reconnectTimer","refreshTimer","attempt","connectedBefore","debouncedRefresh","connectInbox","scheduleReconnect","ev","delay"],"mappings":"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","x_google_ignoreList":[4,5,6,7,8,9,10,11,12,13,14,15,16]}
package/dist/core.js CHANGED
@@ -2,11 +2,10 @@ var c = Object.defineProperty;
2
2
  var d = (t, e, s) => e in t ? c(t, e, { enumerable: !0, configurable: !0, writable: !0, value: s }) : t[e] = s;
3
3
  var n = (t, e, s) => d(t, typeof e != "symbol" ? e + "" : e, s);
4
4
  import { a as o, C as u, b as h } from "./outbox.js";
5
- import { A as C, P as A, c as k, d as E, e as U, f as j, g as x, h as R, i as w } from "./outbox.js";
5
+ import { A as C, P as A, c as k, d as E, e as U, f as j, g as R, h as w, i as x } from "./outbox.js";
6
6
  import { E2ESession as L } from "./e2e.js";
7
- import { p as l, r as m } from "./codec.js";
8
- import { d as O, e as q, h as H, i as P, a as X } from "./codec.js";
9
- import { mountChatList as D } from "./chatlist.js";
7
+ import { p as l, r as m } from "./chatlist2.js";
8
+ import { d as O, e as q, h as H, i as P, m as X, a as Y } from "./chatlist2.js";
10
9
  const I = /* @__PURE__ */ new Set([
11
10
  "resolved",
12
11
  "closed",
@@ -14,7 +13,7 @@ const I = /* @__PURE__ */ new Set([
14
13
  "issued",
15
14
  "checked_out"
16
15
  ]);
17
- function _(t) {
16
+ function p(t) {
18
17
  return I.has(t);
19
18
  }
20
19
  function T(t) {
@@ -129,19 +128,19 @@ export {
129
128
  E as asConnectionId,
130
129
  U as asConversationId,
131
130
  j as asMessageId,
132
- x as asProfileId,
133
- R as asSubjectId,
134
- w as asTenantId,
131
+ R as asProfileId,
132
+ w as asSubjectId,
133
+ x as asTenantId,
135
134
  o as asUserId,
136
135
  O as decodeFrame,
137
136
  q as encodeFrame,
138
137
  H as httpBaseFromWsUrl,
139
138
  P as isClientFrame,
140
- _ as isTerminalState,
141
- D as mountChatList,
139
+ p as isTerminalState,
140
+ X as mountChatList,
142
141
  l as persistentUid,
143
142
  m as resolveRelayUrls,
144
- X as restoreHistory,
143
+ Y as restoreHistory,
145
144
  T as toManifestAction
146
145
  };
147
146
  //# sourceMappingURL=core.js.map
package/dist/core.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"core.js","sources":["../src/protocol/entities.ts","../src/protocol/actions.ts","../src/protocol/frames.ts","../src/core.ts"],"sourcesContent":["import type {\n ConversationId, MessageId, ProfileId, SubjectId, TenantId, UserId,\n} from './ids.js'\nimport type { ActionId } from './ids.js'\n\n// ── Message content (discriminated union) ─────────────────────────────────────\n// The runtime stays generic by never hard-coding business content: a message is\n// one of a small, fixed set of shapes. `card`/`form`/`system` are how action\n// results and structured prompts render — they subsume most \"rich messaging\"\n// features without a per-feature content zoo.\n\nexport interface CardField { label: string; value: string }\n\n/** A reference to an action a card/quick-reply can invoke. */\nexport interface InlineActionRef { actionId: ActionId; label: string }\n\nexport type MessageContent =\n | { kind: 'text'; text: string; enc?: boolean; iv?: string; quickReplies?: string[]; citations?: { source: string }[] }\n | { kind: 'attachment'; url: string; mime: string; name?: string; size?: number }\n | { kind: 'card'; title?: string; body?: string; fields?: CardField[]; actions?: InlineActionRef[] }\n | { kind: 'form'; prompt: string; actionId: ActionId }\n | { kind: 'system'; event: string; data?: Record<string, string | number | boolean> }\n | { kind: 'appointment'; title: string; startIso: string; endIso: string; location?: string; description?: string; googleUrl: string; icalUrl: string; confirmed?: boolean }\n\nexport type SenderRole = 'guest' | 'agent' | 'system' | 'bot'\n\n// ── Message ───────────────────────────────────────────────────────────────────\n// Ordering is by `seq` (server-assigned, monotonic per conversation), never by\n// `ts`. `ts` is wall-clock for display only. This kills the reorder/duplicate/\n// lost-on-reconnect class of bugs that millisecond-timestamp ordering caused.\n\nexport interface Message {\n id: MessageId\n conversationId: ConversationId\n seq: number\n senderId: UserId\n senderRole: SenderRole\n content: MessageContent\n ts: number\n replyToId?: MessageId\n editedAt?: number\n deletedAt?: number\n reactions?: Record<string, UserId[]>\n internal?: boolean // true = internal note, only visible to agents\n}\n\n// ── Conversation (the room; messages partition by conversationId) ─────────────\n// The room is the conversation, NOT the subject. Two guests discussing the same\n// subject get two conversations. `subjectId` is a nullable reference, never part\n// of the room identity — so \"one thread per (guest, subject)\" is enforced as\n// app logic at open-time, and many-threads-per-subject stays possible for free.\n\nexport interface Conversation {\n id: ConversationId\n tenantId: TenantId\n profileId: ProfileId // behavior profile → which actions this room has\n subjectId?: SubjectId // optional: the thing it's about\n guestId: UserId // the end-user\n /** Host-supplied display info for an identified guest (widget `user` option).\n * Display metadata only — identity is still the token/guestId. */\n guestName?: string\n guestEmail?: string\n guestAvatar?: string\n guestMeta?: Record<string, string>\n /** True once the guest's identity has been proven by a signed ES256 JWT\n * against the chatroom's guestPublicKey (secure identity mode). */\n guestVerified?: boolean\n participants: UserId[] // guest + any assigned agents (membership = authz)\n assignedAgentId?: UserId // routing/ownership\n aiActive?: boolean // staff assigned the AI to answer this room\n state: string // conversation state-machine state\n firstResponseAt?: number // first agent reply ts (SLA)\n csat?: number // satisfaction score 1–5 (set on resolution)\n lastSeq: number // highest seq assigned in this conversation\n tags?: string[] // macro/manual tags (e.g. \"refund\", \"vip\")\n /** Live sentiment of the guest's most recent message (best-effort, async). */\n sentiment?: 'positive' | 'neutral' | 'frustrated'\n /** -1 (very frustrated) .. +1 (very positive); paired with `sentiment`. */\n sentimentScore?: number\n /** Set once an SLA-breach escalation macro has fired, so it only fires once. */\n slaEscalatedAt?: number\n /** If set, the conversation is snoozed until this Unix ms timestamp.\n * Hidden from the inbox until the timestamp passes, then resurfaces. */\n snoozedUntil?: number\n /** Page URL where the widget was open when the conversation started. */\n pageUrl?: string\n /** Browser tab title at conversation start — gives agents context. */\n pageTitle?: string\n createdAt: number\n updatedAt: number\n}\n\n// ── Subject (the referenced entity — Intercom \"custom object\") ────────────────\n// Carries shared state (available → reserved → sold) and fields (price, vin…)\n// that actions read/write. Many conversations reference one subject. Never a room.\n\nexport interface Subject {\n id: SubjectId\n tenantId: TenantId\n title: string\n state: string\n fields: Record<string, string | number | boolean>\n /** URL of the page where the subject lives (e.g. the listing page URL).\n * Captured automatically by the widget and stored on first open. */\n url?: string\n createdAt: number\n updatedAt: number\n}\n\n// ── Conversation lifecycle ────────────────────────────────────────────────────\n/** States in which a conversation is no longer \"open\": it's done with, so inbox\n * / proactive sweeps skip it and load balancing frees the assigned agent. The\n * single source of truth for \"is this conversation finished?\". */\nexport const TERMINAL_STATES: ReadonlySet<string> = new Set([\n 'resolved', 'closed', 'sold', 'issued', 'checked_out',\n])\nexport function isTerminalState(state: string): boolean {\n return TERMINAL_STATES.has(state)\n}\n\nexport type Channel = 'widget' | 'email' | 'sms' | 'whatsapp' | 'instagram' | 'kakao' | 'messenger' | 'line'\n","import type { ActionId, ProfileId, TenantId } from './ids.js'\n\n// ── Actions: the product primitive ────────────────────────────────────────────\n// An action is data an admin authors in the dashboard; the runtime stays generic\n// and only knows how to execute a small, fixed set of EFFECTS. Adding \"make\n// offer\" or \"schedule meeting\" is a config row, not a code deploy.\n\nexport type ActionAudience = 'guest' | 'agent' | 'both'\nexport type ActionSurface = 'toolbar' | 'inline' | 'quick_reply'\n\nexport interface ActionInputField {\n name: string\n label: string\n type: 'text' | 'number' | 'date' | 'select'\n required?: boolean\n options?: string[] // for type: 'select'\n}\n\n// A terminal effect produces a result and ends the action. Actions are\n// single-shot: structured multi-step lives in the conversation state machine,\n// and conversational multi-step is the `bot` effect — not an action workflow.\nexport type TerminalEffect =\n | { type: 'webhook'; url: string } // signed POST to tenant system\n | { type: 'state_transition'; target: 'conversation' | 'subject'; toState: string }\n | { type: 'bot' } // route to the AI resolver\n | { type: 'builtin'; name: string } // e.g. 'handoff'\n\n// The ONLY composition allowed is \"collect a form, then run one terminal\n// effect\" — exactly one level deep. This covers input-gathering (e.g. an offer\n// amount) without becoming a workflow engine.\nexport type ActionEffect =\n | TerminalEffect\n | { type: 'form'; fields: ActionInputField[]; then: TerminalEffect }\n\nexport type ActionResult =\n | { kind: 'system_message'; template?: string } // post a system line into the chat\n | { kind: 'card' } // render the effect's response as a card\n | { kind: 'state_badge' } // reflect a state change\n | { kind: 'none' }\n\nexport interface ActionDef {\n id: ActionId\n label: string\n icon?: string\n confirm?: boolean\n audience: ActionAudience\n surface: ActionSurface\n availableInStates?: string[] // conversation/subject states; omit = always available\n effect: ActionEffect\n result: ActionResult\n}\n\n// Client-safe projection of an action: enough for the widget to render it and\n// collect inputs, but NONE of the effect internals (webhook URLs, transition\n// targets) — those stay server-side and execute on `invoke`. The client filters\n// by `availableInStates` locally against the current conversation state, so a\n// state change needs no manifest round-trip; the server re-validates on invoke.\nexport interface ManifestAction {\n id: ActionId\n label: string\n icon?: string\n confirm?: boolean\n audience: ActionAudience\n surface: ActionSurface\n availableInStates?: string[]\n input?: ActionInputField[] // present when the action collects input (form effect)\n}\n\n/** Project an internal action to its client-safe manifest form. */\nexport function toManifestAction(a: ActionDef): ManifestAction {\n const input = a.effect.type === 'form' ? a.effect.fields : undefined\n return {\n id: a.id, label: a.label, audience: a.audience, surface: a.surface,\n ...(a.icon ? { icon: a.icon } : {}),\n ...(a.confirm ? { confirm: a.confirm } : {}),\n ...(a.availableInStates ? { availableInStates: a.availableInStates } : {}),\n ...(input ? { input } : {}),\n }\n}\n\n// ── Behavior profile (what \"domain\" becomes) ──────────────────────────────────\n// A reusable, admin-composed bundle of actions + defaults + state machine. Not a\n// built-in taxonomy — the 7 old templates become starter presets of this shape.\n// `version` lets an in-flight invocation validate against a consistent snapshot.\n\n/** Operating hours slot: 0=Sun … 6=Sat, times in \"HH:MM\" 24h local. */\nexport interface OperatingHoursSlot { day: 0|1|2|3|4|5|6; open: string; close: string }\n\nexport interface BehaviorProfile {\n id: ProfileId\n tenantId: TenantId\n name: string\n actions: ActionDef[]\n defaults: {\n greeting?: string\n theme?: { accent: string }\n e2e?: boolean\n persona?: string\n /** Paid-tier flag: when true, hides the \"Powered by Relay\" footer in the widget. */\n whiteLabel?: boolean\n /** White-label: serve/embed the widget from this hostname (e.g.\n * \"chat.acmeco.com\"). Allowed automatically as a CORS origin for the\n * control-plane API so the widget works from the custom domain. */\n customDomain?: string\n }\n states: string[]\n initialState: string\n version: number\n welcomeMessage?: string // first message guests see when opening the widget\n operatingHours?: OperatingHoursSlot[] // empty/absent = always open\n offlineMessage?: string // shown outside operating hours instead of chat\n /** Base64-encoded ECDSA P-256 SPKI public key. When set, guest tokens must be\n * signed JWTs — unsigned opaque tokens are rejected. */\n guestPublicKey?: string\n createdAt: number\n updatedAt: number\n}\n","import type {\n ConnectionId, ConversationId, MessageId, ProfileId, SubjectId, UserId,\n} from './ids.js'\nimport type { Channel, Conversation, Message, MessageContent, Subject } from './entities.js'\nimport type { ManifestAction } from './actions.js'\n\n/** Dashboard-configured pre-chat qualification form, delivered in the manifest. */\nexport interface PreChatConfig {\n enabled: boolean\n showWhen?: 'always' | 'offline'\n fields?: ('name' | 'email' | 'phone')[]\n topics?: string[]\n callbackOption?: boolean\n title?: string\n}\n\n// ── Wire protocol ─────────────────────────────────────────────────────────────\n// One shared contract, imported by server + widget + dashboard. A change here is\n// a compile error in every consumer — which is the whole reason this lives in a\n// shared package instead of being hand-copied three times.\n\nexport type ErrorCode =\n | 'UNAUTHORIZED' | 'FORBIDDEN' | 'NOT_FOUND' | 'BAD_REQUEST'\n | 'RATE_LIMITED' | 'PAYLOAD_TOO_LARGE' | 'CONFLICT' | 'INTERNAL'\n\nexport type ClientFrame =\n | { type: 'auth'; token: string }\n // Open an existing conversation, or find-or-create one. Find-or-create keys on\n // (guest, subject) when subjectId is given; otherwise a fresh conversation.\n | { type: 'open'; conversationId?: ConversationId; subjectId?: SubjectId; profileId?: ProfileId; pageUrl?: string; pageTitle?: string; subjectTitle?: string; subjectMeta?: string; linkFrom?: UserId;\n /** Host-supplied display info for the guest — persisted onto the\n * conversation server-side so agents see who they're talking to.\n * Display metadata only, never used for authorization. */\n userInfo?: { name?: string; email?: string; avatar?: string; meta?: Record<string, string> } }\n | { type: 'send'; conversationId: ConversationId; clientMsgId: string; content: MessageContent; replyToId?: MessageId; via?: Channel[] }\n | { type: 'sync'; conversationId: ConversationId; sinceSeq: number } // catch-up after cursor\n | { type: 'history'; conversationId: ConversationId; beforeSeq: number; limit?: number } // load older\n | { type: 'read'; conversationId: ConversationId; seq: number } // read up to seq\n | { type: 'typing'; conversationId: ConversationId; isTyping: boolean; preview?: string }\n | { type: 'react'; conversationId: ConversationId; messageId: MessageId; emoji: string; remove?: boolean }\n | { type: 'edit'; conversationId: ConversationId; messageId: MessageId; content: MessageContent }\n | { type: 'delete'; conversationId: ConversationId; messageId: MessageId }\n | { type: 'invoke'; conversationId: ConversationId; actionId: string; clientInvokeId: string; inputs?: Record<string, unknown> }\n | { type: 'assign'; conversationId: ConversationId; agentId: UserId | null } // null = unassign\n | { type: 'tag'; conversationId: ConversationId; tag: string; remove?: boolean }\n | { type: 'note'; conversationId: ConversationId; clientMsgId: string; text: string } // internal note\n | { type: 'agent_status'; status: 'online' | 'away' | 'offline' } // agent sets their availability\n | { type: 'pubkey'; conversationId: ConversationId; key: string }\n // X3DH async E2E: a client uploads a batch of one-time prekeys so peers can\n // encrypt to them while they are offline. The server stores them opaquely and\n // vends one on demand — it never derives or uses the keys.\n | { type: 'uploadPrekeys'; identityKey: string; signedPrekey: string; signedPrekeyId: string; signature: string; oneTimePrekeys: string[] }\n | { type: 'fetchPrekey'; targetUserId: UserId }\n // Inbox stream subscription — used by the agent dashboard, which reuses this\n // ConnectionManager. Typed here so the dashboard doesn't need `as never`.\n | { type: 'subscribe_inbox' }\n | { type: 'unsubscribe_inbox' }\n | { type: 'ping' }\n\nexport type ServerFrame =\n | { type: 'authed'; userId: UserId; connectionId: ConnectionId }\n | { type: 'opened'; conversation: Conversation; subject?: Subject }\n | { type: 'manifest'; conversationId: ConversationId; actions: ManifestAction[]; version: number; name?: string; theme?: { accent: string }; e2e?: boolean; offline?: boolean; offlineMessage?: string; whiteLabel?: boolean; launcherMessage?: { title: string; subtitle?: string }; preChat?: PreChatConfig }\n | { type: 'message'; message: Message }\n | { type: 'ack'; clientMsgId: string; messageId: MessageId; seq: number; ts: number }\n | { type: 'delivered'; conversationId: ConversationId; seq: number; to: UserId }\n | { type: 'read'; conversationId: ConversationId; seq: number; by: UserId }\n | { type: 'sync'; conversationId: ConversationId; messages: Message[] }\n | { type: 'history'; conversationId: ConversationId; messages: Message[]; hasMore: boolean }\n | { type: 'typing'; conversationId: ConversationId; userId: UserId; isTyping: boolean; preview?: string }\n | { type: 'reaction'; conversationId: ConversationId; messageId: MessageId; emoji: string; by: UserId; removed: boolean }\n | { type: 'edited'; conversationId: ConversationId; messageId: MessageId; content: MessageContent; editedAt: number }\n | { type: 'deleted'; conversationId: ConversationId; messageId: MessageId; ts: number }\n | { type: 'state'; conversationId: ConversationId; state: string }\n | { type: 'assigned'; conversationId: ConversationId; agentId: UserId | null }\n | { type: 'tagged'; conversationId: ConversationId; tag: string; removed: boolean }\n | { type: 'visitor_count'; count: number } // broadcast to agents: guests currently connected\n | { type: 'agent_status_changed'; agentId: UserId; status: 'online' | 'away' | 'offline' }\n // Live sentiment of a guest's most recent message — relayed to agents only so\n // the inbox can flag frustrated conversations as they happen.\n | { type: 'sentiment'; conversationId: ConversationId; label: 'positive' | 'neutral' | 'frustrated'; score: number }\n | { type: 'subjectState'; subjectId: SubjectId; state: string }\n | { type: 'presence'; conversationId: ConversationId; userId: UserId; status: 'online' | 'offline'; lastSeen?: number }\n | { type: 'invoked'; clientInvokeId: string; ok: boolean; error?: string }\n | { type: 'error'; code: ErrorCode; message: string }\n | { type: 'peerkey'; conversationId: ConversationId; userId: UserId; key: string }\n // X3DH bundle vended to a requesting client so they can encrypt to an offline peer.\n // Contains null when the target user has no registered prekeys.\n | { type: 'prekeyBundle'; targetUserId: UserId; bundle: { identityKey: string; signedPrekey: string; signedPrekeyId: string; signature: string; oneTimePrekey?: string } | null }\n | { type: 'pong' }\n // Live inbox update for the guest's OWN conversation list (widget list socket\n // subscribes via `subscribe_inbox`). `patch` mirrors the agent inbox patch; the\n // list re-fetches on receipt, so only `kind`/`conversationId` are load-bearing.\n | { type: 'inbox_event'; kind: 'new' | 'update'; conversationId: ConversationId; patch?: Record<string, unknown> }\n\n/** Limits referenced by both ends so validation stays consistent. */\nexport const LIMITS = {\n MAX_TEXT_LEN: 8_000,\n MAX_HISTORY_LIMIT: 100,\n DEFAULT_HISTORY: 50,\n} as const\n","// ── @paramms/chat-widget/core — the headless SDK ─────────────────────────────\n// Everything you need to build your OWN chat UI (an in-app messenger, a\n// marketplace inbox, a full chat app) on the Relay protocol, with zero DOM or\n// React dependencies. This is not a new client: it is the exact transport,\n// store, outbox, and E2E machinery the bundled widget AND the agent dashboard\n// run on — re-exported behind a stable boundary, plus a small convenience\n// client for the common case.\n//\n// import { RelayClient } from '@paramms/chat-widget/core'\n//\n// // ONE url, any scheme — wss/ws/http(s) all work; ws + REST derived from it.\n// const relay = new RelayClient({ url: 'https://api.relay.paramms.com', token, profileId: 'p_x' })\n// const convo = relay.open({ subjectId: 'listing_42' }) // support thread\n// const dm = relay.open({ kind: 'direct', peerId: 'user_bob' }) // user↔user (signed identity required)\n// convo.onChange(() => render(convo.store.messages()))\n// convo.send('hello!')\n//\n// For React, see '@paramms/chat-widget/hooks'.\nexport { ConnectionManager, type SocketLike } from './connection.js'\nexport { ChatStore } from './store.js'\nexport { PersistentOutbox } from './outbox.js'\nexport { E2ESession } from './e2e.js'\nexport { restoreHistory, resolveRelayUrls, httpBaseFromWsUrl } from './history.js'\nexport { mountChatList, type ChatListEntry, type ChatListHandle, type ChatListOptions } from './chatlist.js'\nexport { persistentUid } from './uid.js'\nexport * from './protocol/index.js'\n\nimport { ConnectionManager } from './connection.js'\nimport { ChatStore } from './store.js'\nimport type { ClientFrame, ServerFrame, ConversationId, UserId } from './protocol/index.js'\nimport { asUserId } from './protocol/index.js'\nimport { persistentUid } from './uid.js'\nimport { resolveRelayUrls } from './history.js'\n\nexport interface RelayClientOptions {\n /** Relay URL — ONE url, any scheme. `https://api.relay.paramms.com` is the\n * recommended form; the WebSocket URL (`wss://…/ws`) and REST base are\n * derived from it automatically. `wss://`/`ws://`/`http://` also accepted. */\n url: string\n /** HTTP(S) base for REST calls — only when the REST API lives on a\n * DIFFERENT origin than the socket. Normally omit.\n * @deprecated pass a single `url`; kept for back-compat. */\n apiUrl?: string\n /** Identity: a signed JWT (secure), a stable userId (host-vouched), or omit\n * for an anonymous per-browser guest (browser environments only). */\n token?: string\n /** Chatroom id (from the dashboard). Required to open conversations. */\n profileId: string\n}\n\nexport interface OpenOptions {\n /** Support thread scoped to a subject (listing/order/…): one thread per\n * (user, subject). Omit for the profile's single support thread. */\n subjectId?: string\n subjectTitle?: string\n /** User↔user conversation (requires the chatroom to have signed identity\n * and `token` to be a valid signed JWT). */\n kind?: 'direct'\n peerId?: string\n /** Display info persisted for agents (support threads only). */\n user?: { name?: string; email?: string; avatar?: string; meta?: Record<string, string> }\n}\n\n/** One conversation = one connection + one store. Deliberately thin: the\n * store is the source of truth, `onChange` is the render signal, everything\n * else is the same primitives the first-party UIs use. */\nexport class RelayConversation {\n readonly store: ChatStore\n private readonly conn: ConnectionManager\n private readonly listeners = new Set<() => void>()\n private msgSeq = 0\n private _status = 'connecting'\n private _statusMessage: string | undefined\n\n constructor(opts: RelayClientOptions & OpenOptions & { me: UserId }) {\n this.store = new ChatStore(opts.me)\n const open: Extract<ClientFrame, { type: 'open' }> = {\n type: 'open',\n profileId: opts.profileId as never,\n ...(opts.subjectId ? { subjectId: opts.subjectId as never } : {}),\n ...(opts.subjectTitle ? { subjectTitle: opts.subjectTitle } : {}),\n ...(opts.kind === 'direct' ? { kind: 'direct' as const, peerId: asUserId(opts.peerId ?? '') } : {}),\n ...(opts.user ? { userInfo: opts.user } : {}),\n }\n // Accept any scheme (https/http/wss/ws) — a plain `https://api.…` URL is\n // resolved to the concrete `wss://…/ws` socket endpoint, exactly like the\n // bundled widget's mount(). Before this, RelayClient required a raw\n // WebSocket URL while the React components took `https://` — one URL now\n // works across the entire SDK.\n const { wsUrl } = resolveRelayUrls(opts.url, opts.apiUrl)\n this.conn = new ConnectionManager({\n url: wsUrl,\n token: opts.token ?? opts.me,\n open,\n getCursor: () => this.store.highestSeq(),\n onFrame: (f: ServerFrame) => {\n // The server tells us our CANONICAL id on auth (a signed JWT's sub,\n // not the raw token) — capture it so `mine` checks work under every\n // identity tier.\n if (f.type === 'authed') this._me = f.userId as UserId\n this.store.apply(f); this.emit()\n },\n onStatusChange: (s, msg) => { this._status = s; this._statusMessage = msg; this.emit() },\n })\n this.conn.connect()\n }\n\n /** Subscribe to any change (message, typing, status). Returns unsubscribe. */\n onChange(fn: () => void): () => void {\n this.listeners.add(fn)\n return () => this.listeners.delete(fn)\n }\n private emit(): void { for (const fn of this.listeners) fn() }\n\n private _me: UserId | undefined\n /** Our canonical user id as resolved by the server (JWT sub / userId / anon id). */\n get me(): UserId | undefined { return this._me }\n get conversationId(): ConversationId | undefined { return this.store.conversationId }\n get status(): string { return this._status }\n get statusMessage(): string | undefined { return this._statusMessage }\n\n send(text: string): void {\n const clientMsgId = `c_${Date.now().toString(36)}_${++this.msgSeq}`\n const cid = this.store.conversationId\n if (!cid) return\n this.store.addOptimistic(clientMsgId, { kind: 'text', text })\n this.conn.send({ type: 'send', conversationId: cid, clientMsgId, content: { kind: 'text', text } })\n this.emit()\n }\n\n typing(isTyping: boolean, preview?: string): void {\n const cid = this.store.conversationId\n if (!cid) return\n this.conn.send({ type: 'typing', conversationId: cid, isTyping, ...(preview ? { preview } : {}) })\n }\n\n markRead(): void {\n const cid = this.store.conversationId\n if (!cid) return\n this.conn.send({ type: 'read', conversationId: cid, seq: this.store.highestSeq() })\n }\n\n close(): void { this.conn.close(); this.listeners.clear() }\n}\n\nexport class RelayClient {\n constructor(private readonly opts: RelayClientOptions) {}\n\n /** The identity this client will act as: the token's subject (resolved\n * server-side), the raw userId, or a persistent anonymous browser id. */\n me(): UserId {\n return asUserId(this.opts.token ?? persistentUid())\n }\n\n open(open: OpenOptions = {}): RelayConversation {\n return new RelayConversation({ ...this.opts, ...open, me: this.me() })\n }\n}\n"],"names":["TERMINAL_STATES","isTerminalState","state","toManifestAction","a","input","LIMITS","RelayConversation","opts","__publicField","ChatStore","open","asUserId","wsUrl","resolveRelayUrls","ConnectionManager","f","s","msg","fn","text","clientMsgId","cid","isTyping","preview","RelayClient","persistentUid"],"mappings":";;;;;;;;;AAiHO,MAAMA,wBAA2C,IAAI;AAAA,EAC1D;AAAA,EAAY;AAAA,EAAU;AAAA,EAAQ;AAAA,EAAU;AAC1C,CAAC;AACM,SAASC,EAAgBC,GAAwB;AACtD,SAAOF,EAAgB,IAAIE,CAAK;AAClC;ACjDO,SAASC,EAAiBC,GAA8B;AAC7D,QAAMC,IAAQD,EAAE,OAAO,SAAS,SAASA,EAAE,OAAO,SAAS;AAC3D,SAAO;AAAA,IACL,IAAIA,EAAE;AAAA,IAAI,OAAOA,EAAE;AAAA,IAAO,UAAUA,EAAE;AAAA,IAAU,SAASA,EAAE;AAAA,IAC3D,GAAIA,EAAE,OAAO,EAAE,MAAMA,EAAE,KAAA,IAAS,CAAA;AAAA,IAChC,GAAIA,EAAE,UAAU,EAAE,SAASA,EAAE,QAAA,IAAY,CAAA;AAAA,IACzC,GAAIA,EAAE,oBAAoB,EAAE,mBAAmBA,EAAE,kBAAA,IAAsB,CAAA;AAAA,IACvE,GAAIC,IAAQ,EAAE,OAAAA,MAAU,CAAA;AAAA,EAAC;AAE7B;ACkBO,MAAMC,IAAS;AAAA,EACpB,cAAoB;AAAA,EACpB,mBAAoB;AAAA,EACpB,iBAAoB;AACtB;AClCO,MAAMC,EAAkB;AAAA,EAQ7B,YAAYC,GAAyD;AAP5D,IAAAC,EAAA;AACQ,IAAAA,EAAA;AACA,IAAAA,EAAA,uCAAgB,IAAA;AACzB,IAAAA,EAAA,gBAAS;AACT,IAAAA,EAAA,iBAAU;AACV,IAAAA,EAAA;AA0CA,IAAAA,EAAA;AAvCN,SAAK,QAAQ,IAAIC,EAAUF,EAAK,EAAE;AAClC,UAAMG,IAA+C;AAAA,MACnD,MAAM;AAAA,MACN,WAAWH,EAAK;AAAA,MAChB,GAAIA,EAAK,YAAY,EAAE,WAAWA,EAAK,UAAA,IAAuB,CAAA;AAAA,MAC9D,GAAIA,EAAK,eAAe,EAAE,cAAcA,EAAK,aAAA,IAAiB,CAAA;AAAA,MAC9D,GAAIA,EAAK,SAAS,WAAW,EAAE,MAAM,UAAmB,QAAQI,EAASJ,EAAK,UAAU,EAAE,EAAA,IAAM,CAAA;AAAA,MAChG,GAAIA,EAAK,OAAO,EAAE,UAAUA,EAAK,KAAA,IAAS,CAAA;AAAA,IAAC,GAOvC,EAAE,OAAAK,EAAA,IAAUC,EAAiBN,EAAK,KAAKA,EAAK,MAAM;AACxD,SAAK,OAAO,IAAIO,EAAkB;AAAA,MAChC,KAAKF;AAAA,MACL,OAAOL,EAAK,SAASA,EAAK;AAAA,MAC1B,MAAAG;AAAA,MACA,WAAW,MAAM,KAAK,MAAM,WAAA;AAAA,MAC5B,SAAS,CAACK,MAAmB;AAI3B,QAAIA,EAAE,SAAS,aAAU,KAAK,MAAMA,EAAE,SACtC,KAAK,MAAM,MAAMA,CAAC,GAAG,KAAK,KAAA;AAAA,MAC5B;AAAA,MACA,gBAAgB,CAACC,GAAGC,MAAQ;AAAE,aAAK,UAAUD,GAAG,KAAK,iBAAiBC,GAAK,KAAK,KAAA;AAAA,MAAO;AAAA,IAAA,CACxF,GACD,KAAK,KAAK,QAAA;AAAA,EACZ;AAAA;AAAA,EAGA,SAASC,GAA4B;AACnC,gBAAK,UAAU,IAAIA,CAAE,GACd,MAAM,KAAK,UAAU,OAAOA,CAAE;AAAA,EACvC;AAAA,EACQ,OAAa;AAAE,eAAWA,KAAM,KAAK,UAAW,CAAAA,EAAA;AAAA,EAAK;AAAA;AAAA,EAI7D,IAAI,KAAyB;AAAE,WAAO,KAAK;AAAA,EAAI;AAAA,EAC/C,IAAI,iBAA6C;AAAE,WAAO,KAAK,MAAM;AAAA,EAAe;AAAA,EACpF,IAAI,SAAiB;AAAE,WAAO,KAAK;AAAA,EAAQ;AAAA,EAC3C,IAAI,gBAAoC;AAAE,WAAO,KAAK;AAAA,EAAe;AAAA,EAErE,KAAKC,GAAoB;AACvB,UAAMC,IAAc,KAAK,KAAK,IAAA,EAAM,SAAS,EAAE,CAAC,IAAI,EAAE,KAAK,MAAM,IAC3DC,IAAM,KAAK,MAAM;AACvB,IAAKA,MACL,KAAK,MAAM,cAAcD,GAAa,EAAE,MAAM,QAAQ,MAAAD,GAAM,GAC5D,KAAK,KAAK,KAAK,EAAE,MAAM,QAAQ,gBAAgBE,GAAK,aAAAD,GAAa,SAAS,EAAE,MAAM,QAAQ,MAAAD,EAAA,GAAQ,GAClG,KAAK,KAAA;AAAA,EACP;AAAA,EAEA,OAAOG,GAAmBC,GAAwB;AAChD,UAAMF,IAAM,KAAK,MAAM;AACvB,IAAKA,KACL,KAAK,KAAK,KAAK,EAAE,MAAM,UAAU,gBAAgBA,GAAK,UAAAC,GAAU,GAAIC,IAAU,EAAE,SAAAA,EAAA,IAAY,CAAA,GAAK;AAAA,EACnG;AAAA,EAEA,WAAiB;AACf,UAAMF,IAAM,KAAK,MAAM;AACvB,IAAKA,KACL,KAAK,KAAK,KAAK,EAAE,MAAM,QAAQ,gBAAgBA,GAAK,KAAK,KAAK,MAAM,WAAA,EAAW,CAAG;AAAA,EACpF;AAAA,EAEA,QAAc;AAAE,SAAK,KAAK,MAAA,GAAS,KAAK,UAAU,MAAA;AAAA,EAAQ;AAC5D;AAEO,MAAMG,EAAY;AAAA,EACvB,YAA6BjB,GAA0B;AAA1B,SAAA,OAAAA;AAAA,EAA2B;AAAA;AAAA;AAAA,EAIxD,KAAa;AACX,WAAOI,EAAS,KAAK,KAAK,SAASc,GAAe;AAAA,EACpD;AAAA,EAEA,KAAKf,IAAoB,IAAuB;AAC9C,WAAO,IAAIJ,EAAkB,EAAE,GAAG,KAAK,MAAM,GAAGI,GAAM,IAAI,KAAK,GAAA,GAAM;AAAA,EACvE;AACF;"}
1
+ {"version":3,"file":"core.js","sources":["../src/protocol/entities.ts","../src/protocol/actions.ts","../src/protocol/frames.ts","../src/core.ts"],"sourcesContent":["import type {\n ConversationId, MessageId, ProfileId, SubjectId, TenantId, UserId,\n} from './ids.js'\nimport type { ActionId } from './ids.js'\n\n// ── Message content (discriminated union) ─────────────────────────────────────\n// The runtime stays generic by never hard-coding business content: a message is\n// one of a small, fixed set of shapes. `card`/`form`/`system` are how action\n// results and structured prompts render — they subsume most \"rich messaging\"\n// features without a per-feature content zoo.\n\nexport interface CardField { label: string; value: string }\n\n/** A reference to an action a card/quick-reply can invoke. */\nexport interface InlineActionRef { actionId: ActionId; label: string }\n\nexport type MessageContent =\n | { kind: 'text'; text: string; enc?: boolean; iv?: string; quickReplies?: string[]; citations?: { source: string }[] }\n | { kind: 'attachment'; url: string; mime: string; name?: string; size?: number }\n | { kind: 'card'; title?: string; body?: string; fields?: CardField[]; actions?: InlineActionRef[] }\n | { kind: 'form'; prompt: string; actionId: ActionId }\n | { kind: 'system'; event: string; data?: Record<string, string | number | boolean> }\n | { kind: 'appointment'; title: string; startIso: string; endIso: string; location?: string; description?: string; googleUrl: string; icalUrl: string; confirmed?: boolean }\n\nexport type SenderRole = 'guest' | 'agent' | 'system' | 'bot'\n\n// ── Message ───────────────────────────────────────────────────────────────────\n// Ordering is by `seq` (server-assigned, monotonic per conversation), never by\n// `ts`. `ts` is wall-clock for display only. This kills the reorder/duplicate/\n// lost-on-reconnect class of bugs that millisecond-timestamp ordering caused.\n\nexport interface Message {\n id: MessageId\n conversationId: ConversationId\n seq: number\n senderId: UserId\n senderRole: SenderRole\n content: MessageContent\n ts: number\n replyToId?: MessageId\n editedAt?: number\n deletedAt?: number\n reactions?: Record<string, UserId[]>\n internal?: boolean // true = internal note, only visible to agents\n}\n\n// ── Conversation (the room; messages partition by conversationId) ─────────────\n// The room is the conversation, NOT the subject. Two guests discussing the same\n// subject get two conversations. `subjectId` is a nullable reference, never part\n// of the room identity — so \"one thread per (guest, subject)\" is enforced as\n// app logic at open-time, and many-threads-per-subject stays possible for free.\n\nexport interface Conversation {\n id: ConversationId\n tenantId: TenantId\n profileId: ProfileId // behavior profile → which actions this room has\n subjectId?: SubjectId // optional: the thing it's about\n guestId: UserId // the end-user\n /** Host-supplied display info for an identified guest (widget `user` option).\n * Display metadata only — identity is still the token/guestId. */\n guestName?: string\n guestEmail?: string\n guestAvatar?: string\n guestMeta?: Record<string, string>\n /** True once the guest's identity has been proven by a signed ES256 JWT\n * against the chatroom's guestPublicKey (secure identity mode). */\n guestVerified?: boolean\n participants: UserId[] // guest + any assigned agents (membership = authz)\n assignedAgentId?: UserId // routing/ownership\n aiActive?: boolean // staff assigned the AI to answer this room\n state: string // conversation state-machine state\n firstResponseAt?: number // first agent reply ts (SLA)\n csat?: number // satisfaction score 1–5 (set on resolution)\n lastSeq: number // highest seq assigned in this conversation\n tags?: string[] // macro/manual tags (e.g. \"refund\", \"vip\")\n /** Live sentiment of the guest's most recent message (best-effort, async). */\n sentiment?: 'positive' | 'neutral' | 'frustrated'\n /** -1 (very frustrated) .. +1 (very positive); paired with `sentiment`. */\n sentimentScore?: number\n /** Set once an SLA-breach escalation macro has fired, so it only fires once. */\n slaEscalatedAt?: number\n /** If set, the conversation is snoozed until this Unix ms timestamp.\n * Hidden from the inbox until the timestamp passes, then resurfaces. */\n snoozedUntil?: number\n /** Page URL where the widget was open when the conversation started. */\n pageUrl?: string\n /** Browser tab title at conversation start — gives agents context. */\n pageTitle?: string\n createdAt: number\n updatedAt: number\n}\n\n// ── Subject (the referenced entity — Intercom \"custom object\") ────────────────\n// Carries shared state (available → reserved → sold) and fields (price, vin…)\n// that actions read/write. Many conversations reference one subject. Never a room.\n\nexport interface Subject {\n id: SubjectId\n tenantId: TenantId\n title: string\n state: string\n fields: Record<string, string | number | boolean>\n /** URL of the page where the subject lives (e.g. the listing page URL).\n * Captured automatically by the widget and stored on first open. */\n url?: string\n createdAt: number\n updatedAt: number\n}\n\n// ── Conversation lifecycle ────────────────────────────────────────────────────\n/** States in which a conversation is no longer \"open\": it's done with, so inbox\n * / proactive sweeps skip it and load balancing frees the assigned agent. The\n * single source of truth for \"is this conversation finished?\". */\nexport const TERMINAL_STATES: ReadonlySet<string> = new Set([\n 'resolved', 'closed', 'sold', 'issued', 'checked_out',\n])\nexport function isTerminalState(state: string): boolean {\n return TERMINAL_STATES.has(state)\n}\n\nexport type Channel = 'widget' | 'email' | 'sms' | 'whatsapp' | 'instagram' | 'kakao' | 'messenger' | 'line'\n","import type { ActionId, ProfileId, TenantId } from './ids.js'\n\n// ── Actions: the product primitive ────────────────────────────────────────────\n// An action is data an admin authors in the dashboard; the runtime stays generic\n// and only knows how to execute a small, fixed set of EFFECTS. Adding \"make\n// offer\" or \"schedule meeting\" is a config row, not a code deploy.\n\nexport type ActionAudience = 'guest' | 'agent' | 'both'\nexport type ActionSurface = 'toolbar' | 'inline' | 'quick_reply'\n\nexport interface ActionInputField {\n name: string\n label: string\n type: 'text' | 'number' | 'date' | 'select'\n required?: boolean\n options?: string[] // for type: 'select'\n}\n\n// A terminal effect produces a result and ends the action. Actions are\n// single-shot: structured multi-step lives in the conversation state machine,\n// and conversational multi-step is the `bot` effect — not an action workflow.\nexport type TerminalEffect =\n | { type: 'webhook'; url: string } // signed POST to tenant system\n | { type: 'state_transition'; target: 'conversation' | 'subject'; toState: string }\n | { type: 'bot' } // route to the AI resolver\n | { type: 'builtin'; name: string } // e.g. 'handoff'\n\n// The ONLY composition allowed is \"collect a form, then run one terminal\n// effect\" — exactly one level deep. This covers input-gathering (e.g. an offer\n// amount) without becoming a workflow engine.\nexport type ActionEffect =\n | TerminalEffect\n | { type: 'form'; fields: ActionInputField[]; then: TerminalEffect }\n\nexport type ActionResult =\n | { kind: 'system_message'; template?: string } // post a system line into the chat\n | { kind: 'card' } // render the effect's response as a card\n | { kind: 'state_badge' } // reflect a state change\n | { kind: 'none' }\n\nexport interface ActionDef {\n id: ActionId\n label: string\n icon?: string\n confirm?: boolean\n audience: ActionAudience\n surface: ActionSurface\n availableInStates?: string[] // conversation/subject states; omit = always available\n effect: ActionEffect\n result: ActionResult\n}\n\n// Client-safe projection of an action: enough for the widget to render it and\n// collect inputs, but NONE of the effect internals (webhook URLs, transition\n// targets) — those stay server-side and execute on `invoke`. The client filters\n// by `availableInStates` locally against the current conversation state, so a\n// state change needs no manifest round-trip; the server re-validates on invoke.\nexport interface ManifestAction {\n id: ActionId\n label: string\n icon?: string\n confirm?: boolean\n audience: ActionAudience\n surface: ActionSurface\n availableInStates?: string[]\n input?: ActionInputField[] // present when the action collects input (form effect)\n}\n\n/** Project an internal action to its client-safe manifest form. */\nexport function toManifestAction(a: ActionDef): ManifestAction {\n const input = a.effect.type === 'form' ? a.effect.fields : undefined\n return {\n id: a.id, label: a.label, audience: a.audience, surface: a.surface,\n ...(a.icon ? { icon: a.icon } : {}),\n ...(a.confirm ? { confirm: a.confirm } : {}),\n ...(a.availableInStates ? { availableInStates: a.availableInStates } : {}),\n ...(input ? { input } : {}),\n }\n}\n\n// ── Behavior profile (what \"domain\" becomes) ──────────────────────────────────\n// A reusable, admin-composed bundle of actions + defaults + state machine. Not a\n// built-in taxonomy — the 7 old templates become starter presets of this shape.\n// `version` lets an in-flight invocation validate against a consistent snapshot.\n\n/** Operating hours slot: 0=Sun … 6=Sat, times in \"HH:MM\" 24h local. */\nexport interface OperatingHoursSlot { day: 0|1|2|3|4|5|6; open: string; close: string }\n\nexport interface BehaviorProfile {\n id: ProfileId\n tenantId: TenantId\n name: string\n actions: ActionDef[]\n defaults: {\n greeting?: string\n theme?: { accent: string }\n e2e?: boolean\n persona?: string\n /** Paid-tier flag: when true, hides the \"Powered by Relay\" footer in the widget. */\n whiteLabel?: boolean\n /** White-label: serve/embed the widget from this hostname (e.g.\n * \"chat.acmeco.com\"). Allowed automatically as a CORS origin for the\n * control-plane API so the widget works from the custom domain. */\n customDomain?: string\n }\n states: string[]\n initialState: string\n version: number\n welcomeMessage?: string // first message guests see when opening the widget\n operatingHours?: OperatingHoursSlot[] // empty/absent = always open\n offlineMessage?: string // shown outside operating hours instead of chat\n /** Base64-encoded ECDSA P-256 SPKI public key. When set, guest tokens must be\n * signed JWTs — unsigned opaque tokens are rejected. */\n guestPublicKey?: string\n createdAt: number\n updatedAt: number\n}\n","import type {\n ConnectionId, ConversationId, MessageId, ProfileId, SubjectId, UserId,\n} from './ids.js'\nimport type { Channel, Conversation, Message, MessageContent, Subject } from './entities.js'\nimport type { ManifestAction } from './actions.js'\n\n/** Dashboard-configured pre-chat qualification form, delivered in the manifest. */\nexport interface PreChatConfig {\n enabled: boolean\n showWhen?: 'always' | 'offline'\n fields?: ('name' | 'email' | 'phone')[]\n topics?: string[]\n callbackOption?: boolean\n title?: string\n}\n\n// ── Wire protocol ─────────────────────────────────────────────────────────────\n// One shared contract, imported by server + widget + dashboard. A change here is\n// a compile error in every consumer — which is the whole reason this lives in a\n// shared package instead of being hand-copied three times.\n\nexport type ErrorCode =\n | 'UNAUTHORIZED' | 'FORBIDDEN' | 'NOT_FOUND' | 'BAD_REQUEST'\n | 'RATE_LIMITED' | 'PAYLOAD_TOO_LARGE' | 'CONFLICT' | 'INTERNAL'\n\nexport type ClientFrame =\n | { type: 'auth'; token: string }\n // Open an existing conversation, or find-or-create one. Find-or-create keys on\n // (guest, subject) when subjectId is given; otherwise a fresh conversation.\n | { type: 'open'; conversationId?: ConversationId; subjectId?: SubjectId; profileId?: ProfileId; pageUrl?: string; pageTitle?: string; subjectTitle?: string; subjectMeta?: string; linkFrom?: UserId;\n /** Host-supplied display info for the guest — persisted onto the\n * conversation server-side so agents see who they're talking to.\n * Display metadata only, never used for authorization. */\n userInfo?: { name?: string; email?: string; avatar?: string; meta?: Record<string, string> } }\n | { type: 'send'; conversationId: ConversationId; clientMsgId: string; content: MessageContent; replyToId?: MessageId; via?: Channel[] }\n | { type: 'sync'; conversationId: ConversationId; sinceSeq: number } // catch-up after cursor\n | { type: 'history'; conversationId: ConversationId; beforeSeq: number; limit?: number } // load older\n | { type: 'read'; conversationId: ConversationId; seq: number } // read up to seq\n | { type: 'typing'; conversationId: ConversationId; isTyping: boolean; preview?: string }\n | { type: 'react'; conversationId: ConversationId; messageId: MessageId; emoji: string; remove?: boolean }\n | { type: 'edit'; conversationId: ConversationId; messageId: MessageId; content: MessageContent }\n | { type: 'delete'; conversationId: ConversationId; messageId: MessageId }\n | { type: 'invoke'; conversationId: ConversationId; actionId: string; clientInvokeId: string; inputs?: Record<string, unknown> }\n | { type: 'assign'; conversationId: ConversationId; agentId: UserId | null } // null = unassign\n | { type: 'tag'; conversationId: ConversationId; tag: string; remove?: boolean }\n | { type: 'note'; conversationId: ConversationId; clientMsgId: string; text: string } // internal note\n | { type: 'agent_status'; status: 'online' | 'away' | 'offline' } // agent sets their availability\n | { type: 'pubkey'; conversationId: ConversationId; key: string }\n // X3DH async E2E: a client uploads a batch of one-time prekeys so peers can\n // encrypt to them while they are offline. The server stores them opaquely and\n // vends one on demand — it never derives or uses the keys.\n | { type: 'uploadPrekeys'; identityKey: string; signedPrekey: string; signedPrekeyId: string; signature: string; oneTimePrekeys: string[] }\n | { type: 'fetchPrekey'; targetUserId: UserId }\n // Inbox stream subscription — used by the agent dashboard, which reuses this\n // ConnectionManager. Typed here so the dashboard doesn't need `as never`.\n | { type: 'subscribe_inbox' }\n | { type: 'unsubscribe_inbox' }\n | { type: 'ping' }\n\nexport type ServerFrame =\n | { type: 'authed'; userId: UserId; connectionId: ConnectionId }\n | { type: 'opened'; conversation: Conversation; subject?: Subject }\n | { type: 'manifest'; conversationId: ConversationId; actions: ManifestAction[]; version: number; name?: string; theme?: { accent: string }; e2e?: boolean; offline?: boolean; offlineMessage?: string; whiteLabel?: boolean; launcherMessage?: { title: string; subtitle?: string }; preChat?: PreChatConfig }\n | { type: 'message'; message: Message }\n | { type: 'ack'; clientMsgId: string; messageId: MessageId; seq: number; ts: number }\n | { type: 'delivered'; conversationId: ConversationId; seq: number; to: UserId }\n | { type: 'read'; conversationId: ConversationId; seq: number; by: UserId }\n | { type: 'sync'; conversationId: ConversationId; messages: Message[] }\n | { type: 'history'; conversationId: ConversationId; messages: Message[]; hasMore: boolean }\n | { type: 'typing'; conversationId: ConversationId; userId: UserId; isTyping: boolean; preview?: string }\n | { type: 'reaction'; conversationId: ConversationId; messageId: MessageId; emoji: string; by: UserId; removed: boolean }\n | { type: 'edited'; conversationId: ConversationId; messageId: MessageId; content: MessageContent; editedAt: number }\n | { type: 'deleted'; conversationId: ConversationId; messageId: MessageId; ts: number }\n | { type: 'state'; conversationId: ConversationId; state: string }\n | { type: 'assigned'; conversationId: ConversationId; agentId: UserId | null }\n | { type: 'tagged'; conversationId: ConversationId; tag: string; removed: boolean }\n | { type: 'visitor_count'; count: number } // broadcast to agents: guests currently connected\n | { type: 'agent_status_changed'; agentId: UserId; status: 'online' | 'away' | 'offline' }\n // Live sentiment of a guest's most recent message — relayed to agents only so\n // the inbox can flag frustrated conversations as they happen.\n | { type: 'sentiment'; conversationId: ConversationId; label: 'positive' | 'neutral' | 'frustrated'; score: number }\n | { type: 'subjectState'; subjectId: SubjectId; state: string }\n | { type: 'presence'; conversationId: ConversationId; userId: UserId; status: 'online' | 'offline'; lastSeen?: number }\n | { type: 'invoked'; clientInvokeId: string; ok: boolean; error?: string }\n | { type: 'error'; code: ErrorCode; message: string }\n | { type: 'peerkey'; conversationId: ConversationId; userId: UserId; key: string }\n // X3DH bundle vended to a requesting client so they can encrypt to an offline peer.\n // Contains null when the target user has no registered prekeys.\n | { type: 'prekeyBundle'; targetUserId: UserId; bundle: { identityKey: string; signedPrekey: string; signedPrekeyId: string; signature: string; oneTimePrekey?: string } | null }\n | { type: 'pong' }\n // Live inbox update for the guest's OWN conversation list (widget list socket\n // subscribes via `subscribe_inbox`). `patch` mirrors the agent inbox patch; the\n // list re-fetches on receipt, so only `kind`/`conversationId` are load-bearing.\n | { type: 'inbox_event'; kind: 'new' | 'update'; conversationId: ConversationId; patch?: Record<string, unknown> }\n\n/** Limits referenced by both ends so validation stays consistent. */\nexport const LIMITS = {\n MAX_TEXT_LEN: 8_000,\n MAX_HISTORY_LIMIT: 100,\n DEFAULT_HISTORY: 50,\n} as const\n","// ── @paramms/chat-widget/core — the headless SDK ─────────────────────────────\n// Everything you need to build your OWN chat UI (an in-app messenger, a\n// marketplace inbox, a full chat app) on the Relay protocol, with zero DOM or\n// React dependencies. This is not a new client: it is the exact transport,\n// store, outbox, and E2E machinery the bundled widget AND the agent dashboard\n// run on — re-exported behind a stable boundary, plus a small convenience\n// client for the common case.\n//\n// import { RelayClient } from '@paramms/chat-widget/core'\n//\n// // ONE url, any scheme — wss/ws/http(s) all work; ws + REST derived from it.\n// const relay = new RelayClient({ url: 'https://api.relay.paramms.com', token, profileId: 'p_x' })\n// const convo = relay.open({ subjectId: 'listing_42' }) // support thread\n// const dm = relay.open({ kind: 'direct', peerId: 'user_bob' }) // user↔user (signed identity required)\n// convo.onChange(() => render(convo.store.messages()))\n// convo.send('hello!')\n//\n// For React, see '@paramms/chat-widget/hooks'.\nexport { ConnectionManager, type SocketLike } from './connection.js'\nexport { ChatStore } from './store.js'\nexport { PersistentOutbox } from './outbox.js'\nexport { E2ESession } from './e2e.js'\nexport { restoreHistory, resolveRelayUrls, httpBaseFromWsUrl } from './history.js'\nexport { mountChatList, type ChatListEntry, type ChatListHandle, type ChatListOptions } from './chatlist.js'\nexport { persistentUid } from './uid.js'\nexport * from './protocol/index.js'\n\nimport { ConnectionManager } from './connection.js'\nimport { ChatStore } from './store.js'\nimport type { ClientFrame, ServerFrame, ConversationId, UserId } from './protocol/index.js'\nimport { asUserId } from './protocol/index.js'\nimport { persistentUid } from './uid.js'\nimport { resolveRelayUrls } from './history.js'\n\nexport interface RelayClientOptions {\n /** Relay URL — ONE url, any scheme. `https://api.relay.paramms.com` is the\n * recommended form; the WebSocket URL (`wss://…/ws`) and REST base are\n * derived from it automatically. `wss://`/`ws://`/`http://` also accepted. */\n url: string\n /** HTTP(S) base for REST calls — only when the REST API lives on a\n * DIFFERENT origin than the socket. Normally omit.\n * @deprecated pass a single `url`; kept for back-compat. */\n apiUrl?: string\n /** Identity: a signed JWT (secure), a stable userId (host-vouched), or omit\n * for an anonymous per-browser guest (browser environments only). */\n token?: string\n /** Chatroom id (from the dashboard). Required to open conversations. */\n profileId: string\n}\n\nexport interface OpenOptions {\n /** Support thread scoped to a subject (listing/order/…): one thread per\n * (user, subject). Omit for the profile's single support thread. */\n subjectId?: string\n subjectTitle?: string\n /** User↔user conversation (requires the chatroom to have signed identity\n * and `token` to be a valid signed JWT). */\n kind?: 'direct'\n peerId?: string\n /** Display info persisted for agents (support threads only). */\n user?: { name?: string; email?: string; avatar?: string; meta?: Record<string, string> }\n}\n\n/** One conversation = one connection + one store. Deliberately thin: the\n * store is the source of truth, `onChange` is the render signal, everything\n * else is the same primitives the first-party UIs use. */\nexport class RelayConversation {\n readonly store: ChatStore\n private readonly conn: ConnectionManager\n private readonly listeners = new Set<() => void>()\n private msgSeq = 0\n private _status = 'connecting'\n private _statusMessage: string | undefined\n\n constructor(opts: RelayClientOptions & OpenOptions & { me: UserId }) {\n this.store = new ChatStore(opts.me)\n const open: Extract<ClientFrame, { type: 'open' }> = {\n type: 'open',\n profileId: opts.profileId as never,\n ...(opts.subjectId ? { subjectId: opts.subjectId as never } : {}),\n ...(opts.subjectTitle ? { subjectTitle: opts.subjectTitle } : {}),\n ...(opts.kind === 'direct' ? { kind: 'direct' as const, peerId: asUserId(opts.peerId ?? '') } : {}),\n ...(opts.user ? { userInfo: opts.user } : {}),\n }\n // Accept any scheme (https/http/wss/ws) — a plain `https://api.…` URL is\n // resolved to the concrete `wss://…/ws` socket endpoint, exactly like the\n // bundled widget's mount(). Before this, RelayClient required a raw\n // WebSocket URL while the React components took `https://` — one URL now\n // works across the entire SDK.\n const { wsUrl } = resolveRelayUrls(opts.url, opts.apiUrl)\n this.conn = new ConnectionManager({\n url: wsUrl,\n token: opts.token ?? opts.me,\n open,\n getCursor: () => this.store.highestSeq(),\n onFrame: (f: ServerFrame) => {\n // The server tells us our CANONICAL id on auth (a signed JWT's sub,\n // not the raw token) — capture it so `mine` checks work under every\n // identity tier.\n if (f.type === 'authed') this._me = f.userId as UserId\n this.store.apply(f); this.emit()\n },\n onStatusChange: (s, msg) => { this._status = s; this._statusMessage = msg; this.emit() },\n })\n this.conn.connect()\n }\n\n /** Subscribe to any change (message, typing, status). Returns unsubscribe. */\n onChange(fn: () => void): () => void {\n this.listeners.add(fn)\n return () => this.listeners.delete(fn)\n }\n private emit(): void { for (const fn of this.listeners) fn() }\n\n private _me: UserId | undefined\n /** Our canonical user id as resolved by the server (JWT sub / userId / anon id). */\n get me(): UserId | undefined { return this._me }\n get conversationId(): ConversationId | undefined { return this.store.conversationId }\n get status(): string { return this._status }\n get statusMessage(): string | undefined { return this._statusMessage }\n\n send(text: string): void {\n const clientMsgId = `c_${Date.now().toString(36)}_${++this.msgSeq}`\n const cid = this.store.conversationId\n if (!cid) return\n this.store.addOptimistic(clientMsgId, { kind: 'text', text })\n this.conn.send({ type: 'send', conversationId: cid, clientMsgId, content: { kind: 'text', text } })\n this.emit()\n }\n\n typing(isTyping: boolean, preview?: string): void {\n const cid = this.store.conversationId\n if (!cid) return\n this.conn.send({ type: 'typing', conversationId: cid, isTyping, ...(preview ? { preview } : {}) })\n }\n\n markRead(): void {\n const cid = this.store.conversationId\n if (!cid) return\n this.conn.send({ type: 'read', conversationId: cid, seq: this.store.highestSeq() })\n }\n\n close(): void { this.conn.close(); this.listeners.clear() }\n}\n\nexport class RelayClient {\n constructor(private readonly opts: RelayClientOptions) {}\n\n /** The identity this client will act as: the token's subject (resolved\n * server-side), the raw userId, or a persistent anonymous browser id. */\n me(): UserId {\n return asUserId(this.opts.token ?? persistentUid())\n }\n\n open(open: OpenOptions = {}): RelayConversation {\n return new RelayConversation({ ...this.opts, ...open, me: this.me() })\n }\n}\n"],"names":["TERMINAL_STATES","isTerminalState","state","toManifestAction","a","input","LIMITS","RelayConversation","opts","__publicField","ChatStore","open","asUserId","wsUrl","resolveRelayUrls","ConnectionManager","f","s","msg","fn","text","clientMsgId","cid","isTyping","preview","RelayClient","persistentUid"],"mappings":"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"}