@paramms/chat-widget 1.0.46 → 1.0.48

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/embed.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"embed.js","sources":["../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/store.ts","../src/connection.ts","../src/outbox.ts","../src/crypto.ts","../src/e2e.ts","../src/theme-tokens.ts","../src/renderer.styles.ts","../src/renderer.ts","../src/history.ts","../src/index.ts","../src/embed.ts","../src/chatlist.styles.ts","../src/chatlist.ts"],"sourcesContent":["/** 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","import type {\n ServerFrame, Message, ManifestAction, MessageContent,\n ConversationId, MessageId, UserId, Subject,\n} from './protocol/index.js'\n\nexport type SendStatus = 'pending' | 'sent' | 'delivered' | 'read'\n\nexport interface RenderMessage extends Message {\n clientMsgId?: string\n status?: SendStatus\n}\n\n/** Pure, DOM-free conversation state. Feed it ServerFrames (and local optimistic\n * sends); read an ordered, de-duplicated view out. Ordering is by `seq`; the\n * same message arriving twice (live + sync on reconnect) is collapsed by id —\n * the structural fix for the old duplicate-bubble bug. */\nexport class ChatStore {\n conversationId?: ConversationId\n state = ''\n version = 0\n hasMoreHistory = false\n lastReadByOthers = 0\n assignedAgentId: UserId | undefined\n accent: string | undefined\n subject: Subject | undefined\n name: string | undefined\n e2e = false\n offline = false\n offlineMessage = ''\n launcherMessage: { title: string; subtitle?: string } | null = null\n preChat: import('./protocol/frames.js').PreChatConfig | null = null\n whiteLabel = false\n readonly typing = new Set<string>()\n readonly online = new Set<string>()\n /** Live sentiment of the guest's latest message (agent-side only). */\n sentiment: 'positive' | 'neutral' | 'frustrated' | undefined\n sentimentScore: number | undefined\n\n private actions: ManifestAction[] = []\n private readonly byId = new Map<string, RenderMessage>()\n private readonly keyByClient = new Map<string, string>()\n private _maxSeq = 0\n private _sorted: RenderMessage[] | null = null\n\n constructor(private readonly me: UserId) {}\n\n messages(): RenderMessage[] {\n if (!this._sorted) {\n this._sorted = [...this.byId.values()].sort((a, b) => {\n const ap = a.status === 'pending', bp = b.status === 'pending'\n if (ap !== bp) return ap ? 1 : -1\n if (ap && bp) return a.ts - b.ts\n return a.seq - b.seq\n })\n }\n return this._sorted\n }\n\n visibleActions(): ManifestAction[] {\n return this.actions.filter(a => !a.availableInStates || a.availableInStates.includes(this.state))\n }\n\n highestSeq(): number { return this._maxSeq }\n\n addOptimistic(clientMsgId: string, content: MessageContent): RenderMessage {\n const msg: RenderMessage = {\n id: clientMsgId as MessageId, conversationId: this.conversationId as ConversationId,\n seq: 0, senderId: this.me, senderRole: 'guest', content, ts: Date.now(),\n clientMsgId, status: 'pending',\n }\n this.byId.set(clientMsgId, msg)\n this.keyByClient.set(clientMsgId, clientMsgId)\n this._sorted = null\n return msg\n }\n\n apply(frame: ServerFrame): void {\n switch (frame.type) {\n case 'opened':\n this.conversationId = frame.conversation.id\n this.state = frame.conversation.state\n if (frame.subject) this.subject = frame.subject\n return\n case 'manifest':\n this.actions = frame.actions\n this.version = frame.version\n if (frame.name) this.name = frame.name\n if (frame.theme?.accent) this.accent = frame.theme.accent\n if (frame.e2e) this.e2e = true\n // Track the manifest EXACTLY: a sticky `offline` (only ever set, never\n // cleared) kept the widget in away-mode for the whole session once a\n // single manifest said so — which used to hide the composer entirely.\n this.offline = frame.offline === true\n this.offlineMessage = frame.offlineMessage ?? ''\n if (frame.launcherMessage) this.launcherMessage = frame.launcherMessage\n if (frame.whiteLabel) this.whiteLabel = true\n if (frame.preChat) this.preChat = frame.preChat\n return\n case 'message':\n this.upsert({ ...frame.message })\n return\n case 'ack': {\n const key = this.keyByClient.get(frame.clientMsgId)\n const msg = key ? this.byId.get(key) : undefined\n if (msg && key) {\n this.byId.delete(key)\n const confirmed: RenderMessage = { ...msg, id: frame.messageId, seq: frame.seq, ts: frame.ts, status: 'sent' }\n this.byId.set(frame.messageId, confirmed)\n this.keyByClient.set(frame.clientMsgId, frame.messageId)\n if (frame.seq > this._maxSeq) this._maxSeq = frame.seq\n }\n this._sorted = null\n return\n }\n case 'delivered':\n this.markOwnStatus(frame.seq, 'delivered')\n return\n case 'read':\n if (frame.by !== this.me) {\n this.lastReadByOthers = Math.max(this.lastReadByOthers, frame.seq)\n this.markOwnStatus(frame.seq, 'read')\n }\n return\n case 'sync':\n for (const m of frame.messages) this.upsert({ ...m })\n return\n case 'history':\n for (const m of frame.messages) this.upsert({ ...m })\n this.hasMoreHistory = frame.hasMore\n return\n case 'typing':\n if (frame.userId !== this.me) {\n if (frame.isTyping) this.typing.add(frame.userId)\n else this.typing.delete(frame.userId)\n }\n return\n case 'reaction': {\n const m = this.byId.get(frame.messageId)\n if (!m) return\n const reactions: Record<string, UserId[]> = { ...(m.reactions ?? {}) }\n const users = (reactions[frame.emoji] ?? []).filter(u => u !== frame.by)\n if (!frame.removed) users.push(frame.by)\n if (users.length) reactions[frame.emoji] = users; else delete reactions[frame.emoji]\n this.byId.set(frame.messageId, { ...m, reactions })\n this._sorted = null\n return\n }\n case 'edited': {\n const m = this.byId.get(frame.messageId)\n if (m) { this.byId.set(frame.messageId, { ...m, content: frame.content, editedAt: frame.editedAt }); this._sorted = null }\n return\n }\n case 'deleted': {\n const m = this.byId.get(frame.messageId)\n if (m) { this.byId.set(frame.messageId, { ...m, deletedAt: frame.ts }); this._sorted = null }\n return\n }\n case 'state':\n this.state = frame.state\n return\n case 'assigned':\n this.assignedAgentId = frame.agentId ?? undefined\n return\n case 'presence':\n if (frame.status === 'online') this.online.add(frame.userId)\n else this.online.delete(frame.userId)\n return\n case 'subjectState':\n case 'invoked':\n case 'authed':\n case 'error':\n case 'pong':\n return\n case 'sentiment':\n this.sentiment = frame.label\n this.sentimentScore = frame.score\n return\n default:\n return\n }\n }\n\n private upsert(msg: RenderMessage): void {\n const existing = this.byId.get(msg.id)\n this.byId.set(msg.id, existing ? { ...existing, ...msg } : msg)\n if (msg.seq > this._maxSeq) this._maxSeq = msg.seq\n this._sorted = null\n }\n\n private markOwnStatus(uptoSeq: number, status: SendStatus): void {\n const targetRank = rank(status)\n let changed = false\n for (const [k, m] of this.byId) {\n if (m.senderId !== this.me || m.seq <= 0 || m.seq > uptoSeq) continue\n if (rank(m.status) >= targetRank) continue // already at or above target — skip\n this.byId.set(k, { ...m, status })\n changed = true\n }\n if (changed) this._sorted = null\n }\n}\nfunction rank(s: SendStatus | undefined): number {\n switch (s) { case 'read': return 3; case 'delivered': return 2; case 'sent': return 1; default: return 0 }\n}\n","import {\n encodeFrame, decodeFrame, isClientFrame,\n type ClientFrame, type ServerFrame,\n} from './protocol/index.js'\n\n// Minimal socket surface so tests can inject a fake without a real WebSocket.\nexport interface SocketLike {\n binaryType: string\n send(data: Uint8Array): void\n close(): void\n onopen: (() => void) | null\n onclose: (() => void) | null\n onerror: (() => void) | null\n onmessage: ((ev: { data: ArrayBuffer }) => void) | null\n}\nexport type SocketFactory = (url: string) => SocketLike\n\nexport interface ConnectionOptions {\n url: string\n token: string\n /** Authenticated embeds: called when the server rejects the token\n * (typically an expired signed JWT). Return a freshly minted token to\n * resume seamlessly, or null to give up (shows the fatal error). */\n refreshToken?: () => Promise<string | null>\n open: ClientFrame // frame sent right after auth (e.g. open a conversation, or subscribe_inbox)\n onFrame: (frame: ServerFrame) => void\n getCursor: () => number // highest seq seen (for sync on reconnect)\n onStatusChange?: (status: 'connecting' | 'open' | 'reconnecting' | 'error', message?: string) => void\n socketFactory?: SocketFactory\n backoffBaseMs?: number\n backoffMaxMs?: number\n maxOutbox?: number\n}\n\ntype State = 'idle' | 'connecting' | 'open' | 'closed'\n\nexport class ConnectionManager {\n private socket: SocketLike | null = null\n private state: State = 'idle'\n private authed = false\n private everAuthed = false\n private attempt = 0\n private outbox: ClientFrame[] = []\n private stopped = false\n private timer: ReturnType<typeof setTimeout> | null = null\n\n constructor(private readonly opts: ConnectionOptions) {}\n\n connect(): void {\n if (this.state === 'connecting' || this.state === 'open') return\n this.stopped = false\n this.state = 'connecting'\n this.authed = false\n this.opts.onStatusChange?.(this.attempt > 0 ? 'reconnecting' : 'connecting')\n const make = this.opts.socketFactory ?? defaultFactory\n const sock = make(this.opts.url)\n sock.binaryType = 'arraybuffer'\n this.socket = sock\n\n sock.onopen = () => {\n // Don't reset attempt here — reset only after successful auth ('authed').\n // A connection that opens but fails during auth (bad token, server restart)\n // should still back off, not immediately retry at base delay.\n this.raw({ type: 'auth', token: this.opts.token })\n }\n sock.onmessage = (ev) => {\n const frame = decodeFrame(new Uint8Array(ev.data))\n if (!frame || isClientFrame(frame)) return // ignore non-server frames\n this.handle(frame)\n }\n sock.onclose = () => this.onClosed()\n sock.onerror = () => { try { sock.close() } catch { /* */ } }\n }\n\n /** Queue a frame; sent immediately if open, else flushed on (re)connect.\n * The outbox is bounded so a prolonged outage can't grow memory without limit\n * — oldest queued frames are dropped past the cap. */\n send(frame: ClientFrame): void {\n if (this.state === 'open' && this.authed) { this.raw(frame); return }\n // Evicts the oldest half when full to amortise the O(n) cost of overflow.\n this.queue(frame)\n }\n\n /** How many frames are waiting to go out. Useful for a host that wants to\n * show \"message pending\" state, and for asserting the outbox stays bounded. */\n pendingCount(): number { return this.outbox.length }\n\n close(): void {\n this.stopped = true\n if (this.timer) clearTimeout(this.timer)\n this.state = 'closed'\n try { this.socket?.close() } catch { /* */ }\n }\n\n private handle(frame: ServerFrame): void {\n if (frame.type === 'authed') {\n this.attempt = 0 // reset backoff only after a fully successful auth\n this.state = 'open'\n this.authed = true; this.everAuthed = true\n this.opts.onStatusChange?.('open')\n // Open/resolve the conversation. The catch-up `sync` is sent on 'opened'\n // (below), i.e. only after the server has joined us to the room — sending\n // it here would race the async open and be rejected as \"not joined\".\n this.raw(this.opts.open)\n // The QUEUED frames need exactly the same treatment, and used to not get\n // it: flushing here fired them straight after `open`, before the server\n // had joined us, so the engine answered FORBIDDEN 'Open the conversation\n // first' and the message was gone — no ack, no requeue. This is the\n // reconnect-drops-your-message bug. Frames now wait for 'opened' below.\n //\n // EXCEPT when the open frame doesn't produce a join at all: an inbox\n // subscription (`subscribe_inbox`) never gets an 'opened' reply, so\n // waiting for one would strand the queue forever. Nothing needs joining\n // in that case, so flushing immediately is both safe and required.\n if (this.opts.open.type !== 'open') this.flush()\n }\n // 'opened' confirms we're joined — now catch up from our cursor, then\n // release anything queued while we were disconnected.\n if (frame.type === 'opened') {\n this.raw({ type: 'sync', conversationId: frame.conversation.id, sinceSeq: this.opts.getCursor() })\n this.flush(frame.conversation.id)\n }\n // A CONNECTION-FATAL error (bad or rejected token, closed or missing\n // chatroom) will never succeed on retry — stop the reconnect loop and report\n // a clear reason instead of spinning on \"connecting…\" forever. Per-frame\n // errors (rate limit, one bad message) are NOT fatal and fall through.\n if (frame.type === 'error' && FATAL_ERRORS.has(frame.code)) {\n // Token refresh (authenticated embeds): a signed JWT expiring mid-session\n // used to be a dead end — the widget showed a fatal error until reload.\n // If the host supplied refreshToken, ask it to mint a fresh one and\n // reconnect. One in-flight attempt at a time; a refresh that returns\n // null/throws (user logged out, backend down) falls through to fatal.\n if (frame.code === 'UNAUTHORIZED' && this.opts.refreshToken && !this.refreshing) {\n this.refreshing = true\n this.opts.onStatusChange?.('reconnecting', 'Renewing session…')\n void this.opts.refreshToken()\n .then((fresh) => {\n this.refreshing = false\n if (!fresh) { this.fatal(frame); return }\n this.opts.token = fresh\n try { this.socket?.close() } catch { /* */ }\n // onClosed schedules the reconnect, which re-auths with the new token.\n })\n .catch(() => { this.refreshing = false; this.fatal(frame) })\n return\n }\n this.fatal(frame)\n return\n }\n this.opts.onFrame(frame)\n }\n\n private refreshing = false\n\n private fatal(frame: Extract<ServerFrame, { type: 'error' }>): void {\n this.stopped = true\n try { this.socket?.close() } catch { /* */ }\n this.state = 'closed'\n this.opts.onStatusChange?.('error', friendlyError(frame.code))\n this.opts.onFrame(frame)\n }\n\n /** Release queued frames. When called from 'opened' we know the canonical\n * conversation id the server just resolved us to, and queued `send` frames\n * are retargeted to it. A manager only ever opens ONE conversation (its\n * `opts.open`), so every queued send belongs to that thread by\n * construction — but the id it was queued with can be STALE (queued against\n * the previous session's conversation before a reconnect). Retargeting is a\n * no-op in the normal case and rescues the message in the stale one. */\n private flush(conversationId?: string): void {\n const pending = this.outbox\n this.outbox = []\n for (const f of pending) {\n this.raw(\n conversationId && f.type === 'send' && f.conversationId !== conversationId\n ? { ...f, conversationId: conversationId as typeof f.conversationId }\n : f,\n )\n }\n }\n\n /** Bounded enqueue — the cap lives here so EVERY path that queues respects\n * it (a failed `raw` used to push straight onto the array, bypassing it). */\n private queue(frame: ClientFrame): void {\n const cap = this.opts.maxOutbox ?? 1_000\n if (this.outbox.length >= cap) {\n this.outbox = this.outbox.slice(this.outbox.length - (cap >> 1))\n }\n this.outbox.push(frame)\n }\n\n private raw(frame: ClientFrame): void {\n // `this.socket?.send(...)` silently DROPPED the frame whenever the socket\n // was null (post-disconnect, pre-reconnect): optional chaining short-\n // circuits, so nothing throws and the catch that re-queues never runs.\n // A null socket is exactly when a frame most needs to be kept.\n if (!this.socket) { this.queue(frame); return }\n try { this.socket.send(encodeFrame(frame)) } catch { this.queue(frame) }\n }\n\n private onClosed(): void {\n this.authed = false\n this.socket = null\n if (this.stopped) { this.state = 'closed'; return }\n this.state = 'idle'\n // Exponential backoff with jitter; reconnect re-auths, re-opens, re-syncs.\n const base = this.opts.backoffBaseMs ?? 500\n const max = this.opts.backoffMaxMs ?? 15_000\n const delay = Math.min(max, base * 2 ** this.attempt) * (0.5 + Math.random() * 0.5)\n this.attempt++\n // If we've never once connected after several tries, the relay is likely\n // unreachable (wrong URL, server down, blocked) — say so, but keep retrying.\n if (this.attempt >= 3 && !this.everAuthed) {\n this.opts.onStatusChange?.('reconnecting', \"Can't reach chat — retrying…\")\n }\n this.timer = setTimeout(() => this.connect(), delay)\n }\n}\n\n/** Connection-fatal error codes — retrying can't fix these. ONLY auth-handshake\n * failure qualifies: FORBIDDEN / NOT_FOUND are per-REQUEST errors (a stale\n * reference, one permission check) and must NOT tear down the whole socket. */\nconst FATAL_ERRORS = new Set(['UNAUTHORIZED'])\nfunction friendlyError(code: string): string {\n switch (code) {\n case 'UNAUTHORIZED': return 'Chat unavailable — sign-in/token was rejected'\n default: return 'Chat unavailable'\n }\n}\n\nfunction defaultFactory(url: string): SocketLike {\n return new WebSocket(url) as unknown as SocketLike\n}\n","import type { MessageContent } from './protocol/index.js'\n\nexport interface OutboxItem {\n clientMsgId: string\n content: MessageContent\n ts: number\n}\n\nconst MAX_ITEMS = 200 // cap so a long outage can't grow storage unboundedly\nconst MAX_AGE_MS = 7 * 86_400_000 // drop anything older than 7 days on load\n\n/** Persists not-yet-acknowledged outgoing messages to localStorage, keyed by\n * guest token, so a page reload during a connectivity drop doesn't silently\n * lose what the user typed (the \"WhatsApp\" guarantee: your message is queued\n * until it's confirmed sent, even across app restarts). */\nexport class PersistentOutbox {\n private readonly key: string\n\n constructor(token: string) {\n this.key = `ocw_outbox_${token}`\n }\n\n /** All pending items, oldest first, with stale (>7d) entries dropped. */\n load(): OutboxItem[] {\n try {\n const raw = localStorage.getItem(this.key)\n if (!raw) return []\n const items = JSON.parse(raw) as OutboxItem[]\n const cutoff = Date.now() - MAX_AGE_MS\n const fresh = items.filter(i => i.ts >= cutoff)\n if (fresh.length !== items.length) this.save(fresh)\n return fresh\n } catch {\n return []\n }\n }\n\n add(item: OutboxItem): void {\n try {\n const items = this.load()\n items.push(item)\n // Evict oldest when full — matches the in-memory ConnectionManager outbox policy.\n this.save(items.length > MAX_ITEMS ? items.slice(items.length - MAX_ITEMS) : items)\n } catch { /* localStorage unavailable (private mode, quota) — best-effort only */ }\n }\n\n /** Remove an item once it's been acknowledged by the server. */\n remove(clientMsgId: string): void {\n try {\n const items = this.load().filter(i => i.clientMsgId !== clientMsgId)\n this.save(items)\n } catch { /* best-effort */ }\n }\n\n private save(items: OutboxItem[]): void {\n try { localStorage.setItem(this.key, JSON.stringify(items)) } catch { /* quota exceeded — drop silently */ }\n }\n}\n","/**\n * End-to-end encryption primitives (Web Crypto): ECDH P-256 for key agreement\n * + AES-GCM for message content. The server only ever relays public keys and\n * stores ciphertext — it cannot read messages.\n *\n * Scope/limitations (honest): this secures a *live 1:1* session — the guest and\n * one agent exchange public keys while both are connected, then messages between\n * them are encrypted. True asynchronous E2E (encrypting to an offline party)\n * needs a prekey/X3DH scheme, which is out of scope here. When E2E is on, the\n * AI assistant cannot read the room (by design).\n */\n\nconst subtle = (): SubtleCrypto => globalThis.crypto.subtle\n\nfunction b64encode(buf: ArrayBuffer | Uint8Array): string {\n const bytes = buf instanceof Uint8Array ? buf : new Uint8Array(buf)\n let s = ''\n for (const b of bytes) s += String.fromCharCode(b)\n return btoa(s)\n}\nfunction b64decode(s: string): Uint8Array<ArrayBuffer> {\n const bin = atob(s)\n const buf = new ArrayBuffer(bin.length)\n const out = new Uint8Array(buf)\n for (let i = 0; i < bin.length; i++) out[i] = bin.charCodeAt(i)\n return out\n}\n\nexport interface KeyPair { publicKey: CryptoKey; privateKey: CryptoKey }\n\nexport async function generateKeyPair(): Promise<KeyPair> {\n const kp = await subtle().generateKey({ name: 'ECDH', namedCurve: 'P-256' }, true, ['deriveKey', 'deriveBits'])\n return { publicKey: kp.publicKey, privateKey: kp.privateKey }\n}\n\n/** Export a public key to a compact base64 string (raw, 65 bytes for P-256). */\nexport async function exportPublicKey(key: CryptoKey): Promise<string> {\n return b64encode(await subtle().exportKey('raw', key))\n}\n\nasync function importPeerPublicKey(b64: string): Promise<CryptoKey> {\n return subtle().importKey('raw', b64decode(b64), { name: 'ECDH', namedCurve: 'P-256' }, false, [])\n}\n\n/** Derive the shared AES-GCM key from our private key + the peer's public key. */\nexport async function deriveSharedKey(privateKey: CryptoKey, peerPublicKeyB64: string): Promise<CryptoKey> {\n const peer = await importPeerPublicKey(peerPublicKeyB64)\n return subtle().deriveKey(\n { name: 'ECDH', public: peer },\n privateKey,\n { name: 'AES-GCM', length: 256 },\n false,\n ['encrypt', 'decrypt'],\n )\n}\n\nexport interface Ciphertext { ct: string; iv: string }\n\nexport async function encrypt(key: CryptoKey, plaintext: string): Promise<Ciphertext> {\n const iv = globalThis.crypto.getRandomValues(new Uint8Array(12))\n const data = new TextEncoder().encode(plaintext)\n const ct = await subtle().encrypt({ name: 'AES-GCM', iv }, key, data)\n return { ct: b64encode(ct), iv: b64encode(iv) }\n}\n\nexport async function decrypt(key: CryptoKey, ct: string, iv: string): Promise<string> {\n const plain = await subtle().decrypt({ name: 'AES-GCM', iv: b64decode(iv) }, key, b64decode(ct))\n return new TextDecoder().decode(plain)\n}\n\n/** Persist/restore our keypair across reloads (so prior ciphertext stays readable). */\nexport async function loadOrCreateKeyPair(storageKey: string): Promise<KeyPair> {\n try {\n const raw = globalThis.localStorage?.getItem(storageKey)\n if (raw) {\n const { pub, priv } = JSON.parse(raw) as { pub: JsonWebKey; priv: JsonWebKey }\n const publicKey = await subtle().importKey('jwk', pub, { name: 'ECDH', namedCurve: 'P-256' }, true, [])\n const privateKey = await subtle().importKey('jwk', priv, { name: 'ECDH', namedCurve: 'P-256' }, true, ['deriveKey', 'deriveBits'])\n return { publicKey, privateKey }\n }\n } catch { /* fall through to fresh keys */ }\n const kp = await generateKeyPair()\n try {\n const pub = await subtle().exportKey('jwk', kp.publicKey)\n const priv = await subtle().exportKey('jwk', kp.privateKey)\n globalThis.localStorage?.setItem(storageKey, JSON.stringify({ pub, priv }))\n } catch { /* non-persistent environment is fine */ }\n return kp\n}\n\n// ── X3DH async E2E ────────────────────────────────────────────────────────────\n// Extended Triple Diffie-Hellman (X3DH) allows encrypting to an *offline* peer\n// using their published prekey bundle. This enables asynchronous E2E: the sender\n// can encrypt before the recipient connects.\n//\n// Key roles:\n// IK = long-term identity key (ECDH P-256, persistent in localStorage)\n// SPK = signed prekey (ECDH P-256, rotated periodically, server-stored)\n// OPK = one-time prekey (ECDH P-256, single-use pool, server-stored)\n// EK = ephemeral key (ECDH P-256, generated per-message, discarded after)\n//\n// X3DH shared secret = KDF(DH(IK_s, SPK_r) || DH(EK, IK_r) || DH(EK, SPK_r) || DH(EK, OPK_r))\n// Where _s = sender, _r = recipient.\n\n/** Sign a prekey public key bytes using ECDSA P-256 SHA-256.\n * The signingKey must be an ECDSA P-256 private key (not ECDH).\n * In the full X3DH setup the identity key pair contains both an ECDH key\n * (for DH) and an ECDSA key (for signing). We keep them separate here. */\nexport async function signPrekey(signingPrivateKey: CryptoKey, spkPublicKey: CryptoKey): Promise<string> {\n const spkRaw = await subtle().exportKey('raw', spkPublicKey)\n const sig = await subtle().sign({ name: 'ECDSA', hash: 'SHA-256' }, signingPrivateKey, spkRaw)\n return b64encode(sig)\n}\n\n/** Verify an SPK signature. verifyPublicKey must be an ECDSA P-256 public key. */\nexport async function verifyPrekeySignature(verifyPublicKeyB64: string, spkPublicKeyB64: string, signatureB64: string): Promise<boolean> {\n try {\n const verKey = await subtle().importKey('raw', b64decode(verifyPublicKeyB64), { name: 'ECDSA', namedCurve: 'P-256' }, false, ['verify'])\n return await subtle().verify({ name: 'ECDSA', hash: 'SHA-256' }, verKey, b64decode(signatureB64), b64decode(spkPublicKeyB64))\n } catch { return false }\n}\n\n/** A full identity keypair for X3DH: ECDH key for DH computations + ECDSA key\n * for signing prekeys. The two key objects share the same P-256 curve but have\n * different usages, so Web Crypto treats them separately. */\nexport interface IdentityKeyPair {\n ecdhKP: KeyPair // for DH in X3DH\n ecdsaKP: { publicKey: CryptoKey; privateKey: CryptoKey } // for signing SPKs\n /** The ECDH public key exported as base64 — used as the X3DH identity key. */\n publicKeyB64: string\n /** The ECDSA public key exported as base64 — used for SPK signature verification. */\n sigPublicKeyB64: string\n}\n\n/** Generate a full X3DH identity keypair (ECDH + ECDSA on the same P-256 curve). */\nexport async function generateIdentityKeyPair(): Promise<IdentityKeyPair> {\n const ecdhKP = await generateKeyPair()\n const ecdsaKP = await subtle().generateKey({ name: 'ECDSA', namedCurve: 'P-256' }, true, ['sign', 'verify'])\n return {\n ecdhKP,\n ecdsaKP: { publicKey: ecdsaKP.publicKey, privateKey: ecdsaKP.privateKey },\n publicKeyB64: await exportPublicKey(ecdhKP.publicKey),\n sigPublicKeyB64: await exportPublicKey(ecdsaKP.publicKey),\n }\n}\n\n/** Load or generate an identity keypair, persisting both components. */\nexport async function loadOrCreateIdentityKeyPair(storageKey: string): Promise<IdentityKeyPair> {\n try {\n const raw = globalThis.localStorage?.getItem(`${storageKey}-identity`)\n if (raw) {\n const d = JSON.parse(raw) as { ecdhPub: JsonWebKey; ecdhPriv: JsonWebKey; ecdsaPub: JsonWebKey; ecdsaPriv: JsonWebKey }\n const ecdhPub = await subtle().importKey('jwk', d.ecdhPub, { name: 'ECDH', namedCurve: 'P-256' }, true, [])\n const ecdhPriv = await subtle().importKey('jwk', d.ecdhPriv, { name: 'ECDH', namedCurve: 'P-256' }, true, ['deriveKey', 'deriveBits'])\n const ecdsaPub = await subtle().importKey('jwk', d.ecdsaPub, { name: 'ECDSA', namedCurve: 'P-256' }, true, ['verify'])\n const ecdsaPriv = await subtle().importKey('jwk', d.ecdsaPriv, { name: 'ECDSA', namedCurve: 'P-256' }, true, ['sign'])\n return {\n ecdhKP: { publicKey: ecdhPub, privateKey: ecdhPriv },\n ecdsaKP: { publicKey: ecdsaPub, privateKey: ecdsaPriv },\n publicKeyB64: await exportPublicKey(ecdhPub),\n sigPublicKeyB64: await exportPublicKey(ecdsaPub),\n }\n }\n } catch { /* generate fresh */ }\n const ikp = await generateIdentityKeyPair()\n try {\n const ecdhPub = await subtle().exportKey('jwk', ikp.ecdhKP.publicKey)\n const ecdhPriv = await subtle().exportKey('jwk', ikp.ecdhKP.privateKey)\n const ecdsaPub = await subtle().exportKey('jwk', ikp.ecdsaKP.publicKey)\n const ecdsaPriv = await subtle().exportKey('jwk', ikp.ecdsaKP.privateKey)\n globalThis.localStorage?.setItem(`${storageKey}-identity`, JSON.stringify({ ecdhPub, ecdhPriv, ecdsaPub, ecdsaPriv }))\n } catch { /* non-persistent ok */ }\n return ikp\n}\n\nexport interface X3DHBundle {\n identityKey: string // base64 raw P-256 public key\n signedPrekey: string // base64 raw P-256 public key\n signedPrekeyId: string // opaque ID for key rotation tracking\n signature: string // base64 ECDSA signature of SPK by IK\n oneTimePrekey?: string // base64 raw P-256 public key (optional)\n}\n\n/** X3DH sender side: derive a shared key from the recipient's prekey bundle.\n * Returns the shared AES-GCM key and the ephemeral public key to transmit. */\nexport async function x3dhSend(\n senderIK: KeyPair,\n recipientBundle: X3DHBundle,\n): Promise<{ sharedKey: CryptoKey; ephemeralPublicKey: string }> {\n const ek = await generateKeyPair()\n const epkB64 = await exportPublicKey(ek.publicKey)\n\n // Import recipient keys for DH.\n const ik_r = await importPeerPublicKey(recipientBundle.identityKey)\n const spk_r = await importPeerPublicKey(recipientBundle.signedPrekey)\n const opk_r = recipientBundle.oneTimePrekey ? await importPeerPublicKey(recipientBundle.oneTimePrekey) : null\n\n // Four DH computations per spec (three if no OPK).\n const dh1 = await rawDH(senderIK.privateKey, spk_r) // DH(IK_s, SPK_r)\n const dh2 = await rawDH(ek.privateKey, ik_r) // DH(EK, IK_r)\n const dh3 = await rawDH(ek.privateKey, spk_r) // DH(EK, SPK_r)\n const dh4 = opk_r ? await rawDH(ek.privateKey, opk_r) : null // DH(EK, OPK_r)\n\n const ikm = concatBuffers(dh1, dh2, dh3, ...(dh4 ? [dh4] : []))\n const sharedKey = await hkdfDeriveKey(ikm)\n\n return { sharedKey, ephemeralPublicKey: epkB64 }\n}\n\n/** X3DH recipient side: rederive the shared key from an init message.\n * Returns the shared AES-GCM key. */\nexport async function x3dhReceive(\n recipientIK: KeyPair,\n recipientSPK: KeyPair,\n senderIKb64: string,\n ephemeralKeyB64: string,\n recipientOPK?: KeyPair,\n): Promise<CryptoKey> {\n const ik_s = await importPeerPublicKey(senderIKb64)\n const ek_s = await importPeerPublicKey(ephemeralKeyB64)\n\n const dh1 = await rawDH(recipientSPK.privateKey, ik_s) // DH(SPK_r, IK_s)\n const dh2 = await rawDH(recipientIK.privateKey, ek_s) // DH(IK_r, EK)\n const dh3 = await rawDH(recipientSPK.privateKey, ek_s) // DH(SPK_r, EK)\n const dh4 = recipientOPK ? await rawDH(recipientOPK.privateKey, ek_s) : null\n\n const ikm = concatBuffers(dh1, dh2, dh3, ...(dh4 ? [dh4] : []))\n return hkdfDeriveKey(ikm)\n}\n\nasync function rawDH(privateKey: CryptoKey, publicKey: CryptoKey): Promise<ArrayBuffer> {\n return subtle().deriveBits({ name: 'ECDH', public: publicKey }, privateKey, 256)\n}\n\nfunction concatBuffers(...bufs: ArrayBuffer[]): ArrayBuffer {\n const total = bufs.reduce((n, b) => n + b.byteLength, 0)\n const out = new Uint8Array(total)\n let offset = 0\n for (const b of bufs) { out.set(new Uint8Array(b), offset); offset += b.byteLength }\n return out.buffer\n}\n\nasync function hkdfDeriveKey(ikm: ArrayBuffer): Promise<CryptoKey> {\n const ikmKey = await subtle().importKey('raw', ikm, 'HKDF', false, ['deriveKey'])\n return subtle().deriveKey(\n { name: 'HKDF', hash: 'SHA-256', salt: new Uint8Array(32), info: new TextEncoder().encode('ObjectChat X3DH v1') },\n ikmKey,\n { name: 'AES-GCM', length: 256 },\n false,\n ['encrypt', 'decrypt'],\n )\n}\n","import type { MessageContent, UserId } from './protocol/index.js'\nimport type { ServerFrame } from './protocol/index.js'\nimport {\n type KeyPair, loadOrCreateKeyPair, exportPublicKey, deriveSharedKey, encrypt, decrypt,\n generateKeyPair, signPrekey, x3dhSend, x3dhReceive, type X3DHBundle,\n loadOrCreateIdentityKeyPair, type IdentityKeyPair,\n} from './crypto.js'\n\n// Number of one-time prekeys to generate per upload batch.\nconst OTP_BATCH_SIZE = 20\n\n/**\n * Per-user E2E session. Supports two modes:\n *\n * LIVE (original): Both parties are online. ECDH P-256 key exchange via the\n * `pubkey`/`peerkey` frames. Instant but requires both parties to be connected.\n *\n * ASYNC (X3DH): The sender encrypts to the recipient's prekey bundle while the\n * recipient is offline. Uses X3DH (Extended Triple DH) with identity keys,\n * signed prekeys, and one-time prekeys. The recipient derives the same shared\n * key from the init message when they come online.\n *\n * Both modes produce an AES-GCM 256 shared key for message encryption.\n */\nexport class E2ESession {\n // Live ECDH mode state\n private kp?: KeyPair\n private shared?: CryptoKey\n\n // X3DH async mode state\n private identityKP: IdentityKeyPair | undefined = undefined\n private signedPreKP: KeyPair | undefined = undefined\n private signedPrekeyId: string | undefined = undefined\n private readonly otpKeys: KeyPair[] = [] // one-time prekeys awaiting matching\n private x3dhShared?: CryptoKey\n // Queued init messages arriving before we could derive (shouldn't happen, but safe)\n private pendingX3DH: { senderIK: string; ephemeralKey: string; spkId: string; usedOTP: boolean } | undefined = undefined\n\n constructor(private readonly storageKey: string) {}\n\n get ready(): boolean { return !!(this.shared ?? this.x3dhShared) }\n\n /** Live ECDH mode: Generate/restore our keypair and return our public key to publish. */\n async begin(): Promise<string> {\n this.kp = await loadOrCreateKeyPair(this.storageKey)\n return exportPublicKey(this.kp.publicKey)\n }\n\n /** Live ECDH mode: A peer published their key — derive the shared secret. */\n async onPeerKey(peerKeyB64: string): Promise<void> {\n if (!this.kp) return\n this.shared = await deriveSharedKey(this.kp.privateKey, peerKeyB64)\n }\n\n // ── X3DH async mode ────────────────────────────────────────────────────────\n\n /** X3DH: Generate identity key, signed prekey, and OTP prekeys.\n * Returns the upload frame payload the caller should send to the server. */\n async initX3DH(): Promise<{\n identityKey: string; signedPrekey: string; signedPrekeyId: string;\n signature: string; oneTimePrekeys: string[]\n }> {\n // Restore or generate persistent identity keypair (ECDH + ECDSA).\n this.identityKP = await loadOrCreateIdentityKeyPair(this.storageKey)\n // Always generate a fresh signed prekey (rotation).\n this.signedPreKP = await generateKeyPair()\n this.signedPrekeyId = `spk-${Date.now()}-${Math.random().toString(36).slice(2)}`\n // Batch of one-time prekeys.\n for (let i = 0; i < OTP_BATCH_SIZE; i++) this.otpKeys.push(await generateKeyPair())\n\n const signedPrekeyPub = await exportPublicKey(this.signedPreKP.publicKey)\n const signature = await signPrekey(this.identityKP.ecdsaKP.privateKey, this.signedPreKP.publicKey)\n const oneTimePrekeys = await Promise.all(this.otpKeys.map(kp => exportPublicKey(kp.publicKey)))\n\n return {\n identityKey: this.identityKP.publicKeyB64,\n signedPrekey: signedPrekeyPub,\n signedPrekeyId: this.signedPrekeyId,\n signature,\n oneTimePrekeys,\n }\n }\n\n /** X3DH sender: given a recipient's prekey bundle, derive the shared key and\n * return the init message fields to embed in the first encrypted message. */\n async x3dhSendTo(bundle: X3DHBundle): Promise<{ ephemeralKey: string; spkId: string; usedOTP: boolean; senderIK: string }> {\n if (!this.identityKP) this.identityKP = await loadOrCreateIdentityKeyPair(this.storageKey)\n const { sharedKey, ephemeralPublicKey } = await x3dhSend(this.identityKP.ecdhKP, bundle)\n this.x3dhShared = sharedKey\n return { ephemeralKey: ephemeralPublicKey, spkId: bundle.signedPrekeyId, usedOTP: !!bundle.oneTimePrekey, senderIK: this.identityKP.publicKeyB64 }\n }\n\n /** X3DH recipient: given an init message's sender IK + EK + SPK ID, derive\n * the shared key. `usedOTP` MUST reflect whether the SENDER actually\n * included a one-time prekey in its DH computation (carried on the wire\n * as `x3dhOTP`, see `X3DHInitFields`) — it must never be inferred from\n * whether we happen to still have OTP keys locally. Popping one\n * unconditionally was the bug here: our OTP pool almost always has spare\n * keys (we upload a batch of 20 and only the sender's own choice consumes\n * one), so we'd derive dh4 against an OTP the sender never included,\n * producing a shared key that doesn't match the sender's — every\n * message would come back \"🔒 unable to decrypt\" — while also burning a\n * one-time key that was never actually used. */\n async x3dhReceiveFrom(senderIKb64: string, ephemeralKeyB64: string, spkId: string, usedOTP: boolean): Promise<void> {\n if (!this.identityKP || !this.signedPreKP) {\n // Keys not yet initialised — queue for when initX3DH completes.\n this.pendingX3DH = { senderIK: senderIKb64, ephemeralKey: ephemeralKeyB64, spkId, usedOTP }\n return\n }\n // Only consume an OTP when the sender's own message says it used one.\n const otp = usedOTP ? this.otpKeys.shift() : undefined\n this.x3dhShared = await x3dhReceive(this.identityKP.ecdhKP, this.signedPreKP, senderIKb64, ephemeralKeyB64, otp)\n void spkId // we matched by position; full impl would look up by ID\n }\n\n /** Flush pending X3DH derivation after initX3DH() completes. */\n async flushPendingX3DH(): Promise<void> {\n if (!this.pendingX3DH) return\n const { senderIK, ephemeralKey, spkId, usedOTP } = this.pendingX3DH\n this.pendingX3DH = undefined\n await this.x3dhReceiveFrom(senderIK, ephemeralKey, spkId, usedOTP)\n }\n\n /** Encrypt outgoing text into a wire content object. For X3DH init messages,\n * the caller should pass x3dhInit fields to embed in the content. */\n async sealText(text: string, x3dhInit?: { ephemeralKey: string; spkId: string; senderIK: string; usedOTP: boolean }): Promise<MessageContent> {\n const key = this.x3dhShared ?? this.shared\n if (!key) throw new Error('secure channel not ready')\n const { ct, iv } = await encrypt(key, text)\n return {\n kind: 'text', text: ct, enc: true, iv,\n ...(x3dhInit ? { x3dhEK: x3dhInit.ephemeralKey, x3dhSPK: x3dhInit.spkId, x3dhIK: x3dhInit.senderIK, x3dhOTP: x3dhInit.usedOTP } as never : {}),\n }\n }\n\n /** Decrypt one content object if it is encrypted (otherwise pass through). */\n private async openContent(content: MessageContent): Promise<MessageContent> {\n if (content.kind !== 'text' || !content.enc || !content.iv) return content\n const key = this.x3dhShared ?? this.shared\n if (!key) return { kind: 'text', text: '🔒 encrypted' }\n try { return { kind: 'text', text: await decrypt(key, content.text, content.iv) } }\n catch { return { kind: 'text', text: '🔒 unable to decrypt' } }\n }\n\n /** Decrypt any encrypted message content carried by an incoming frame, in place. */\n async openFrame(frame: ServerFrame): Promise<void> {\n if (frame.type === 'message') frame.message.content = await this.openContent(frame.message.content)\n else if (frame.type === 'sync') {\n for (const m of frame.messages) m.content = await this.openContent(m.content)\n }\n }\n}\n\n/** X3DH init fields embedded in a text MessageContent (as extra properties).\n * Present only on the very first message from a sender to an offline peer. */\nexport interface X3DHInitFields {\n x3dhEK: string // sender's ephemeral public key (base64)\n x3dhSPK: string // recipient's signed prekey ID used\n x3dhIK: string // sender's identity public key (base64)\n /** Whether the sender's DH computation included a one-time prekey (dh4).\n * The receiver MUST honor this exactly — it decides whether to consume\n * one of its own OTP keys, and doing so when the sender didn't include\n * one derives a mismatched shared key (see x3dhReceiveFrom). Absent on\n * messages from a build predating this field: treated as `false`, which\n * is only correct if that sender also never used an OTP — a fresh E2E\n * session on both sides (the normal case) is unaffected either way. */\n x3dhOTP: boolean\n}\n\nexport function extractX3DHInit(content: MessageContent): X3DHInitFields | null {\n if (content.kind !== 'text' || !content.enc) return null\n const c = content as MessageContent & Partial<X3DHInitFields>\n if (!c.x3dhEK || !c.x3dhSPK || !c.x3dhIK) return null\n return { x3dhEK: c.x3dhEK, x3dhSPK: c.x3dhSPK, x3dhIK: c.x3dhIK, x3dhOTP: c.x3dhOTP ?? false }\n}\n\nexport { type X3DHBundle } from './crypto.js'\nexport { type UserId }\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 widget (`.ocw`). Extracted from renderer.ts\n// to keep the renderer focused on behaviour. Tokens come from the single\n// source of truth in theme-tokens.ts.\nimport { lightTokens, darkTokens } from './theme-tokens.js'\n\nexport const CSS = `\n.ocw { ${lightTokens('ocw')}\n position:relative;\n display:flex; flex-direction:column; height:100%; min-height:320px; background:var(--ocw-bg);\n font-family:var(--ocw-fb); color:var(--ocw-ink); overflow:hidden; }\n@media (prefers-color-scheme: dark) { .ocw:not([data-theme=\"light\"]) { ${darkTokens('ocw')} } }\n.ocw[data-theme=\"dark\"] { ${darkTokens('ocw')} }\n/* ── Responsive sizing ──────────────────────────────────────────────────────\n * Sizing is driven by the WIDGET'S OWN width (ResizeObserver toggles\n * .ocw-compact below 400px), not the viewport — so a widget embedded in a\n * narrow desktop sidebar sizes the same as one on a phone, and a tablet in\n * landscape keeps comfortable desktop sizing. A viewport query alone can't\n * see the container. Fullscreen (launcher on mobile) additionally gets\n * .ocw-fs from the launcher, which is the only case that should remove the\n * corner radius — an INLINE embed on a phone must NOT take over the page\n * (the old blanket min-height:100dvh rule did exactly that). */\n.ocw.ocw-fs { border-radius:0 !important; }\n.ocw-compact .ocw-bubble { font-size:15px; }\n.ocw-compact.ocw .ocw-input textarea { font-size:16px; } /* ≥16px prevents iOS zoom on focus */\n.ocw-compact .ocw-chip { padding:9px 14px; font-size:14px; }\n.ocw-compact .ocw-modal-card { width:90%; }\n.ocw-compact .ocw-row { max-width:94%; }\n.ocw-compact .ocw-sendbtn { min-width:44px; height:44px; }\n.ocw-compact .ocw-back { width:34px; height:34px; }\n.ocw-compact .ocw-quick button { padding:9px 15px; font-size:14px; }\n/* RTL support: when the host element has dir=rtl, flip layout direction */\n[dir=\"rtl\"] .ocw-row.mine { flex-direction:row; }\n[dir=\"rtl\"] .ocw-row.theirs { flex-direction:row-reverse; }\n[dir=\"rtl\"] .mine .ocw-bubble { border-bottom-right-radius:18px; border-bottom-left-radius:4px; }\n[dir=\"rtl\"] .theirs .ocw-bubble { border-bottom-left-radius:18px; border-bottom-right-radius:4px; }\n[dir=\"rtl\"] .ocw-input { flex-direction:row-reverse; }\n[dir=\"rtl\"] .mine .ocw-meta { text-align:left; }\n.ocw-head { display:flex; align-items:center; gap:10px; padding:12px 14px; background:var(--ocw-card); border-bottom:1px solid var(--ocw-line); }\n.ocw-back { flex:none; width:30px; height:30px; margin:-2px -2px -2px -4px; border:none; background:none; color:var(--ocw-ink); font-size:26px; line-height:1; cursor:pointer; border-radius:50%; display:flex; align-items:center; justify-content:center; }\n.ocw-back:hover { background:var(--ocw-bg); }\n.ocw-avatar { width:34px; height:34px; border-radius:50%; background:var(--ocw-tint); color:var(--ocw-accent); font-family:var(--ocw-fh); font-weight:600; display:flex; align-items:center; justify-content:center; font-size:13px; flex:none; }\n.ocw-head-main { flex:1; min-width:0; }\n.ocw-head-name { font-family:var(--ocw-fh); font-weight:600; font-size:15px; }\n.ocw-head-meta { color:var(--ocw-mut); font-size:12px; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }\n.ocw-head-status { font-size:10.5px; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }\n.ocw-head-status.online { color:#5cb37a; }\n.ocw-head-status.away { color:#c98b2e; }\n.ocw-msg-sender { font-size:10px; color:var(--ocw-mut); margin-bottom:2px; }\n.ocw-resolved-note { text-align:center; font-size:10.5px; color:var(--ocw-mut); margin:6px 0 12px; }\n.ocw-reopen { display:none; width:calc(100% - 32px); margin:0 16px 14px; height:40px; border:1.5px solid var(--ocw-accent); color:var(--ocw-accent); background:none; border-radius:20px; font:inherit; font-size:13.5px; font-weight:600; cursor:pointer; }\n.ocw-reopen:hover { background:var(--ocw-tint); }\n.ocw-badge { font-size:11px; font-weight:600; color:#2f8a52; background:#eafaf0; border-radius:20px; padding:5px 12px; }\n.ocw-e2e { font-size:11px; font-weight:700; color:var(--ocw-accent); background:var(--ocw-tint); border-radius:20px; padding:5px 12px; align-items:center; }\n.ocw-menu { color:var(--ocw-mut); width:30px; height:30px; border-radius:50%; border:1px solid var(--ocw-line); background:var(--ocw-card); cursor:pointer; }\n.ocw-chiprow { display:flex; gap:8px; padding:10px 12px; background:var(--ocw-card); border-bottom:1px solid var(--ocw-line); overflow-x:auto; }\n.ocw-chip { flex:none; display:flex; align-items:center; gap:6px; border:none; background:var(--ocw-tint); color:var(--ocw-accent); border-radius:999px; padding:7px 13px; font-size:12px; font-weight:600; cursor:pointer; white-space:nowrap; }\n.ocw-chip:hover { border-color:var(--ocw-accent); color:var(--ocw-accent); }\n.ocw-scroll { flex:1; min-height:0; overflow-y:auto; padding:16px 14px; display:flex; flex-direction:column; gap:10px; }\n.ocw-subject { background:var(--ocw-tint); border:none; border-radius:16px; padding:10px 12px; }\n.ocw-subject-title { font-family:var(--ocw-fh); font-weight:600; font-size:13px; margin-bottom:2px; }\n.ocw-subject-sub { color:var(--ocw-mut); font-size:10.5px; margin-bottom:6px; }\n.ocw-tags { display:flex; flex-wrap:wrap; gap:6px; }\n.ocw-tag { font-size:12px; color:#5b554e; background:#efeae3; border-radius:8px; padding:4px 10px; }\n.ocw-row { display:flex; align-items:flex-end; gap:8px; max-width:86%; }\n.ocw-row.mine { align-self:flex-end; flex-direction:row-reverse; }\n.ocw-row.theirs { align-self:flex-start; }\n.ocw-dot { width:26px; height:26px; border-radius:50%; background:var(--ocw-tint); color:var(--ocw-accent); font-size:12px; font-weight:700; display:flex; align-items:center; justify-content:center; flex:none; }\n.ocw-bubble { padding:10px 14px; border-radius:18px; font-size:13.5px; line-height:1.45; word-wrap:break-word; max-width:80%; }\n.theirs .ocw-bubble { background:var(--ocw-tint); border-bottom-left-radius:4px; }\n.mine .ocw-bubble { background:var(--ocw-accent2); color:#fff; border-bottom-right-radius:4px; }\n.ocw-sys { align-self:center; color:var(--ocw-mut); font-size:12.5px; font-style:italic; text-align:center; max-width:90%; }\n.ocw-bot .ocw-bubble { background:var(--ocw-tint); }\n.ocw-note .ocw-bubble { background:#fffbeb; border:1.5px dashed #f59e0b; color:#78350f; border-radius:12px !important; }\n.ocw-note .ocw-bubble::before { content:'🔒 Note — '; font-size:11px; font-weight:700; color:#b45309; display:block; margin-bottom:3px; letter-spacing:.3px; }\n.ocw-time { font-size:10.5px; color:var(--ocw-mut); margin-top:3px; }\n.mine .ocw-meta { text-align:right; }\n.ocw-tick { margin-left:4px; font-size:11px; color:var(--ocw-mut); }\n.ocw-tick.read { color:#3b82f6; }\n.ocw-tick.delivered { color:var(--ocw-mut); }\n.ocw-deleted { font-style:italic; color:var(--ocw-mut); }\n.ocw-edited { font-size:10px; color:var(--ocw-mut); margin-left:4px; }\n.ocw-react { font-size:12px; margin-top:3px; display:flex; flex-wrap:wrap; gap:3px; }\n.ocw-react-pill { display:inline-flex; align-items:center; gap:3px; border:1px solid var(--ocw-line); border-radius:999px; padding:2px 7px; background:var(--ocw-card); font-size:12px; cursor:pointer; }\n.ocw-react-pill:hover { border-color:var(--ocw-accent); }\n.ocw-react-pill.mine { border-color:var(--ocw-accent); background:#fff8f5; }\n.ocw-react-wrap { position:relative; }\n.ocw-react-wrap:not(:hover) .ocw-react-picker { display:none; }\n.ocw-react-picker { position:absolute; bottom:calc(100% + 4px); left:0; background:var(--ocw-card); border:1px solid var(--ocw-line); border-radius:14px; padding:6px 8px; box-shadow:0 4px 16px rgba(0,0,0,.12); display:flex; gap:4px; z-index:10; white-space:nowrap; }\n.ocw-react-picker button { background:none; border:none; font-size:16px; cursor:pointer; padding:2px; border-radius:6px; }\n.ocw-react-picker button:hover { background:var(--ocw-bg); }\n.ocw-react-btn { background:none; border:1px solid var(--ocw-line); border-radius:999px; padding:2px 7px; font-size:12px; cursor:pointer; color:var(--ocw-mut); }\n.ocw-react-btn:hover { border-color:var(--ocw-accent); color:var(--ocw-accent); }\n.ocw-msg-menu { position:absolute; top:0; right:0; display:none; gap:3px; }\n.ocw-row.mine:hover .ocw-msg-menu { display:flex; }\n.ocw-row.theirs:hover .ocw-msg-menu { display:flex; left:0; right:auto; }\n.ocw-msg-menu button { background:var(--ocw-card); border:1px solid var(--ocw-line); border-radius:6px; font-size:11px; padding:2px 6px; cursor:pointer; color:var(--ocw-mut); }\n.ocw-msg-menu button:hover { border-color:var(--ocw-accent); color:var(--ocw-accent); }\n.ocw-msg-menu button.del:hover { border-color:#e74c3c; color:#e74c3c; }\n.ocw-bubble-wrap { position:relative; }\n.ocw-seen { font-size:10.5px; color:var(--ocw-mut); }\n.ocw-appt { background:#f0f7ff; border:1px solid #c7deff; border-radius:12px; padding:12px 14px; max-width:260px; }\n.ocw-appt-title { font-weight:700; font-size:14px; margin-bottom:4px; }\n.ocw-appt-time { font-size:12px; color:#1d4ed8; margin-bottom:4px; }\n.ocw-appt-loc { font-size:12px; color:var(--ocw-mut); margin-bottom:4px; }\n.ocw-appt-desc { font-size:12px; color:var(--ocw-mut); margin-bottom:10px; white-space:pre-wrap; }\n.ocw-appt-links { display:flex; flex-direction:column; gap:6px; }\n.ocw-appt-btn { display:block; text-align:center; padding:8px 12px; border-radius:8px; font-size:13px; font-weight:600; text-decoration:none; background:var(--ocw-accent); color:#fff; }\n.ocw-appt-btn-sec { background:var(--ocw-card); color:var(--ocw-accent); border:1px solid var(--ocw-accent); }\n.ocw-conn-status { font-size:10px; color:var(--ocw-mut); margin-left:4px; }\n.ocw-conn-status.warn { color:#e67e22; }\n.ocw-conn-status.err { color:#c0392b; font-weight:600; }\n.ocw-load-more { display:block; width:100%; background:none; border:1px solid var(--ocw-line); border-radius:10px; padding:6px 0; font-size:12px; color:var(--ocw-mut); cursor:pointer; margin-bottom:8px; }\n.ocw-load-more:hover { border-color:var(--ocw-accent); color:var(--ocw-accent); }\n.ocw-away { margin:0 14px 8px; padding:9px 12px; background:#fff8e6; border:1px solid #f0e2bd; border-radius:10px; font-size:12px; color:#7a5c17; display:flex; gap:7px; align-items:flex-start; line-height:1.45; }\n.ocw button:focus-visible, .ocw textarea:focus-visible, .ocw a:focus-visible, .ocw [tabindex]:focus-visible { outline:2px solid var(--ocw-accent); outline-offset:2px; border-radius:8px; }\n.ocw-sendbtn:active { transform:scale(.92); }\n.ocw-quick button:active, .ocw-chip:active { transform:scale(.97); }\n@media (prefers-color-scheme: dark) { .ocw:not([data-theme=\"light\"]) .ocw-away { background:#3a3018; border-color:#5a4a1f; color:#e8d9a8; } .ocw:not([data-theme=\"light\"]) .ocw-note .ocw-bubble { background:#332b12; border-color:#7a5c17; color:#f0e2bd; } .ocw:not([data-theme=\"light\"]) .ocw-note .ocw-bubble::before { color:#e0c060; } }\n.ocw[data-theme=\"dark\"] .ocw-away { background:#3a3018; border-color:#5a4a1f; color:#e8d9a8; }\n.ocw[data-theme=\"dark\"] .ocw-note .ocw-bubble { background:#332b12; border-color:#7a5c17; color:#f0e2bd; }\n.ocw[data-theme=\"dark\"] .ocw-note .ocw-bubble::before { color:#e0c060; }\n.ocw-away-icon { flex:none; }\n/* Shared form styles (used by the pre-chat panel; named for the retired offline form). */\n.ocw-offline-form { display:flex; flex-direction:column; gap:8px; text-align:left; }\n.ocw-offline-input { border:none; background:var(--ocw-tint); border-radius:14px; padding:10px 12px; font-size:13px; font-family:inherit; color:var(--ocw-ink); }\n.ocw-offline-input:focus { outline:none; box-shadow:inset 0 0 0 1.5px var(--ocw-accent); }\n.ocw-offline-submit { background:var(--ocw-accent); color:var(--ocw-onaccent); border:none; border-radius:20px; padding:11px; font-family:var(--ocw-fh); font-size:13.5px; font-weight:600; cursor:pointer; box-shadow:var(--ocw-shadow); }\n.ocw-prechat { margin:16px; padding:0; background:none; border:none; }\n.ocw-prechat-title { font-family:var(--ocw-fh); font-weight:600; font-size:20px; margin-bottom:10px; }\n.ocw-prechat select { border:none; border-radius:14px; padding:10px 12px; font:inherit; font-size:13px; background:var(--ocw-tint); color:var(--ocw-ink); }\n.ocw-prechat-cb { display:flex; align-items:center; gap:8px; font-size:13px; color:var(--ocw-ink); }\n.ocw-deflect { margin:0 14px 8px; display:flex; flex-direction:column; gap:6px; }\n.ocw-deflect-card { text-align:left; background:var(--ocw-card); border:1px solid var(--ocw-line); border-radius:12px; padding:10px 12px; font:inherit; font-size:13px; cursor:pointer; }\n.ocw-deflect-card:hover { border-color:var(--ocw-accent); }\n.ocw-deflect-q { font-weight:600; margin-bottom:2px; }\n.ocw-deflect-a { color:var(--ocw-mut); font-size:12.5px; display:none; white-space:pre-wrap; }\n.ocw-deflect-card.open .ocw-deflect-a { display:block; }\n.ocw-deflect-hint { font-size:11.5px; color:var(--ocw-mut); text-align:center; }\n.ocw-csat-title { font-size:13px; font-weight:600; margin-bottom:8px; }\n.ocw-csat-stars { display:flex; gap:6px; }\n.ocw-csat-star { background:none; border:none; font-size:22px; cursor:pointer; padding:2px; opacity:.4; transition:opacity .15s; }\n.ocw-csat-star:hover, .ocw-csat-star.lit { opacity:1; }\n.ocw-csat-done { font-size:12px; color:var(--ocw-mut); margin-top:6px; }\n\n.ocw-typing { min-height:22px; padding:0 16px 4px; display:flex; align-items:center; }\n.ocw-typing-bubble { display:none; align-items:center; gap:3px; background:var(--ocw-card); border:1px solid var(--ocw-line); border-radius:14px; border-bottom-left-radius:4px; padding:7px 12px; }\n.ocw-typing.active .ocw-typing-bubble { display:flex; }\n.ocw-typing-dot { width:6px; height:6px; border-radius:50%; background:var(--ocw-mut); animation:ocw-bounce 1.2s infinite ease-in-out; }\n.ocw-typing-dot:nth-child(2) { animation-delay:.2s; }\n.ocw-typing-dot:nth-child(3) { animation-delay:.4s; }\n@keyframes ocw-bounce { 0%,60%,100%{transform:translateY(0)} 30%{transform:translateY(-5px)} }\n.ocw-quick { display:flex; gap:8px; padding:8px 12px 6px; overflow-x:auto; scrollbar-width:none; flex-shrink:0; }\n.ocw-quick::-webkit-scrollbar { display:none; }\n.ocw-quick button { flex:none; border:none; background:var(--ocw-tint); border-radius:999px; padding:7px 14px; font-size:12px; font-weight:600; cursor:pointer; color:var(--ocw-accent); white-space:nowrap; transition:background .12s,color .12s; }\n.ocw-quick button:hover { background:var(--ocw-accent); color:var(--ocw-onaccent); }\n.ocw-form-host:empty { display:none; }\n.ocw-form { margin:6px 12px 0; padding:12px; background:var(--ocw-card); border:1px solid var(--ocw-line); border-radius:14px; }\n.ocw-form-title { font-weight:700; font-size:14px; margin-bottom:8px; }\n.ocw-form-row { display:flex; flex-direction:column; gap:3px; margin-bottom:8px; }\n.ocw-form-lbl { font-size:12px; color:var(--ocw-mut); }\n.ocw-form-input { border:1px solid var(--ocw-line); border-radius:9px; padding:9px 11px; font:inherit; font-size:14px; outline:none; }\n.ocw-form-input:focus { border-color:var(--ocw-accent); }\n.ocw-form-actions { display:flex; justify-content:flex-end; gap:8px; margin-top:4px; }\n.ocw-form-cancel { background:none; border:none; color:var(--ocw-mut); font-size:13px; cursor:pointer; padding:8px 10px; }\n.ocw-form-submit { background:var(--ocw-accent); color:#fff; border:none; border-radius:999px; padding:8px 18px; font-size:13px; font-weight:600; cursor:pointer; }\n.ocw-modal { position:absolute; inset:0; background:rgba(20,18,16,.42); display:flex; align-items:center; justify-content:center; z-index:50; }\n.ocw-modal-card { background:var(--ocw-card); border-radius:16px; padding:20px; width:78%; max-width:300px; box-shadow:0 14px 44px rgba(0,0,0,.22); }\n.ocw-modal-title { font-weight:700; font-size:16px; margin-bottom:6px; }\n.ocw-modal-body { color:var(--ocw-mut); font-size:14px; margin-bottom:16px; }\n.ocw-modal-actions { display:flex; justify-content:flex-end; gap:8px; }\n.ocw-modal-cancel { background:none; border:none; color:var(--ocw-mut); font-size:14px; cursor:pointer; padding:9px 12px; }\n.ocw-modal-ok { background:var(--ocw-accent); color:#fff; border:none; border-radius:999px; padding:9px 20px; font-size:14px; font-weight:600; cursor:pointer; }\n.ocw-input { display:flex; align-items:center; gap:10px; padding:12px; }\n.ocw-footer { text-align:center; font-size:11px; color:var(--ocw-mut); padding:6px 0 8px; }\n.ocw-footer a { color:var(--ocw-mut); text-decoration:none; font-weight:600; }\n.ocw-footer a:hover { color:var(--ocw-accent); }\n.ocw-attach { background:none;border:none;cursor:pointer;font-size:18px;padding:4px 6px;opacity:.6;flex-none; }\n.ocw-attach:hover { opacity:1; }\n.ocw-input textarea { flex:1; min-width:0; resize:none; border:none; border-radius:20px; padding:11px 16px; font:inherit; font-size:14px; line-height:1.4; background:var(--ocw-tint); outline:none; max-height:120px; overflow-y:auto; }\n.ocw-input textarea:focus { box-shadow:inset 0 0 0 1.5px var(--ocw-accent); }\n/* Send button auto-sizes to its label: the default is a fixed circle around an\n * inline SVG; a TEXT label (i18n.send: \"Send\", \"보내기\", \"Enviar\"…) switches to\n * .ocw-sendbtn-label — a pill whose width follows the text. A fixed 42px\n * circle with 18px type overflowed the moment anyone localized the label. */\n.ocw-sendbtn { min-width:38px; height:38px; border-radius:999px; border:none; background:var(--ocw-accent2); color:#fff; font:inherit; font-size:14px; font-weight:600; cursor:pointer; flex:none; display:flex; align-items:center; justify-content:center; padding:0; transition:opacity .15s, transform .1s; }\n.ocw-sendbtn-label { padding:0 16px; white-space:nowrap; }\n.ocw-sendbtn svg { width:19px; height:19px; display:block; }\n.ocw-sendbtn:not(:disabled):hover { transform:scale(1.05); }\n.ocw-sendbtn:not(:disabled):active { transform:scale(.96); }\n.ocw-sendbtn:disabled { opacity:.5; cursor:default; }\n.ocw-sendbtn:focus-visible, .ocw-back:focus-visible, .ocw-chip:focus-visible { outline:2px solid var(--ocw-accent); outline-offset:2px; }\n\n.ocw-translate-btn { position:absolute; bottom:2px; right:-26px; background:var(--ocw-card); border:1px solid var(--ocw-line); border-radius:50%; width:22px; height:22px; font-size:11px; cursor:pointer; color:var(--ocw-mut); display:flex; align-items:center; justify-content:center; opacity:0; transition:opacity .15s; padding:0; }\n.ocw-row.theirs .ocw-translate-btn { right:auto; left:-26px; }\n.ocw-bubble-wrap:hover .ocw-translate-btn { opacity:1; }\n.ocw-translated-tag { font-size:10px; color:var(--ocw-mut); margin-top:2px; }\n`\n","import type { ManifestAction, MessageContent } from './protocol/index.js'\nimport type { ChatStore, RenderMessage } from './store.js'\nimport { CSS } from './renderer.styles.js'\n\nexport interface WidgetConfig {\n subject?: { title?: string; subtitle?: string; tags?: string[]; status?: string; ownerLabel?: string }\n quickReplies?: string[]\n accent?: string\n /** Secondary accent — the guest's OWN bubble + send button. Defaults to the\n * design blue; if omitted while `accent` is set, follows `accent` so a single\n * accent override re-themes cohesively. */\n accent2?: string\n /** Colour scheme: auto (follow OS, default), or force light/dark. */\n theme?: 'auto' | 'light' | 'dark'\n /** Load the brand webfonts (Baloo 2 + Nunito). Default true; set false for\n * strict-CSP / privacy-sensitive hosts (falls back to the system stack). */\n webfont?: boolean\n /** Identified user info — shown as the guest avatar/name in the widget header. */\n userInfo?: { name?: string; avatar?: string }\n /** i18n string overrides */\n i18n?: { placeholder?: string; send?: string; offline?: string; poweredBy?: string; online?: string; away?: string; aiAssistant?: string; resolved?: string; reopen?: string }\n\n}\n\nexport interface RendererHandlers {\n onSend(text: string): void\n onAttach?(file: File): void\n onInvoke(actionId: string, inputs?: Record<string, unknown>): void\n onTyping(isTyping: boolean, preview?: string): void\n onReadUpTo(seq: number): void\n onReact?(messageId: string, emoji: string, remove: boolean): void\n onCsat?(score: number): void\n onLoadMore?(): void\n onEdit?(messageId: string, newText: string): void\n onDelete?(messageId: string): void\n /** Pre-chat qualification submitted (values keyed by field; topic/callback included). */\n onPreChat?(values: { name?: string; email?: string; phone?: string; topic?: string; callback?: boolean }): void\n /** KB deflection: the guest is typing their FIRST message — look up articles. */\n onDeflectQuery?(q: string): void\n /** Translate a message's text for display. Return null if unavailable —\n * the renderer shows a brief \"unavailable\" hint and leaves the original. */\n onTranslate?(text: string): Promise<string | null>\n /** Stack navigation (chat-app surfaces): when set, the header shows a back\n * chevron on the left that calls this — tap a conversation → chatroom →\n * back → list, like a native messaging app. Omit for a standalone widget,\n * which has nothing to go \"back\" to. */\n onBack?(): void\n}\n\nconst STYLE_ID = 'objectchat-widget-styles'\nconst REACTION_EMOJIS = ['👍', '❤️', '😂', '😮', '😢', '🙏']\n/** Width below which the widget switches to compact (touch-friendly) sizing. */\nconst COMPACT_BREAKPOINT = 400\n// Inline, dependency-free send glyph — `currentColor` follows the button text\n// colour; no emoji/font dependency so it renders identically across platforms.\nconst SEND_ICON_SVG =\n '<svg viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\" aria-hidden=\"true\">' +\n '<path d=\"M22 2 11 13M22 2l-7 20-4-9-9-4 20-7z\" stroke=\"currentColor\" stroke-width=\"2\" ' +\n 'stroke-linecap=\"round\" stroke-linejoin=\"round\"/></svg>'\n// CSS lives in renderer.styles.ts (single source of truth for .ocw styling).\n\nfunction injectStyles(): void {\n if (typeof document === 'undefined' || document.getElementById(STYLE_ID)) return\n const s = document.createElement('style'); s.id = STYLE_ID; s.textContent = CSS; document.head.appendChild(s)\n}\n\n/** Load the brand webfonts (Baloo 2 + Nunito) once. The design's identity is its\n * rounded type — without this the widget falls back to system fonts and looks\n * generic. Injected as a <link> so a strict host CSP that blocks it degrades\n * gracefully to the system stack. Opt out with `webfont: false`. */\nconst FONT_ID = 'ocw-webfont'\nfunction injectFonts(): void {\n if (typeof document === 'undefined' || document.getElementById(FONT_ID)) return\n const l = document.createElement('link')\n l.id = FONT_ID; 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.appendChild(l)\n}\n\nfunction el<K extends keyof HTMLElementTagNameMap>(tag: K, cls?: string, text?: string): HTMLElementTagNameMap[K] {\n const n = document.createElement(tag); if (cls) n.className = cls; if (text !== undefined) n.textContent = text; return n\n}\nfunction fmtTime(ts: number): string {\n try { return new Date(ts).toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' }) } catch { return '' }\n}\nfunction contentText(c: MessageContent): string {\n switch (c.kind) {\n case 'text': return c.text\n case 'system': return typeof c.data?.['message'] === 'string' ? String(c.data['message']) : c.event\n case 'card': return [c.title, c.body].filter(Boolean).join(' — ')\n case 'attachment': return c.name ?? c.url\n case 'form': return c.prompt\n case 'appointment': return `📅 ${c.title} — ${new Date(c.startIso).toLocaleString()}`\n }\n}\n\n/** Renders a ChatStore into a host element in the Image-1 layout: header →\n * subject card → action chips → chat → quick replies → input. Self-injects its\n * stylesheet so it looks right wherever it mounts. Accent comes from the\n * dashboard-authored profile theme (via the manifest), falling back to config. */\nexport class Renderer {\n private readonly scroll: HTMLElement\n private readonly chips: HTMLElement\n private readonly typing: HTMLElement\n private readonly quick: HTMLElement\n private readonly formHost: HTMLElement\n private readonly csatPanel: HTMLElement\n private readonly awayNotice: HTMLElement\n private readonly headStatus: HTMLElement\n private readonly reopenBtn: HTMLButtonElement\n private readonly preChatPanel: HTMLElement\n private readonly deflectPanel: HTMLElement\n private preChatBuilt = false\n private preChatDone = false\n private readonly footer: HTMLElement\n private readonly input: HTMLTextAreaElement\n private readonly subjectCard: HTMLElement\n private readonly e2eBadge: HTMLElement\n private readonly statusBadge: HTMLElement\n private readonly headerName: HTMLElement\n private readonly connStatus: HTMLElement\n private typingTimer: ReturnType<typeof setTimeout> | null = null\n private csatSubmitted = false\n private readonly sendBtn: HTMLButtonElement\n /** Container-driven responsive sizing — toggles .ocw-compact (see CSS note). */\n private compactObserver: ResizeObserver | null = null\n private storeRef: ChatStore | null = null\n private readonly cfgAccent2: string | undefined\n private scrollCleanup: (() => void) | null = null\n\n /** Returns the scroll container so history.ts can attach scroll listeners. */\n getScrollEl(): HTMLElement | null { return this.scroll }\n\n /** Registers a cleanup fn removed on destroy() to prevent listener leaks. */\n setScrollCleanup(fn: () => void): void {\n this.scrollCleanup?.()\n this.scrollCleanup = fn\n }\n\n // ── Live translation ──────────────────────────────────────────────────-\n private readonly translationCache = new Map<string, string>()\n private readonly showingTranslation = new Set<string>()\n\n\n /** Last seq the guest has seen per conversationId — used to compute unread badges. */\n\n\n constructor(\n private readonly root: HTMLElement,\n private readonly me: string,\n private readonly h: RendererHandlers,\n private readonly cfg: WidgetConfig = {},\n ) {\n injectStyles()\n if (cfg.webfont !== false) injectFonts()\n // Clear any previous widget content on this element before building.\n // This is the last line of defence against double-mounts: even if mount()\n // is called twice on the same element (React StrictMode, HMR, caller bug),\n // the second Renderer wipes the first one's DOM so only one UI is visible.\n root.replaceChildren()\n root.classList.add('ocw')\n if (cfg.accent) root.style.setProperty('--ocw-accent', cfg.accent)\n // Two-accent model: explicit accent2 wins; else if only accent is set, accent2\n // follows it (single-token retheme); else the CSS defaults (indigo + blue) hold.\n const accent2 = cfg.accent2 ?? cfg.accent\n if (accent2) root.style.setProperty('--ocw-accent2', accent2)\n this.cfgAccent2 = cfg.accent2\n if (cfg.theme && cfg.theme !== 'auto') root.dataset.theme = cfg.theme\n\n // Header\n const head = el('div', 'ocw-head')\n // Stack navigation: a back chevron returns to the conversation list. Only\n // shown when the host wired onBack (chat-app surfaces) — a standalone\n // support widget has no list to go back to.\n if (this.h.onBack) {\n const back = el('button', 'ocw-back', '‹') as HTMLButtonElement\n back.type = 'button'\n back.setAttribute('aria-label', 'Back')\n back.addEventListener('click', () => this.h.onBack!())\n head.append(back)\n }\n const avatarEl = el('div', 'ocw-avatar')\n if (cfg.userInfo?.avatar) {\n const img = document.createElement('img')\n img.src = cfg.userInfo.avatar; img.alt = cfg.userInfo.name ?? 'You'\n img.style.cssText = 'width:100%;height:100%;border-radius:50%;object-fit:cover'\n avatarEl.append(img)\n } else {\n avatarEl.textContent = cfg.userInfo?.name ? cfg.userInfo.name[0]!.toUpperCase() : '🧑'\n }\n head.append(avatarEl)\n const hm = el('div', 'ocw-head-main')\n this.headerName = el('div', 'ocw-head-name', cfg.subject?.ownerLabel ?? cfg.subject?.title ?? '')\n hm.append(this.headerName)\n this.headStatus = el('div', 'ocw-head-status'); this.headStatus.style.display = 'none'\n hm.append(this.headStatus)\n if (cfg.subject?.subtitle) hm.append(el('div', 'ocw-head-meta', cfg.subject.subtitle))\n head.append(hm)\n this.statusBadge = el('span', 'ocw-badge', cfg.subject?.status ?? '')\n if (!cfg.subject?.status) this.statusBadge.style.display = 'none'\n head.append(this.statusBadge)\n this.e2eBadge = el('span', 'ocw-e2e', '🔒 E2E'); this.e2eBadge.style.display = 'none'; head.append(this.e2eBadge)\n this.connStatus = el('span', 'ocw-conn-status'); this.connStatus.style.display = 'none'; head.append(this.connStatus)\n\n head.append(el('button', 'ocw-menu', '⋯'))\n\n // Action chips (filled in render)\n this.chips = el('div', 'ocw-chiprow')\n\n // Scroll area with optional subject card + messages\n this.scroll = el('div', 'ocw-scroll')\n this.subjectCard = el('div', 'ocw-subject')\n this.typing = el('div', 'ocw-typing')\n const typingBubble = el('div', 'ocw-typing-bubble')\n typingBubble.append(el('div', 'ocw-typing-dot'), el('div', 'ocw-typing-dot'), el('div', 'ocw-typing-dot'))\n this.typing.append(el('div', 'ocw-dot', '🧑'), typingBubble)\n this.quick = el('div', 'ocw-quick')\n for (const q of cfg.quickReplies ?? []) {\n const b = el('button', undefined, q)\n b.addEventListener('click', () => {\n this.h.onSend(q)\n // Hide quick replies immediately after one is tapped\n this.quick.style.display = 'none'\n })\n this.quick.append(b)\n }\n\n // Input\n this.formHost = el('div', 'ocw-form-host')\n this.csatPanel = el('div', 'ocw-csat'); this.csatPanel.style.display = 'none'\n // Away notice (outside office hours). INFORMATIONAL only — it never blocks\n // the composer: the message is delivered either way and an agent replies\n // when they're back. (It used to be a card that replaced the composer with\n // a name/email/message form; guests could not simply chat.)\n this.awayNotice = el('div', 'ocw-away'); this.awayNotice.style.display = 'none'\n this.preChatPanel = el('div', 'ocw-prechat'); this.preChatPanel.style.display = 'none'\n this.deflectPanel = el('div', 'ocw-deflect'); this.deflectPanel.style.display = 'none'\n this.input = el('textarea', undefined); this.input.rows = 1\n // i18n.placeholder was documented in MountOptions but never actually\n // applied — the composer always said \"Message…\" regardless.\n this.input.placeholder = cfg.i18n?.placeholder ?? 'Message…'\n const sendBtn = el('button', 'ocw-sendbtn') as HTMLButtonElement\n sendBtn.type = 'button'\n const sendLabel = cfg.i18n?.send\n if (sendLabel) {\n // Text label → auto-width pill (see the .ocw-sendbtn-label CSS note).\n sendBtn.textContent = sendLabel\n sendBtn.classList.add('ocw-sendbtn-label')\n sendBtn.setAttribute('aria-label', sendLabel)\n } else {\n // Default: inline SVG paper plane — renders identically on every\n // platform (the old '➤' text glyph varied per OS font).\n sendBtn.innerHTML = SEND_ICON_SVG\n sendBtn.setAttribute('aria-label', 'Send message')\n }\n // The :disabled style existed but nothing ever set the state — send is\n // inactive until there's something to send, like every mainstream chat UI.\n sendBtn.disabled = true\n this.sendBtn = sendBtn\n sendBtn.addEventListener('click', () => this.flushSend())\n this.input.addEventListener('input', () => {\n this.sendBtn.disabled = this.input.value.trim().length === 0\n this.autoGrowInput()\n // Deflection fires only for the FIRST message of an empty conversation —\n // once a thread exists, suggestions would just be noise.\n if (this.storeRef && !this.storeRef.messages().some(m => m.senderRole === 'guest')) this.h.onDeflectQuery?.(this.input.value)\n else this.hideDeflection()\n })\n this.input.addEventListener('keydown', (e) => {\n // Guard against IME composition (Korean/Japanese/Chinese input): while\n // the user is selecting a candidate from the IME's suggestion list,\n // pressing Enter to CONFIRM the candidate also fires a keydown with\n // key === 'Enter'. Without this check, that confirmation keystroke was\n // being treated as \"send the message\" — firing early with a partial\n // composition, and then firing again on the real Enter press with\n // whatever text was left, producing two bubbles for one message\n // (e.g. typing \"음식\" sends \"음식\" then \"식\").\n // e.isComposing covers most browsers; keyCode 229 is the long-standing\n // fallback for browsers/IMEs that don't set isComposing reliably.\n if (e.isComposing || e.keyCode === 229) return\n if (e.key === 'Enter' && !e.shiftKey) { e.preventDefault(); this.flushSend() } else this.signalTyping()\n })\n\n const attachBtn = el('button', 'ocw-attach', '📎'); attachBtn.title = 'Attach image or file'\n const fileInput = document.createElement('input'); fileInput.type = 'file'\n fileInput.accept = 'image/*,.pdf,.txt,.doc,.docx'; fileInput.style.display = 'none'\n attachBtn.addEventListener('click', () => fileInput.click())\n fileInput.addEventListener('change', () => { if (fileInput.files?.[0] && this.h.onAttach) this.h.onAttach(fileInput.files[0]); fileInput.value = '' })\n\n const inputRow = el('div', 'ocw-input'); inputRow.append(attachBtn, fileInput, this.input, sendBtn)\n\n const footer = el('div', 'ocw-footer')\n // i18n.poweredBy: if the caller provides it, treat as plain text — no innerHTML.\n // Only our own hardcoded default renders the anchor as HTML.\n if (cfg.i18n?.poweredBy !== undefined) {\n footer.textContent = cfg.i18n.poweredBy\n } else {\n footer.innerHTML = 'Powered by <a href=\"https://relay.paramms.com\" target=\"_blank\" rel=\"noopener\">Relay</a>'\n }\n this.footer = footer\n\n this.reopenBtn = el('button', 'ocw-reopen', this.cfg.i18n?.reopen ?? 'Reopen conversation') as HTMLButtonElement\n this.reopenBtn.type = 'button'\n this.reopenBtn.addEventListener('click', () => {\n this.reopenBtn.style.display = 'none'\n const ta = this.root.querySelector('.ocw-input textarea') as HTMLTextAreaElement | null\n ta?.focus()\n })\n root.append(head, this.chips, this.scroll, this.typing, this.quick, this.formHost, this.csatPanel, this.preChatPanel, this.deflectPanel, this.awayNotice, inputRow, this.reopenBtn, this.footer)\n\n // Container-driven responsive sizing: compact below COMPACT_BREAKPOINT of\n // the widget's OWN width. Covers phones AND narrow desktop embeds — a\n // viewport media query can't see the container. Guarded: jsdom/tests and\n // very old runtimes have no ResizeObserver; they keep desktop sizing.\n const applyCompact = (w: number): void => { root.classList.toggle('ocw-compact', w > 0 && w < COMPACT_BREAKPOINT) }\n applyCompact(root.clientWidth)\n if (typeof ResizeObserver !== 'undefined') {\n this.compactObserver = new ResizeObserver((entries) => {\n const w = entries[0]?.contentRect.width ?? root.clientWidth\n applyCompact(w)\n })\n this.compactObserver.observe(root)\n }\n }\n\n /** Call when the widget is unmounted. Disconnects scroll listeners and clears timers. */\n destroy(): void {\n this.scrollCleanup?.()\n this.scrollCleanup = null\n if (this.typingTimer) { clearTimeout(this.typingTimer); this.typingTimer = null }\n this.compactObserver?.disconnect()\n this.compactObserver = null\n }\n\n\n private flushSend(): void {\n this.hideDeflection()\n const text = this.input.value.trim()\n if (!text) return\n this.input.value = ''\n this.sendBtn.disabled = true\n this.autoGrowInput() // collapse back to one row\n this.h.onTyping(false)\n this.h.onSend(text)\n }\n\n /** Grow the composer with its content (up to the CSS max-height), collapse\n * when cleared. scrollHeight is 0 in non-layout environments (jsdom) —\n * skip there so tests and SSR-ish mounts are unaffected. */\n private autoGrowInput(): void {\n this.input.style.height = 'auto'\n const sh = this.input.scrollHeight\n if (sh > 0) this.input.style.height = `${Math.min(sh, 120)}px`\n else this.input.style.removeProperty('height')\n }\n private signalTyping(): void {\n const preview = this.input.value.trim().slice(0, 100) || undefined\n this.h.onTyping(true, preview)\n if (this.typingTimer) clearTimeout(this.typingTimer)\n this.typingTimer = setTimeout(() => this.h.onTyping(false), 2000)\n }\n\n render(store: ChatStore): void {\n this.storeRef = store\n if (store.accent) {\n this.root.style.setProperty('--ocw-accent', store.accent)\n this.root.style.setProperty('--ocw-accent2', this.cfgAccent2 ?? store.accent)\n }\n this.e2eBadge.style.display = store.e2e ? 'inline-flex' : 'none'\n this.buildSubjectCard(store)\n // Header: when a subject is attached, show ownerLabel (\"Seller\", \"Host\")\n // or nothing — the subject card below carries the identity.\n // Without a subject, the header is already set to cfg.subject?.ownerLabel\n // or \"Chat\" from the constructor — don't overwrite it with the domain name\n // which would duplicate the subject card title or clutter a plain chat.\n if (store.subject) {\n const ownerLabel = this.cfg.subject?.ownerLabel\n if (ownerLabel) this.headerName.textContent = ownerLabel\n // else leave constructor default (\"Chat\")\n }\n // Without a subject: leave header as-is (set once in constructor)\n\n // Quick replies are a first-touch affordance (\"Is this still available?\").\n // They belong only on an empty conversation — once there's any message,\n // hide them, and keep them hidden on every re-render (returning to the\n // widget, reload, back-nav). Without this they reappear each mount even\n // though the conversation is already underway.\n this.quick.style.display = store.messages().length === 0 ? 'flex' : 'none'\n\n // Action chips from the manifest (filtered by state in the store)\n this.chips.replaceChildren()\n const actions = store.visibleActions()\n this.chips.style.display = actions.length ? 'flex' : 'none'\n for (const a of actions) this.chips.append(this.chipEl(a))\n\n // Messages\n // Preserve scroll anchor when history is prepended: capture height before\n // replaceChildren so we can restore relative position after.\n const prevScrollHeight = this.scroll.scrollHeight\n const prevScrollTop = this.scroll.scrollTop\n\n this.scroll.replaceChildren()\n if (this.subjectCard.childNodes.length) this.scroll.append(this.subjectCard)\n if (store.hasMoreHistory) {\n // Sentinel at top — scroll to here triggers load-more via the scroll\n // listener set up by restoreHistory. Shows a subtle loading indicator\n // so the user knows older messages are available.\n const sentinel = el('div', 'ocw-load-more')\n sentinel.textContent = '↑ Loading earlier messages…'\n sentinel.style.pointerEvents = 'none'\n this.scroll.append(sentinel)\n }\n let maxOther = 0\n let prevSender: string | null = null\n for (const m of store.messages()) {\n const showLabel = m.senderRole !== 'system' && m.senderId !== this.me && !m.internal && m.senderId !== prevSender\n this.scroll.append(this.messageEl(m, store, showLabel))\n if (m.senderRole !== 'system') prevSender = m.senderId\n if (m.senderId !== this.me && m.seq > maxOther) maxOther = m.seq\n }\n // Auto-scroll to bottom only for new messages; restore anchor when history was prepended.\n if (prevScrollTop > 20) {\n this.scroll.scrollTop = this.scroll.scrollHeight - prevScrollHeight + prevScrollTop\n } else {\n this.scroll.scrollTop = this.scroll.scrollHeight\n }\n if (maxOther > 0) this.h.onReadUpTo(maxOther)\n\n const typingNames = [...store.typing]\n this.typing.classList.toggle('active', typingNames.length > 0)\n // Bubble is always present in DOM (hidden via CSS); just update label\n const bubble = this.typing.querySelector('.ocw-typing-bubble')\n if (bubble) bubble.setAttribute('aria-label', typingNames.length ? 'typing' : '')\n this.footer.style.display = store.whiteLabel ? 'none' : 'block'\n\n // Offline mode: show form instead of chat input\n // Pre-chat qualification (dashboard-configured, arrives in the manifest):\n // shown before the FIRST message when enabled — 'offline'-scoped configs\n // replace the default leave-a-message form; 'always' configs gate the\n // composer while the team is online too. Never re-shown once completed\n // or once the conversation has any history.\n // \"Before the first message\" means the GUEST hasn't spoken — a chatroom\n // welcomeMessage is a real stored system message, so counting ALL\n // messages suppressed pre-chat (and deflection) on exactly the chatrooms\n // most likely to configure them.\n const guestHasSpoken = store.messages().some(m => m.senderRole === 'guest')\n const preChatWanted = !!store.preChat?.enabled && !this.preChatDone && !guestHasSpoken &&\n (store.preChat!.showWhen !== 'offline' || store.offline)\n if (preChatWanted) {\n if (!this.preChatBuilt) this.buildPreChatPanel(store.preChat!)\n this.preChatPanel.style.display = 'block'\n this.awayNotice.style.display = 'none'\n ;(this.root.querySelector('.ocw-input') as HTMLElement | null)?.style.setProperty('display', 'none')\n } else {\n this.preChatPanel.style.display = 'none'\n // Being outside office hours only changes EXPECTATIONS, never capability:\n // say we're away, keep the composer, deliver the message, reply later.\n if (store.offline) {\n if (!this.awayNotice.firstChild) {\n this.awayNotice.append(el('span', 'ocw-away-icon', '🌙'), el('span', '', ''))\n }\n const copy = this.awayNotice.lastChild as HTMLElement\n copy.textContent = store.offlineMessage\n || this.cfg.i18n?.offline\n || \"We're away right now — send your message and we'll reply as soon as we're back.\"\n this.awayNotice.style.display = 'flex'\n } else {\n this.awayNotice.style.display = 'none'\n }\n ;(this.root.querySelector('.ocw-input') as HTMLElement | null)?.style.removeProperty('display')\n }\n\n // CSAT: show star-rating panel when conversation reaches a terminal state\n // and the user hasn't yet rated. Terminal states are heuristic: 'resolved',\n // 'closed', 'sold', 'issued', 'checked_out'. The panel self-dismisses on submit.\n const terminalStates = ['resolved', 'closed', 'sold', 'issued', 'checked_out']\n if (this.h.onCsat && !this.csatSubmitted && terminalStates.includes(store.state) && store.messages().length > 0) {\n if (this.csatPanel.style.display === 'none') this.buildCsatPanel()\n this.csatPanel.style.display = 'block'\n }\n\n // Header availability line: green when online, amber when the chatroom is\n // outside office hours. Server-provided offlineMessage (already localized)\n // is preferred for the away text; falls back to the i18n label.\n const isTerminal = terminalStates.includes(store.state)\n if (store.offline) {\n this.headStatus.textContent = `● ${store.offlineMessage || this.cfg.i18n?.away || 'Away'}`\n this.headStatus.className = 'ocw-head-status away'\n this.headStatus.style.display = ''\n } else if (store.conversationId) {\n this.headStatus.textContent = `● ${this.cfg.i18n?.online ?? 'Online'}`\n this.headStatus.className = 'ocw-head-status online'\n this.headStatus.style.display = ''\n } else {\n this.headStatus.style.display = 'none'\n }\n\n // Resolved: a legible divider in the thread + a one-tap reopen affordance.\n if (isTerminal && store.messages().length > 0) {\n const note = el('div', 'ocw-resolved-note', `— ${this.cfg.i18n?.resolved ?? 'Marked as resolved'} —`)\n this.scroll.append(note)\n this.reopenBtn.style.display = 'block'\n } else {\n this.reopenBtn.style.display = 'none'\n }\n }\n\n setConnStatus(status: 'connecting' | 'open' | 'reconnecting' | 'error', message?: string): void {\n if (status === 'open') { this.connStatus.style.display = 'none'; return }\n this.connStatus.style.display = ''\n // 'error' is a FATAL, non-transient state (bad token, closed chatroom, or the\n // relay is unreachable after repeated tries) — show a clear reason and don't\n // pretend we're still \"connecting…\". Anything else is transient.\n const fatal = status === 'error'\n this.connStatus.className = `ocw-conn-status${fatal ? ' err' : status === 'reconnecting' ? ' warn' : ''}`\n this.connStatus.textContent = fatal\n ? `⚠ ${message ?? 'Chat unavailable'}`\n : status === 'reconnecting' ? (message ?? '↻ reconnecting…') : '● connecting…'\n }\n\n private buildPreChatPanel(cfg: import('./protocol/frames.js').PreChatConfig): void {\n this.preChatBuilt = true\n this.preChatPanel.replaceChildren()\n this.preChatPanel.append(el('div', 'ocw-prechat-title', cfg.title ?? 'Before we start…'))\n const form = el('div', 'ocw-offline-form')\n const inputs: Partial<Record<'name' | 'email' | 'phone', HTMLInputElement>> = {}\n for (const f of cfg.fields ?? ['name', 'email']) {\n const inp = el('input', 'ocw-offline-input') as HTMLInputElement\n inp.type = f === 'email' ? 'email' : f === 'phone' ? 'tel' : 'text'\n inp.placeholder = f === 'name' ? 'Your name' : f === 'email' ? 'Your email' : 'Your phone number'\n inputs[f] = inp\n form.append(inp)\n }\n let topicSel: HTMLSelectElement | null = null\n if (cfg.topics?.length) {\n topicSel = el('select', undefined) as HTMLSelectElement\n const ph = document.createElement('option'); ph.value = ''; ph.textContent = 'What is this about?'; topicSel.append(ph)\n for (const t of cfg.topics) { const o = document.createElement('option'); o.value = t; o.textContent = t; topicSel.append(o) }\n form.append(topicSel)\n }\n let callbackCb: HTMLInputElement | null = null\n let phoneForCb: HTMLInputElement | null = null\n if (cfg.callbackOption) {\n const row = el('label', 'ocw-prechat-cb')\n callbackCb = document.createElement('input'); callbackCb.type = 'checkbox'\n row.append(callbackCb, document.createTextNode('📞 Request a call back'))\n form.append(row)\n if (!inputs.phone) {\n phoneForCb = el('input', 'ocw-offline-input') as HTMLInputElement\n phoneForCb.type = 'tel'; phoneForCb.placeholder = 'Phone number for the call'; phoneForCb.style.display = 'none'\n callbackCb.addEventListener('change', () => phoneForCb!.style.setProperty('display', callbackCb!.checked ? 'block' : 'none'))\n form.append(phoneForCb)\n }\n }\n const submit = el('button', 'ocw-offline-submit', 'Start chat') as HTMLButtonElement\n submit.type = 'button'\n submit.addEventListener('click', () => {\n const email = inputs.email?.value.trim()\n if (inputs.email && (!email || !/^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/.test(email))) { inputs.email.focus(); return }\n const callback = !!callbackCb?.checked\n const phone = (inputs.phone?.value ?? phoneForCb?.value ?? '').trim()\n if (callback && !phone) { (inputs.phone ?? phoneForCb)?.focus(); return }\n if (topicSel && cfg.topics?.length && !topicSel.value) { topicSel.focus(); return }\n submit.disabled = true // a double-click must not qualify twice\n this.completePreChat()\n this.h.onPreChat?.({\n ...(inputs.name?.value.trim() ? { name: inputs.name.value.trim() } : {}),\n ...(email ? { email } : {}),\n ...(phone ? { phone } : {}),\n ...(topicSel?.value ? { topic: topicSel.value } : {}),\n ...(callback ? { callback: true } : {}),\n })\n })\n form.append(submit)\n this.preChatPanel.append(form)\n }\n\n /** Mark pre-chat complete (submitted now or in a previous session). */\n completePreChat(): void {\n this.preChatDone = true\n this.preChatPanel.style.display = 'none'\n if (this.storeRef) this.render(this.storeRef)\n }\n\n /** KB deflection results (\"was this your question?\") above the composer. */\n showDeflection(articles: { id: string; title: string; answer: string }[]): void {\n if (!articles.length) return this.hideDeflection()\n this.deflectPanel.replaceChildren()\n this.deflectPanel.append(el('div', 'ocw-deflect-hint', 'Instant answers — tap to expand'))\n for (const a of articles.slice(0, 3)) {\n const card = el('button', 'ocw-deflect-card')\n card.append(el('div', 'ocw-deflect-q', a.title), el('div', 'ocw-deflect-a', a.answer))\n card.addEventListener('click', () => card.classList.toggle('open'))\n this.deflectPanel.append(card)\n }\n this.deflectPanel.style.display = 'flex'\n }\n\n hideDeflection(): void {\n this.deflectPanel.style.display = 'none'\n this.deflectPanel.replaceChildren()\n }\n\n private buildCsatPanel(): void {\n this.csatPanel.replaceChildren()\n this.csatPanel.append(el('div', 'ocw-csat-title', 'How did we do?'))\n const stars = el('div', 'ocw-csat-stars')\n const btns: HTMLButtonElement[] = []\n for (let i = 1; i <= 5; i++) {\n const b = el('button', 'ocw-csat-star', '★')\n b.dataset['score'] = String(i)\n b.addEventListener('mouseenter', () => btns.forEach((bb, idx) => bb.classList.toggle('lit', idx < i)))\n b.addEventListener('mouseleave', () => btns.forEach(bb => bb.classList.remove('lit')))\n b.addEventListener('click', () => {\n this.csatSubmitted = true\n this.csatPanel.replaceChildren(el('div', 'ocw-csat-done', `Thanks for your ${i}★ rating!`))\n this.h.onCsat?.(i)\n })\n btns.push(b); stars.append(b)\n }\n this.csatPanel.append(stars)\n }\n\n /** Whether the subject card (server Subject entity, mount config fallback)\n * has been built — built once when data first arrives. */\n private subjectBuilt = false\n\n private buildSubjectCard(store: ChatStore): void {\n if (this.subjectBuilt) return\n const s = store.subject\n const cfg = this.cfg.subject\n // Only show the subject card when there is actual subject data (from the\n // server) or an explicit subject config passed by the embedder (title,\n // tags, status). Never fall back to store.name — that's the domain/profile\n // name and is already shown in the header; rendering it here as well is\n // what caused the duplication seen in the Hotel front desk screenshot.\n const title = s?.title ?? cfg?.title\n if (!title) return\n this.subjectBuilt = true\n this.subjectCard.replaceChildren()\n this.subjectCard.append(el('div', 'ocw-subject-title', title))\n if (cfg?.subtitle) this.subjectCard.append(el('div', 'ocw-subject-sub', cfg.subtitle))\n const tags = el('div', 'ocw-tags')\n if (s) for (const [k, v] of Object.entries(s.fields)) tags.append(el('span', 'ocw-tag', `${k}: ${v}`))\n else for (const t of cfg?.tags ?? []) tags.append(el('span', 'ocw-tag', t))\n if (tags.childNodes.length) this.subjectCard.append(tags)\n const status = s?.state ?? cfg?.status\n if (status) { this.statusBadge.textContent = status; this.statusBadge.style.display = 'inline-flex' }\n }\n\n private chipEl(a: ManifestAction): HTMLButtonElement {\n const btn = el('button', 'ocw-chip', a.icon ? `${a.icon} ${a.label}` : a.label)\n btn.dataset['actionId'] = a.id\n btn.addEventListener('click', async () => {\n if (a.confirm && !(await this.confirm(a.label))) return\n if (a.input?.length) this.openForm(a)\n else this.h.onInvoke(a.id)\n })\n return btn\n }\n\n /** In-widget confirmation modal (replaces window.confirm). */\n private confirm(label: string): Promise<boolean> {\n return new Promise((resolve) => {\n const overlay = el('div', 'ocw-modal')\n const card = el('div', 'ocw-modal-card')\n card.append(el('div', 'ocw-modal-title', label))\n card.append(el('div', 'ocw-modal-body', `Confirm “${label}”?`))\n const row = el('div', 'ocw-modal-actions')\n const cancel = el('button', 'ocw-modal-cancel', 'Cancel')\n const ok = el('button', 'ocw-modal-ok', 'Confirm')\n const close = (v: boolean) => { overlay.remove(); resolve(v) }\n cancel.addEventListener('click', () => close(false))\n ok.addEventListener('click', () => close(true))\n overlay.addEventListener('click', (e) => { if (e.target === overlay) close(false) })\n row.append(cancel, ok); card.append(row); overlay.append(card)\n this.root.append(overlay)\n ok.focus()\n })\n }\n\n /** Inline form for a form-effect action: typed inputs (date picker, number,\n * text) rendered above the composer — no browser prompts. */\n private openForm(a: ManifestAction): void {\n this.formHost.replaceChildren()\n const panel = el('div', 'ocw-form')\n panel.append(el('div', 'ocw-form-title', a.icon ? `${a.icon} ${a.label}` : a.label))\n const inputs = new Map<string, HTMLInputElement>()\n for (const f of a.input ?? []) {\n const row = el('label', 'ocw-form-row'); row.append(el('span', 'ocw-form-lbl', f.label))\n if (f.type === 'select' && f.options?.length) {\n const sel = el('select', 'ocw-form-input')\n if (!f.required) sel.append(el('option', undefined, '— select —'))\n for (const opt of f.options) { const o = el('option'); o.value = opt; o.textContent = opt; sel.append(o) }\n if (f.required) sel.required = true\n row.append(sel)\n inputs.set(f.name, sel as unknown as HTMLInputElement)\n } else {\n const inp = el('input', 'ocw-form-input')\n inp.type = f.type === 'number' ? 'number' : f.type === 'date' ? 'datetime-local' : 'text'\n if (f.required) inp.required = true\n row.append(inp); inputs.set(f.name, inp)\n }\n panel.append(row)\n }\n const actions = el('div', 'ocw-form-actions')\n const cancel = el('button', 'ocw-form-cancel', 'Cancel')\n const submit = el('button', 'ocw-form-submit', 'Send')\n cancel.addEventListener('click', () => this.formHost.replaceChildren())\n submit.addEventListener('click', () => {\n const out: Record<string, unknown> = {}\n for (const [name, inp] of inputs) {\n if (inp.required && !inp.value) { inp.style.borderColor = '#e5484d'; return }\n out[name] = inp.type === 'number' ? Number(inp.value) : inp.value\n }\n this.formHost.replaceChildren()\n this.h.onInvoke(a.id, out)\n })\n actions.append(cancel, submit); panel.append(actions)\n this.formHost.append(panel)\n inputs.values().next().value?.focus()\n }\n\n private messageEl(m: RenderMessage, store: ChatStore, showLabel = false): HTMLElement {\n if (m.senderRole === 'system') {\n const sys = el('div', 'ocw-sys'); sys.textContent = m.deletedAt ? 'message deleted' : contentText(m.content); return sys\n }\n const mine = m.senderId === this.me\n const isNote = !!m.internal\n const row = el('div', `ocw-row ${isNote ? 'ocw-note mine' : mine ? 'mine' : 'theirs'} ${m.senderRole === 'bot' ? 'ocw-bot' : ''}`)\n if (!mine && !isNote) row.append(el('div', 'ocw-dot', m.senderRole === 'bot' ? '🤖' : '🧑'))\n const col = el('div')\n if (showLabel) {\n const who = m.senderRole === 'bot'\n ? (this.cfg.i18n?.aiAssistant ?? 'AI Assistant')\n : (this.cfg.subject?.ownerLabel ?? this.cfg.subject?.title ?? 'Support')\n col.append(el('div', 'ocw-msg-sender', who))\n }\n const bubbleWrap = el('div', 'ocw-bubble-wrap')\n // Reply-to context if present\n if (m.replyToId) {\n const replyCtx = el('div', 'ocw-reply-to', '↩ replying to a message')\n replyCtx.style.cssText = 'font-size:11px;color:var(--ocw-mut);margin-bottom:2px;font-style:italic'\n col.append(replyCtx)\n }\n const bubble = el('div', 'ocw-bubble')\n let textNode: Text | null = null\n if (m.deletedAt) bubble.append(el('span', 'ocw-deleted', 'message deleted'))\n else if (m.content.kind === 'attachment') {\n const c = m.content\n if (c.mime?.startsWith('image/')) {\n const img = document.createElement('img')\n img.src = c.url; img.alt = c.name ?? 'image'\n img.style.cssText = 'max-width:220px;max-height:160px;border-radius:10px;display:block;cursor:pointer'\n img.addEventListener('click', () => window.open(c.url, '_blank'))\n bubble.append(img)\n } else {\n const a = document.createElement('a')\n a.href = c.url; a.target = '_blank'; a.rel = 'noopener'\n a.style.cssText = 'display:flex;align-items:center;gap:8px;color:inherit;text-decoration:none'\n a.append(el('span', undefined, '📄'), el('span', undefined, c.name ?? 'file'))\n bubble.append(a)\n }\n } else {\n if (m.content.kind === 'appointment') {\n const ap = m.content\n const card = el('div', 'ocw-appt')\n card.append(el('div', 'ocw-appt-title', `\\u{1F4C5} ${ap.title}`))\n card.append(el('div', 'ocw-appt-time', new Date(ap.startIso).toLocaleString() + ' \\u2013 ' + new Date(ap.endIso).toLocaleTimeString()))\n if (ap.location) card.append(el('div', 'ocw-appt-loc', `\\u{1F4CD} ${ap.location}`))\n if (ap.description) card.append(el('div', 'ocw-appt-desc', ap.description))\n const links = el('div', 'ocw-appt-links')\n const gLink = document.createElement('a'); gLink.href = ap.googleUrl; gLink.target = '_blank'; gLink.rel = 'noopener'; gLink.className = 'ocw-appt-btn'; gLink.textContent = '\\u{1F4C5} Add to Google Calendar'\n const iLink = document.createElement('a'); iLink.href = ap.icalUrl; iLink.download = `${ap.title}.ics`; iLink.className = 'ocw-appt-btn ocw-appt-btn-sec'; iLink.textContent = '\\u{1F34E} Apple / iCal'\n links.append(gLink, iLink); card.append(links); bubble.append(card)\n } else {\n textNode = document.createTextNode(contentText(m.content))\n bubble.append(textNode)\n if (m.editedAt) bubble.append(el('span', 'ocw-edited', '(edited)'))\n }\n }\n bubbleWrap.append(bubble)\n\n // Live translation: only for the other party's plain-text messages (not notes).\n if (!mine && !isNote && this.h.onTranslate && m.content.kind === 'text' && !m.deletedAt && m.seq > 0 && textNode) {\n const original = m.content.text\n if (original.trim()) {\n const translateBtn = el('button', 'ocw-translate-btn', '🌐')\n translateBtn.type = 'button'\n translateBtn.title = 'Translate'\n translateBtn.addEventListener('click', (e) => {\n e.stopPropagation()\n if (this.showingTranslation.has(m.id)) {\n this.showingTranslation.delete(m.id)\n textNode!.textContent = original\n translateBtn.textContent = '🌐'\n translateBtn.title = 'Translate'\n return\n }\n const cached = this.translationCache.get(m.id)\n if (cached !== undefined) {\n this.showingTranslation.add(m.id)\n textNode!.textContent = cached\n translateBtn.textContent = '↩'\n translateBtn.title = 'Show original'\n return\n }\n translateBtn.textContent = '⏳'\n void this.h.onTranslate!(original).then((result) => {\n if (result === null) {\n translateBtn.textContent = '⚠️'\n translateBtn.title = 'Translation unavailable'\n setTimeout(() => { translateBtn.textContent = '🌐'; translateBtn.title = 'Translate' }, 1500)\n return\n }\n this.translationCache.set(m.id, result)\n this.showingTranslation.add(m.id)\n textNode!.textContent = result\n translateBtn.textContent = '↩'\n translateBtn.title = 'Show original'\n })\n })\n bubbleWrap.append(translateBtn)\n }\n }\n // Edit/delete context menu on own non-deleted messages\n if (mine && !m.deletedAt && m.seq > 0 && (this.h.onEdit ?? this.h.onDelete)) {\n const menu = el('div', 'ocw-msg-menu')\n if (this.h.onEdit) {\n const editBtn = el('button', undefined, '✏️')\n editBtn.title = 'Edit'\n editBtn.addEventListener('click', (e) => {\n e.stopPropagation()\n // Inline edit: replace bubble text with a small textarea + save/cancel\n const original = contentText(m.content)\n const ta = document.createElement('textarea')\n ta.value = original\n ta.rows = Math.min(4, Math.ceil(original.length / 40) + 1)\n ta.style.cssText = 'width:100%;resize:vertical;border:1px solid var(--ocw-accent);border-radius:8px;padding:6px 10px;font:inherit;font-size:14px;background:var(--ocw-card);color:#1c1b1a;box-sizing:border-box'\n const saveBtn = el('button', 'ocw-form-submit', 'Save')\n saveBtn.style.cssText = 'margin-top:6px;padding:5px 14px;font-size:13px'\n const cancelBtn = el('button', 'ocw-form-cancel', 'Cancel')\n cancelBtn.style.cssText = 'margin-top:6px;padding:5px 10px;font-size:13px'\n const btnRow = el('div'); btnRow.style.cssText = 'display:flex;gap:6px;justify-content:flex-end'\n btnRow.append(cancelBtn, saveBtn)\n const editPanel = el('div'); editPanel.append(ta, btnRow)\n bubble.replaceChildren(editPanel)\n ta.focus(); ta.select()\n const restore = () => bubble.replaceChildren(textNode ?? document.createTextNode(original))\n cancelBtn.addEventListener('click', restore)\n saveBtn.addEventListener('click', () => {\n const newText = ta.value.trim()\n if (newText && newText !== original) { this.h.onEdit!(m.id, newText); restore() }\n else restore()\n })\n ta.addEventListener('keydown', (ke) => {\n if (ke.key === 'Enter' && !ke.shiftKey) { ke.preventDefault(); saveBtn.click() }\n if (ke.key === 'Escape') restore()\n })\n })\n menu.append(editBtn)\n }\n if (this.h.onDelete) {\n const delBtn = el('button', 'del', '🗑')\n delBtn.title = 'Delete'\n delBtn.addEventListener('click', (e) => { e.stopPropagation(); this.h.onDelete!(m.id) })\n menu.append(delBtn)\n }\n bubbleWrap.append(menu)\n }\n col.append(bubbleWrap)\n\n // Reactions: existing pills + add-reaction picker (hover-revealed)\n if (this.h.onReact && !m.deletedAt && m.seq > 0) {\n const reactWrap = el('div', 'ocw-react-wrap')\n const reactRow = el('div', 'ocw-react')\n // Existing reaction pills\n if (m.reactions && Object.keys(m.reactions).length) {\n for (const [emoji, users] of Object.entries(m.reactions)) {\n const pill = el('button', `ocw-react-pill${(users as string[]).includes(this.me) ? ' mine' : ''}`, `${emoji} ${(users as string[]).length}`)\n pill.addEventListener('click', () => this.h.onReact?.(m.id, emoji, (users as string[]).includes(this.me)))\n reactRow.append(pill)\n }\n }\n // Add-reaction button + picker\n const addBtn = el('button', 'ocw-react-btn', '+')\n const picker = el('div', 'ocw-react-picker')\n for (const emoji of REACTION_EMOJIS) {\n const pb = el('button', undefined, emoji)\n pb.addEventListener('click', (e) => {\n e.stopPropagation()\n const alreadyReacted = m.reactions?.[emoji]?.includes(this.me as never)\n this.h.onReact?.(m.id, emoji, !!alreadyReacted)\n picker.style.display = 'none'\n })\n picker.append(pb)\n }\n picker.style.display = 'none'\n addBtn.addEventListener('click', (e) => {\n e.stopPropagation()\n const opening = picker.style.display === 'none'\n picker.style.display = opening ? 'flex' : 'none'\n // Close on the next outside click. Registered only when OPENING —\n // the old code added one document listener per message on EVERY\n // render, so long conversations piled up hundreds of stale handlers.\n if (opening) document.addEventListener('click', () => { picker.style.display = 'none' }, { once: true })\n })\n reactRow.append(addBtn)\n reactWrap.append(reactRow, picker)\n col.append(reactWrap)\n } else if (m.reactions && Object.keys(m.reactions).length) {\n col.append(el('div', 'ocw-react', Object.entries(m.reactions).map(([e, u]) => `${e}${(u as string[]).length}`).join(' ')))\n }\n const meta = el('div', 'ocw-time ocw-meta', fmtTime(m.ts))\n if (mine && m.status) {\n const t = el('span', `ocw-tick${m.status === 'read' ? ' read' : m.status === 'delivered' ? ' delivered' : ''}`, tick(m.status))\n meta.append(t)\n }\n // \"Seen\" indicator when agent has read past this message\n if (mine && m.seq > 0 && store.lastReadByOthers >= m.seq) {\n meta.append(el('span', 'ocw-seen', ' · Seen'))\n }\n col.append(meta)\n row.append(col)\n return row\n }\n}\n\nfunction tick(s: NonNullable<RenderMessage['status']>): string {\n switch (s) {\n case 'read': return '✓✓' // blue double tick rendered via CSS colour\n case 'delivered': return '✓✓'\n case 'sent': return '✓'\n default: return '🕓'\n }\n}\n","// 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","import { persistentUid } from './uid.js'\nimport {\n asConversationId,\n type ClientFrame, type ConversationId,\n} from './protocol/index.js'\nimport { ChatStore } from './store.js'\nimport { ConnectionManager } from './connection.js'\nimport { PersistentOutbox } from './outbox.js'\nimport { E2ESession, extractX3DHInit } from './e2e.js'\nimport { Renderer, type WidgetConfig } from './renderer.js'\nimport { restoreHistory, resolveRelayUrls } from './history.js'\n\nexport interface UserInfo {\n /** Display name shown in the conversation (e.g. \"Sarah Chen\"). */\n name?: string\n /** Email address — passed as conversation metadata for agent context. */\n email?: string\n /** Avatar URL — shown as the guest's avatar in both widget and dashboard. */\n avatar?: string\n /** Any custom key/value metadata to attach to the conversation\n * (e.g. plan tier, account ID, page URL). Shown to agents in the sidebar. */\n meta?: Record<string, string>\n}\n\nexport interface MountOptions {\n el: HTMLElement\n /** Relay URL. Any scheme works — `https://api.example.com` is fine; the widget\n * derives the WebSocket URL (`wss://…/ws`) and REST base from it. */\n url: string\n /** HTTP(S) base for REST calls — only needed when the REST API is on a\n * DIFFERENT origin than the socket. Normally leave unset. */\n apiUrl?: string\n profileId: string\n subjectId?: string\n /** Open a user↔user direct conversation with `peerId` instead of a support\n * thread. Requires signed identity on the chatroom (both `kind: 'direct'`\n * and `peerId` together; `subjectId` is ignored — the server derives the\n * symmetric DM key so both sides land in the SAME conversation). */\n kind?: 'direct'\n peerId?: string\n /** IDENTITY (tiered — the host owns identity, the widget never has to persist it):\n * 1. `token` — a signed identity token. Either a capability token, or (recommended\n * for embedders) an ES256 JWT `{sub,iat,exp}` signed by your backend with the\n * private key whose public half is set as the chatroom's `guestPublicKey`.\n * The server cryptographically verifies it. Works in ANY language/environment,\n * no cookies or storage required. This is the production path.\n * 2. `userId` — a stable id you already have for the visitor (e.g. your logged-in\n * user id). Unauthenticated (\"you vouch for it\") but works everywhere. Used\n * only when `token` is absent.\n * 3. Neither — the widget falls back to best-effort local identity on the host\n * origin (first-party cookie + localStorage). A returning visitor on the same\n * browser keeps their history; if storage is blocked they get a fresh chat. */\n token?: string\n /** Called when a signed token is rejected (expired): return a fresh token\n * from your backend to renew the session without a reload. */\n refreshToken?: () => Promise<string | null>\n userId?: string\n subject?: WidgetConfig['subject']\n quickReplies?: string[]\n accent?: string\n /** Secondary accent (guest bubble + send button). Defaults to the design\n * blue; omit and it follows `accent` for a cohesive single-token retheme. */\n accent2?: string\n /** Colour scheme: 'auto' (follow OS, default), 'light', or 'dark'. */\n theme?: 'auto' | 'light' | 'dark'\n /** Load Baloo 2 + Nunito webfonts (default true). false = system fonts only. */\n webfont?: boolean\n /** Stack navigation: when set, the chatroom header shows a back chevron that\n * calls this. Used by `<ChatApp>` so tapping a conversation opens the room and\n * the back arrow returns to the list — native-app style. */\n onBack?: () => void\n /** If set, shows a 🌐 translate button on incoming messages that translates\n * them into this language (ISO code or language name) via the server's\n * /translate endpoint. Omit to disable the feature. */\n translateLang?: string\n /** If true, mount as a floating launcher button that opens/closes the chat */\n launcher?: boolean\n /** Position of the launcher button: default 'bottom-right' */\n position?: 'bottom-right' | 'bottom-left'\n /** Launcher teaser — the \"optional message\" card shown ABOVE the closed\n * launcher button to invite a chat (like Channel.io's greeting). Pass a\n * string for just a title, or `{ title, subtitle }`. If omitted, the\n * widget uses `defaults.launcherMessage` from the chatroom manifest when\n * present. Dismissible by the visitor (remembered for the browser session);\n * auto-hides once the chat is opened. Only applies in `launcher` mode. */\n launcherMessage?: string | { title: string; subtitle?: string }\n /** Optional user info for identified users. When provided, the name/email/\n * avatar are shown to agents in the dashboard instead of the anonymous ID.\n * The token still controls identity — this is display metadata only.\n * Anonymous users (no token, no user) remain fully anonymous. */\n user?: UserInfo\n /** Optional per-tenant feature switches. All default to ON (omit for current\n * behavior). Set a flag to `false` to disable the feature — the widget then\n * does no work for it (no reaction picker built per message, no CSAT panel,\n * no KB-deflection lookups). Gating is by not wiring the handler, so the\n * renderer skips the feature entirely. */\n features?: {\n reactions?: boolean // emoji reactions on messages (default true)\n csat?: boolean // post-resolution satisfaction survey (default true)\n deflection?: boolean // pre-first-message KB article suggestions (default true)\n }\n /** i18n: override UI strings. All keys are optional — omitted keys fall\n * back to English defaults. */\n i18n?: {\n placeholder?: string // input placeholder, default \"Message…\"\n send?: string // send button label, default \"➤\"\n offline?: string // offline panel title, default \"We're offline right now\"\n poweredBy?: string // footer text, default \"Powered by Relay\"\n online?: string // header status when available, default \"Online\"\n away?: string // header status when offline, default \"Away\"\n aiAssistant?: string // speaker label for bot messages, default \"AI Assistant\"\n resolved?: string // resolved divider text, default \"Marked as resolved\"\n reopen?: string // reopen button label, default \"Reopen conversation\"\n }\n}\n\nexport interface WidgetHandle { close(): void }\n\n\n// ── Mount registry ────────────────────────────────────────────────────────────\n// Tracks active widget instances per host element. Prevents double-mounting\n// when React strict mode, HMR, or caller code calls mount() twice on the same\n// element — the most common cause of two widgets appearing on one page.\nconst _registry = new WeakMap<Element, WidgetHandle>()\n// Launcher widgets attach to document.body (not the ref div), and in launcher\n// mode React may re-create the ref div on re-render — so the el-keyed registry\n// above can't catch a stale launcher. This slot-keyed registry guarantees at\n// most ONE launcher per (profileId, subjectId), so an identity flicker or\n// re-render can never leave two stacked bubbles/panels on the page.\nconst _launcherRegistry = new Map<string, WidgetHandle>()\nfunction launcherSlot(opts: MountOptions): string {\n return `relay-launcher::${opts.profileId}::${opts.subjectId ?? ''}`\n}\n\n// One AudioContext for ALL widget instances on the page (notification blips\n// are fire-and-forget; nothing about them is per-instance).\nlet _audioCtx: AudioContext | null = null\nfunction getAudioContext(): AudioContext | null {\n if (_audioCtx && _audioCtx.state !== 'closed') return _audioCtx\n try { _audioCtx = new AudioContext(); return _audioCtx } catch { return null }\n}\n\n/** Unmount any widget currently mounted on `el`. No-op if nothing is mounted. */\nexport function unmount(el: Element): void {\n _registry.get(el)?.close()\n _registry.delete(el)\n}\n\nexport function mount(opts: MountOptions): WidgetHandle {\n // Auto-close any previous instance on this exact element before re-mounting.\n // Covers React double-invoke in StrictMode, HMR, and accidental duplicate calls.\n if (_registry.has(opts.el)) {\n _registry.get(opts.el)!.close()\n _registry.delete(opts.el)\n }\n // Launcher mode: also close any prior launcher for the same slot, even if it\n // was mounted on a now-detached div (React re-creates the ref div on\n // re-render). This is what prevents two stacked widgets after an identity\n // flicker (anonymous → logged-in).\n if (opts.launcher) _launcherRegistry.get(launcherSlot(opts))?.close()\n\n // Tiered identity (see MountOptions): a host-provided signed token wins, then a\n // host-vouched userId, then best-effort local persistence. The widget never\n // depends on its own storage when the host supplies identity — which is what\n // makes it safe to embed in any environment (iframes, webviews, SSR, etc.).\n // Always keep the stable per-browser anonymous id, even when the host\n // identifies the visitor — so on login we can tell the server to merge the\n // anonymous conversation into the user (Channel.io-style boot+identify).\n const anonId = persistentUid()\n let deflectTimer: ReturnType<typeof setTimeout> | undefined\n let destroyed = false\n const token = opts.token ?? opts.userId ?? anonId\n // If we're connecting as an identified user (token differs from the anon id),\n // pass the anon id as linkFrom so the server adopts any anonymous history.\n const linkFrom = token !== anonId ? anonId : undefined\n // Accept any scheme on `url` (https/http/wss/ws) and derive both the concrete\n // WebSocket URL and the REST base from it. `apiUrl` overrides the REST base\n // only when the API is on a different origin than the socket.\n const { wsUrl, httpBase } = resolveRelayUrls(opts.url, opts.apiUrl)\n let store = new ChatStore(token as never)\n // Key the outbox by token + subjectId so each listing has its own pending queue.\n // Without this, a pending message from listing A appears as a ghost on listing B.\n const outboxKey = opts.subjectId ? `${token}::${opts.subjectId}` : token\n const outbox = new PersistentOutbox(outboxKey)\n let cid: ConversationId | undefined\n let outboxRestored = false\n\n let _mql: MediaQueryList | null = null\n let _mqlHandler: ((e: MediaQueryListEvent) => void) | null = null\n let _escHandler: ((e: KeyboardEvent) => void) | null = null\n let _paintTeaser: (() => void) | null = null\n // (e.g. a bare `<div id=\"chat\"></div>` with no CSS). Without this the\n // widget's internal `height:100%` collapses to near-zero. Only applies\n // when the element truly has no height set — explicit CSS always wins.\n if (!opts.launcher && !opts.el.style.height && opts.el.clientHeight === 0) {\n opts.el.style.width = opts.el.style.width || '100%'\n opts.el.style.height = '600px'\n }\n\n // Restore pending outbox items for this specific listing/conversation.\n // The outbox is keyed by token+subjectId so ghost bubbles from other listings\n // never appear here.\n for (const item of outbox.load()) store.addOptimistic(item.clientMsgId, item.content)\n\n // ── Launcher mode ─────────────────────────────────────────────────────────\n let launcherEl: HTMLElement | null = null\n let badgeEl: HTMLElement | null = null\n let unread = 0\n let open = !opts.launcher // start open when not in launcher mode\n\n if (opts.launcher) {\n const pos = opts.position ?? 'bottom-right'\n const isRight = pos.includes('right')\n\n // Outer wrapper holds both the panel and the bubble button\n launcherEl = document.createElement('div')\n launcherEl.style.cssText = `position:fixed;${isRight ? 'right:20px' : 'left:20px'};bottom:20px;z-index:9999;display:flex;flex-direction:column;align-items:${isRight ? 'flex-end' : 'flex-start'};gap:12px`\n\n // ── Chat panel — sits above the bubble ─────────────────────────────────\n const panel = document.createElement('div')\n // Responsive panel: full-screen on mobile (<480px); on desktop 380×600\n // CLAMPED to the viewport (`min(…)`) so a short or narrow browser window\n // never clips the composer — same clamp the React launcher already uses.\n // A MediaQueryList keeps the layout live across rotation/resize.\n const mql = typeof window !== 'undefined' && typeof window.matchMedia === 'function'\n ? window.matchMedia('(max-width: 479px)') : null\n const applyPanelLayout = (mobile: boolean) => {\n // Fullscreen is the ONLY case that strips the widget's corner radius —\n // the renderer keys .ocw-fs, never a blanket viewport query, so inline\n // mobile embeds keep their normal in-page layout.\n opts.el.classList.toggle('ocw-fs', mobile)\n panel.style.cssText = mobile ? [\n 'position:fixed', 'inset:0', 'width:100%', 'height:100dvh',\n 'border-radius:0', 'overflow:hidden',\n 'box-shadow:none', 'display:none', 'flex-direction:column', 'background:#fff',\n 'transition:opacity .18s', 'opacity:0', 'z-index:9998',\n ].join(';') : [\n 'width:min(380px, calc(100vw - 40px))', 'height:min(600px, calc(100dvh - 108px))',\n 'border-radius:28px', 'overflow:hidden',\n 'box-shadow:0 12px 32px rgba(108,92,231,.14)',\n 'display:none', 'flex-direction:column', 'background:#fff',\n 'transform-origin:bottom ' + (isRight ? 'right' : 'left'),\n 'transition:opacity .18s,transform .18s', 'opacity:0', 'transform:scale(.95)',\n ].join(';')\n }\n applyPanelLayout(mql?.matches ?? false)\n const mqlHandler = (e: MediaQueryListEvent): void => applyPanelLayout(e.matches)\n mql?.addEventListener('change', mqlHandler)\n _mql = mql; _mqlHandler = mqlHandler\n\n // Move the mount target INSIDE the panel — not full-page\n opts.el.style.cssText = 'width:100%;height:100%;overflow:hidden'\n panel.append(opts.el)\n\n // ── Bubble button ─────────────────────────────────────────────────────\n // Inline SVGs, not emoji: '💬'/'✕' render differently on every OS (and as\n // colour emoji can clash with the accent); these are crisp everywhere.\n const CHAT_SVG =\n '<svg viewBox=\"0 0 24 24\" width=\"26\" height=\"26\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\" aria-hidden=\"true\">' +\n '<path d=\"M21 11.5a8.38 8.38 0 0 1-.9 3.8 8.5 8.5 0 0 1-7.6 4.7 8.38 8.38 0 0 1-3.8-.9L3 21l1.9-5.7a8.38 8.38 0 0 1-.9-3.8 8.5 8.5 0 0 1 4.7-7.6 8.38 8.38 0 0 1 3.8-.9h.5a8.48 8.48 0 0 1 8 8v.5z\" ' +\n 'fill=\"currentColor\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/></svg>'\n const CLOSE_SVG =\n '<svg viewBox=\"0 0 24 24\" width=\"22\" height=\"22\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\" aria-hidden=\"true\">' +\n '<path d=\"M18 6 6 18M6 6l12 12\" stroke=\"currentColor\" stroke-width=\"2.5\" stroke-linecap=\"round\"/></svg>'\n\n const btn = document.createElement('button')\n btn.type = 'button'\n btn.style.cssText = [\n `width:56px;height:56px;border-radius:50%`,\n `background:${opts.accent ?? '#6c5ce7'}`,\n `color:#fff;border:none;cursor:pointer`,\n `box-shadow:0 12px 32px rgba(108,92,231,.14)`,\n `position:relative;flex:none`,\n `display:flex;align-items:center;justify-content:center`,\n `transition:transform .15s`,\n ].join(';')\n btn.onmouseenter = () => { btn.style.transform = 'scale(1.08)' }\n btn.onmouseleave = () => { btn.style.transform = 'scale(1)' }\n\n badgeEl = document.createElement('span')\n badgeEl.style.cssText = `position:absolute;top:-4px;right:-4px;background:#4c6fff;color:#fff;border-radius:50%;width:20px;height:20px;font-size:11px;font-weight:700;display:none;align-items:center;justify-content:center`\n\n // (Re)build the bubble's content for the current open state. innerHTML\n // wipes children, so the badge is re-appended each time.\n const paintBubble = () => {\n btn.innerHTML = open ? CLOSE_SVG : CHAT_SVG\n btn.setAttribute('aria-label', open ? 'Close chat' : 'Open chat')\n btn.setAttribute('aria-expanded', String(open))\n btn.append(badgeEl!)\n }\n paintBubble()\n\n launcherEl.append(panel, btn)\n document.body.append(launcherEl)\n\n // ── Launcher teaser (the \"optional message\" card) ─────────────────────\n // A small dismissible card above the button inviting a chat. Source of\n // truth: the explicit `launcherMessage` option (instant), else the\n // chatroom manifest's `defaults.launcherMessage` (arrives on connect).\n // Dismissal is per browser session so it doesn't nag across page nav.\n const teaserKey = `ocw-teaser-dismissed::${opts.profileId}`\n const optMsg = typeof opts.launcherMessage === 'string'\n ? { title: opts.launcherMessage }\n : opts.launcherMessage\n let teaserEl: HTMLElement | null = null\n const teaserDismissed = (): boolean => {\n try { return sessionStorage.getItem(teaserKey) === '1' } catch { return false }\n }\n const CHAT_MINI_SVG =\n '<svg viewBox=\"0 0 24 24\" width=\"15\" height=\"15\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\" aria-hidden=\"true\">' +\n '<path d=\"M21 11.5a8.38 8.38 0 0 1-.9 3.8 8.5 8.5 0 0 1-7.6 4.7 8.38 8.38 0 0 1-3.8-.9L3 21l1.9-5.7a8.38 8.38 0 0 1-.9-3.8 8.5 8.5 0 0 1 4.7-7.6 8.38 8.38 0 0 1 3.8-.9h.5a8.48 8.48 0 0 1 8 8v.5z\" ' +\n 'fill=\"currentColor\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/></svg>'\n const paintTeaser = (): void => {\n const msg = optMsg?.title ? optMsg : (store.launcherMessage ?? undefined)\n const shouldShow = !!msg?.title && !open && !teaserDismissed()\n if (!shouldShow) { if (teaserEl) { teaserEl.remove(); teaserEl = null } return }\n if (teaserEl) return // already shown; don't rebuild (avoids flicker)\n teaserEl = document.createElement('div')\n teaserEl.setAttribute('role', 'button')\n teaserEl.setAttribute('tabindex', '0')\n teaserEl.setAttribute('aria-label', msg!.title)\n teaserEl.style.cssText = [\n 'max-width:280px', 'background:#fff', 'border-radius:16px',\n 'box-shadow:0 12px 32px rgba(108,92,231,.14)', 'padding:14px 40px 14px 16px',\n 'position:relative', 'cursor:pointer', 'font-family:inherit',\n `align-self:${isRight ? 'flex-end' : 'flex-start'}`,\n 'animation:ocw-teaser-in .22s ease-out',\n ].join(';')\n const title = document.createElement('div')\n title.textContent = msg!.title\n title.style.cssText = 'font-size:15px;font-weight:600;color:#111;line-height:1.35'\n teaserEl.append(title)\n if (msg!.subtitle) {\n const sub = document.createElement('div')\n sub.style.cssText = 'display:flex;align-items:center;gap:6px;margin-top:6px;font-size:13px;color:#6b7280'\n const ic = document.createElement('span'); ic.innerHTML = CHAT_MINI_SVG; ic.style.cssText = `color:${opts.accent ?? '#6c5ce7'};display:inline-flex`\n const st = document.createElement('span'); st.textContent = msg!.subtitle\n sub.append(ic, st); teaserEl.append(sub)\n }\n // Close (×) — dismiss for the session without opening the chat.\n const x = document.createElement('button')\n x.type = 'button'\n x.setAttribute('aria-label', 'Dismiss')\n x.innerHTML = '<svg viewBox=\"0 0 24 24\" width=\"14\" height=\"14\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\"><path d=\"M18 6 6 18M6 6l12 12\" stroke=\"currentColor\" stroke-width=\"2.5\" stroke-linecap=\"round\"/></svg>'\n x.style.cssText = 'position:absolute;top:8px;right:8px;width:24px;height:24px;border:none;border-radius:50%;background:#f3f4f6;color:#6b7280;cursor:pointer;display:flex;align-items:center;justify-content:center;padding:0'\n x.addEventListener('click', (e) => {\n e.stopPropagation()\n try { sessionStorage.setItem(teaserKey, '1') } catch { /* storage blocked — dismiss for this pageview only */ }\n if (teaserEl) { teaserEl.remove(); teaserEl = null }\n })\n teaserEl.append(x)\n const openFromTeaser = (): void => {\n if (open) return\n open = true; showPanel(true); paintBubble()\n unread = 0; if (badgeEl) badgeEl.style.display = 'none'\n if (teaserEl) { teaserEl.remove(); teaserEl = null }\n }\n teaserEl.addEventListener('click', openFromTeaser)\n teaserEl.addEventListener('keydown', (e) => { if (e.key === 'Enter' || e.key === ' ') { e.preventDefault(); openFromTeaser() } })\n // Insert ABOVE the button (button is the last child of launcherEl).\n launcherEl!.insertBefore(teaserEl, btn)\n }\n // Keyframes for the gentle pop-in (injected once).\n if (!document.getElementById('ocw-teaser-style')) {\n const st = document.createElement('style'); st.id = 'ocw-teaser-style'\n st.textContent = '@keyframes ocw-teaser-in{from{opacity:0;transform:translateY(8px)}to{opacity:1;transform:translateY(0)}}'\n document.head.append(st)\n }\n _paintTeaser = paintTeaser\n paintTeaser() // shows immediately when the option is set; manifest repaints later\n\n const showPanel = (show: boolean) => {\n if (show) {\n panel.style.display = 'flex'\n requestAnimationFrame(() => { panel.style.opacity = '1'; panel.style.transform = 'scale(1)' })\n } else {\n panel.style.opacity = '0'; panel.style.transform = 'scale(.95)'\n setTimeout(() => { if (!open) panel.style.display = 'none' }, 180)\n }\n }\n\n btn.addEventListener('click', () => {\n open = !open\n showPanel(open)\n paintBubble()\n if (open) {\n unread = 0; if (badgeEl) badgeEl.style.display = 'none'\n // Opening satisfies the teaser's whole purpose — retire it for the session.\n try { sessionStorage.setItem(teaserKey, '1') } catch { /* ignore */ }\n }\n _paintTeaser?.()\n })\n\n // Close on Escape. Kept as a named handler so close() can REMOVE it —\n // the old anonymous listener outlived the widget (leaked on every\n // remount/identify, and a stale one could still flip `open`).\n _escHandler = (e: KeyboardEvent) => {\n if (e.key === 'Escape' && open) { open = false; showPanel(false); paintBubble() }\n }\n document.addEventListener('keydown', _escHandler)\n }\n\n const addUnread = () => {\n if (open) return\n unread++\n if (badgeEl) { badgeEl.textContent = String(unread); badgeEl.style.display = 'flex' }\n }\n\n // ── Notification sound ────────────────────────────────────────────────────\n const playSound = () => {\n try {\n // ONE lazy shared context, resumed on each play. The old code created a\n // fresh AudioContext per message; browsers cap concurrent contexts (~6\n // in Chrome), after which construction throws and chat goes silent.\n const ctx = getAudioContext()\n if (!ctx) return\n if (ctx.state === 'suspended') void ctx.resume().catch(() => {})\n const osc = ctx.createOscillator(); const gain = ctx.createGain()\n osc.connect(gain); gain.connect(ctx.destination)\n osc.frequency.setValueAtTime(880, ctx.currentTime)\n osc.frequency.exponentialRampToValueAtTime(440, ctx.currentTime + 0.15)\n gain.gain.setValueAtTime(0.3, ctx.currentTime)\n gain.gain.exponentialRampToValueAtTime(0.001, ctx.currentTime + 0.3)\n osc.start(); osc.stop(ctx.currentTime + 0.3)\n } catch { /* audio not available */ }\n }\n\n // Messages typed before the 'opened' frame arrives are queued here and\n // flushed once cid is known. This prevents silent message loss when the\n // user types immediately after the widget mounts (before WS handshake).\n const preSendQueue: { clientMsgId: string; content: import('./protocol/index.js').MessageContent }[] = []\n\n const flushPreSendQueue = (conversationId: ConversationId) => {\n while (preSendQueue.length) {\n const item = preSendQueue.shift()!\n outbox.add({ clientMsgId: item.clientMsgId, content: item.content, ts: Date.now() })\n conn.send({ type: 'send', conversationId, clientMsgId: item.clientMsgId, content: item.content })\n }\n }\n\n let conn: ConnectionManager\n // E2E is compiled out of the 'lite' build (__E2E__=false) via dead-code\n // elimination — non-encrypted chatrooms don't ship the crypto. In the lite\n // build e2e is null and encrypted rooms are refused (never sent as plaintext).\n const e2e = __E2E__ ? new E2ESession(`ocw-e2e-${opts.profileId}`) : null\n let e2eStarted = false\n // Live ECDH pending (peer not yet online)\n const pending: { clientMsgId: string; text: string }[] = []\n // X3DH async: pending send awaiting the peer's prekey bundle\n const x3dhPending: { clientMsgId: string; text: string }[] = []\n let x3dhBundleFetched = false\n\n const sendSealed = (clientMsgId: string, text: string): void => {\n void e2e!.sealText(text).then((content) => {\n if (cid) conn.send({ type: 'send', conversationId: cid, clientMsgId, content })\n })\n }\n\n const sendSealedX3DH = (clientMsgId: string, text: string, x3dhInit: { ephemeralKey: string; spkId: string; senderIK: string; usedOTP: boolean }): void => {\n void e2e!.sealText(text, x3dhInit).then((content) => {\n if (cid) conn.send({ type: 'send', conversationId: cid, clientMsgId, content })\n })\n }\n\n const flushPending = (): void => {\n while (pending.length) { const p = pending.shift()!; sendSealed(p.clientMsgId, p.text) }\n while (x3dhPending.length) { const p = x3dhPending.shift()!; sendSealed(p.clientMsgId, p.text) }\n }\n\n /** Fetch the peer's prekey bundle and perform X3DH sender init. */\n const fetchAndX3DH = (targetUserId: string): void => {\n conn.send({ type: 'fetchPrekey', targetUserId: targetUserId as never })\n }\n\n const i18n = opts.i18n ?? {}\n // Auto-detect RTL for Arabic/Hebrew/Persian/Urdu regardless of i18n strings\n const rtlLocales = ['ar', 'he', 'fa', 'ur']\n const browserLang = typeof navigator !== 'undefined' ? (navigator.language ?? '').slice(0, 2).toLowerCase() : ''\n if (rtlLocales.includes(browserLang) && !opts.el.dir) {\n opts.el.dir = 'rtl'\n opts.el.style.fontFamily = opts.el.style.fontFamily || 'Tahoma,Arial,system-ui,sans-serif'\n }\n // Pre-chat completion is per (chatroom, identity) — a returning visitor who\n // already qualified goes straight to the composer.\n const preChatKey = `oc_prechat_${opts.profileId}_${token.slice(-8)}`\n\n const renderer = new Renderer(opts.el, token, {\n onSend(text) {\n const clientMsgId = `cm_${Math.random().toString(36).slice(2)}`\n const content: import('./protocol/index.js').MessageContent = { kind: 'text', text }\n store.addOptimistic(clientMsgId, content)\n renderer.render(store)\n if (store.e2e) {\n if (!__E2E__) {\n console.error('[relay] this chat is end-to-end encrypted — use the full widget build')\n return\n }\n if (e2e!.ready) {\n sendSealed(clientMsgId, text)\n } else if (x3dhBundleFetched) {\n x3dhPending.push({ clientMsgId, text })\n } else {\n pending.push({ clientMsgId, text })\n if (store.assignedAgentId) fetchAndX3DH(store.assignedAgentId)\n }\n } else if (!cid) {\n // Connection not yet opened — queue the message; flushed on 'opened'\n preSendQueue.push({ clientMsgId, content })\n } else {\n outbox.add({ clientMsgId, content, ts: Date.now() })\n conn.send({ type: 'send', conversationId: cid, clientMsgId, content })\n }\n },\n async onAttach(file: File) {\n if (!cid) return\n const uploadUrl = `${httpBase}/upload?name=${encodeURIComponent(file.name)}`\n const clientMsgId = `cm_${Math.random().toString(36).slice(2)}`\n // Optimistic: show uploading state\n store.addOptimistic(clientMsgId, { kind: 'text', text: `📎 Uploading ${file.name}…` })\n renderer.render(store)\n try {\n const res = await fetch(uploadUrl, {\n method: 'POST',\n // Use the resolved connection token (a signed JWT, an explicit userId,\n // or the anonymous persistent uid) — NOT just opts.token. The server\n // requires an Authorization header, and the verifier accepts an\n // anonymous id as a guest; keying off opts.token alone meant anonymous\n // visitors (the common case) sent no auth and every upload 401'd.\n headers: { 'content-type': file.type, authorization: `Bearer ${token}` },\n body: file,\n })\n if (!res.ok) throw new Error(`Upload failed: ${res.status}`)\n const { url, name, mime, size } = await res.json() as { url: string; name: string; mime: string; size: number }\n // Swap the \"📎 Uploading…\" placeholder for the REAL attachment content,\n // keyed by the SAME clientMsgId, BEFORE we send. Without this the\n // optimistic entry stayed as placeholder text: the server's `ack`\n // carries no content (see frames.ts), so reconciliation did\n // `{...msg, status:'sent'}` and kept the \"Uploading…\" text forever. The\n // real attachment only appeared on the next history fetch — i.e. after\n // a refresh — which reads exactly as \"the upload is slow\" even though\n // it already succeeded. Re-seeding here means the ack confirms an\n // attachment, and it renders immediately in the live view.\n store.addOptimistic(clientMsgId, { kind: 'attachment', url, name, mime, size })\n renderer.render(store)\n conn.send({ type: 'send', conversationId: cid, clientMsgId, content: { kind: 'attachment', url, name, mime, size } })\n } catch (e) {\n store.addOptimistic(clientMsgId, { kind: 'text', text: `⚠️ Upload failed: ${(e as Error).message}` })\n renderer.render(store)\n }\n },\n onInvoke(actionId, inputs) {\n if (!cid) return\n conn.send({ type: 'invoke', conversationId: cid, actionId, clientInvokeId: `iv_${Math.random().toString(36).slice(2)}`, ...(inputs ? { inputs } : {}) })\n },\n onTyping(isTyping, preview) { if (cid) conn.send({ type: 'typing', conversationId: cid, isTyping, ...(preview ? { preview } : {}) }) },\n onPreChat(values) {\n // Persist \"done\" per (chatroom, browser identity) so reloads skip the form.\n try { localStorage.setItem(preChatKey, '1') } catch { /* private mode */ }\n // Identity fields flow through the SAME open+userInfo path the host's\n // `user` config uses — the engine sanitizes and stores them on the\n // conversation (guestName/guestEmail; phone lands in guest meta).\n conn.send({\n type: 'open', profileId: opts.profileId as never,\n ...(opts.subjectId ? { subjectId: opts.subjectId as never } : {}),\n userInfo: {\n ...(values.name ? { name: values.name } : {}),\n ...(values.email ? { email: values.email } : {}),\n ...(values.phone || values.topic ? { meta: {\n ...(values.phone ? { phone: values.phone } : {}),\n ...(values.topic ? { topic: values.topic } : {}),\n } } : {}),\n },\n } as never)\n // Topic / callback become the visible first line so agents see the\n // qualification without opening the CRM pane. A callback request is\n // explicit and carries the number.\n const first = values.callback\n ? `📞 Call-back requested${values.phone ? `: ${values.phone}` : ''}${values.topic ? ` — ${values.topic}` : ''}`\n : values.topic ? `Topic: ${values.topic}` : ''\n // E2E rooms: identity fields still flow (userInfo above), but the\n // qualification line must not be sent as plaintext into an encrypted\n // conversation — agents see topic/phone in the CRM pane instead.\n if (first && cid && !store.e2e) {\n conn.send({ type: 'send', conversationId: cid, clientMsgId: `pc_${Math.random().toString(36).slice(2, 12)}`, content: { kind: 'text', text: first } })\n }\n },\n ...(opts.features?.deflection !== false ? {\n onDeflectQuery(q: string) {\n if (destroyed) return\n // Debounced keyword lookup against the chatroom's KB — \"was this your\n // question?\" before the first message ever sends. Fails silent: a KB\n // hiccup must never affect typing.\n clearTimeout(deflectTimer)\n const query = q.trim()\n if (query.length < 3) { renderer.hideDeflection(); return }\n deflectTimer = setTimeout(() => {\n void fetch(`${httpBase}/kb/search?profileId=${encodeURIComponent(opts.profileId)}&q=${encodeURIComponent(query.slice(0, 200))}`)\n .then(r => (r.ok ? r.json() : { articles: [] }))\n .then((d: { articles?: { id: string; title: string; answer: string }[] }) => renderer.showDeflection(d.articles ?? []))\n .catch(() => renderer.hideDeflection())\n }, 350)\n },\n } : {}),\n onReadUpTo(seq) { if (cid) conn.send({ type: 'read', conversationId: cid, seq }) },\n onLoadMore() {\n // WS fallback for E2E rooms where REST history can't be decrypted.\n // Non-E2E rooms use scroll-triggered REST pagination from restoreHistory().\n if (!cid || !store.e2e) return\n const oldest = store.messages()[0]\n if (oldest) conn.send({ type: 'history', conversationId: cid, beforeSeq: oldest.seq, limit: 20 })\n },\n onEdit(messageId, newText) {\n if (cid) conn.send({ type: 'edit', conversationId: cid, messageId: messageId as never, content: { kind: 'text', text: newText } })\n },\n onDelete(messageId) {\n if (cid) conn.send({ type: 'delete', conversationId: cid, messageId: messageId as never })\n },\n ...(opts.features?.reactions !== false ? {\n onReact(messageId: string, emoji: string, remove: boolean) {\n if (!cid) return\n conn.send({ type: 'react', conversationId: cid, messageId: messageId as never, emoji, remove })\n },\n } : {}),\n ...(opts.features?.csat !== false ? {\n onCsat(score: number) {\n if (!cid) return\n fetch(`${httpBase}/conversations/${cid}/csat`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${token}` },\n body: JSON.stringify({ score }),\n }).catch(() => {})\n },\n } : {}),\n ...(opts.translateLang ? {\n async onTranslate(text: string) {\n try {\n const res = await fetch(`${httpBase}/translate`, {\n method: 'POST',\n headers: { 'content-type': 'application/json', authorization: `Bearer ${token}` },\n body: JSON.stringify({ text, targetLang: opts.translateLang }),\n })\n if (!res.ok) return null\n const { translated } = await res.json() as { translated: string | null }\n return translated\n } catch { return null }\n },\n } : {}),\n ...(opts.onBack ? { onBack: opts.onBack } : {}),\n }, {\n ...(opts.subject ? { subject: opts.subject } : {}),\n ...(opts.quickReplies ? { quickReplies: opts.quickReplies } : {}),\n ...(opts.accent ? { accent: opts.accent } : {}),\n ...(opts.accent2 ? { accent2: opts.accent2 } : {}),\n ...(opts.theme ? { theme: opts.theme } : {}),\n ...(opts.webfont === false ? { webfont: false } : {}),\n ...(opts.user?.name || opts.user?.avatar ? { userInfo: { ...(opts.user.name ? { name: opts.user.name } : {}), ...(opts.user.avatar ? { avatar: opts.user.avatar } : {}) } } : {}),\n i18n,\n\n })\n\n // Returning visitor who already completed pre-chat → straight to composer.\n try { if (localStorage.getItem(preChatKey)) renderer.completePreChat() } catch { /* private mode */ }\n\n // Identified-user display info rides on the open frame itself: the server\n // persists it onto the conversation (sanitized) so agents see who they're\n // talking to. The previous approach — sending a `note` frame after 'opened' —\n // never worked: `note` is agent-only, so the server answered FORBIDDEN and\n // the info was silently dropped. Carrying it on `open` also means it reaches\n // the dashboard for EXISTING conversations (e.g. a visitor who logs in after\n // chatting anonymously), not just brand-new empty ones.\n const userInfo = opts.user && (opts.user.name || opts.user.email || opts.user.avatar || opts.user.meta)\n ? {\n ...(opts.user.name ? { name: opts.user.name } : {}),\n ...(opts.user.email ? { email: opts.user.email } : {}),\n ...(opts.user.avatar ? { avatar: opts.user.avatar } : {}),\n ...(opts.user.meta ? { meta: opts.user.meta } : {}),\n }\n : undefined\n\n const openFrame: Extract<ClientFrame, { type: 'open' }> = {\n type: 'open', profileId: opts.profileId as never,\n // Direct conversations use the kind/peerId pair; the dm:… subject key is\n // server-derived and owner-keyed, so passing it as subjectId from the\n // NON-owner side would find-or-create a junk duplicate thread.\n ...(opts.kind === 'direct' && opts.peerId\n ? { kind: 'direct' as const, peerId: opts.peerId as never }\n : opts.subjectId ? { subjectId: opts.subjectId as never } : {}),\n ...(linkFrom ? { linkFrom: linkFrom as never } : {}),\n ...(userInfo ? { userInfo } : {}),\n ...(typeof location !== 'undefined' ? { pageUrl: location.href } : {}),\n ...(typeof document !== 'undefined' && document.title ? { pageTitle: document.title } : {}),\n // Pass subject display info so the server can persist it to the Subject record.\n // This is how listingTitle and listingMeta get saved without a separate API call.\n ...(opts.subject?.title ? { subjectTitle: opts.subject.title } : {}),\n ...(opts.subject?.subtitle ? { subjectMeta: opts.subject.subtitle } : {}),\n }\n\n conn = new ConnectionManager({\n ...(opts.refreshToken ? { refreshToken: opts.refreshToken } : {}),\n url: wsUrl, token, open: openFrame,\n getCursor: () => store.highestSeq(),\n onStatusChange: (s, msg) => renderer.setConnStatus(s, msg),\n onFrame(frame) {\n if (frame.type === 'opened') {\n cid = frame.conversation.id\n\n // Flush persistent outbox exactly once (idempotent: items are ack-removed).\n if (!outboxRestored) {\n outboxRestored = true\n for (const item of outbox.load()) {\n conn.send({ type: 'send', conversationId: cid, clientMsgId: item.clientMsgId, content: item.content })\n }\n }\n\n // Restore history on EVERY successful open (covers reconnects too).\n // On reconnect the store still has messages in memory so this is a\n // no-op if there's nothing newer — cheap REST call, correct behaviour.\n void restoreHistory(wsUrl, token, cid, store, renderer, httpBase)\n\n // Flush any messages typed while the connection was still opening.\n if (preSendQueue.length) flushPreSendQueue(cid)\n }\n\n if (frame.type === 'ack') outbox.remove(frame.clientMsgId)\n\n // X3DH: handle incoming prekey bundle response\n if (__E2E__ && frame.type === 'prekeyBundle') {\n if (frame.bundle) {\n x3dhBundleFetched = true\n void e2e!.x3dhSendTo(frame.bundle).then((x3dhInit) => {\n // Drain any X3DH-pending messages with the derived key.\n const toSend = [...pending.splice(0), ...x3dhPending.splice(0)]\n for (const p of toSend) sendSealedX3DH(p.clientMsgId, p.text, x3dhInit)\n renderer.render(store)\n })\n }\n // If no bundle, peer has no prekeys; fall back to live ECDH queue\n return\n }\n\n // X3DH recipient: detect init message in incoming encrypted messages\n if (__E2E__ && frame.type === 'message' && store.e2e) {\n const x3dh = extractX3DHInit(frame.message.content)\n if (x3dh && !e2e!.ready) {\n void e2e!.x3dhReceiveFrom(x3dh.x3dhIK, x3dh.x3dhEK, x3dh.x3dhSPK, x3dh.x3dhOTP).then(async () => {\n // Now decrypt the message that carried the init\n await e2e!.openFrame(frame)\n store.apply(frame)\n renderer.render(store)\n })\n return\n }\n }\n\n if (__E2E__ && frame.type === 'peerkey') {\n void e2e!.onPeerKey(frame.key).then(() => { flushPending(); renderer.render(store) })\n return\n }\n void (async () => {\n if (__E2E__ && store.e2e) await e2e!.openFrame(frame)\n store.apply(frame)\n // The manifest carries the launcher teaser (defaults.launcherMessage);\n // repaint so a manifest-configured message appears over the closed launcher.\n if (frame.type === 'manifest') _paintTeaser?.()\n // Trigger badge + sound for new messages from others.\n // In chatList mode, skip the badge if the user is already in the chat\n // screen for this conversation — they can see the message immediately.\n if (frame.type === 'message' && frame.message.senderId !== (token as never) && !frame.message.internal) {\n addUnread()\n playSound()\n }\n // Once we learn the room is E2E, run the key handshake exactly once.\n if (__E2E__ && store.e2e && cid && !e2eStarted) {\n e2eStarted = true\n // Upload our prekey bundle for async E2E support.\n const prekeyPayload = await e2e!.initX3DH()\n conn.send({ type: 'uploadPrekeys', ...prekeyPayload })\n // Also do live ECDH handshake in case peer is already online.\n const liveKey = await e2e!.begin()\n conn.send({ type: 'pubkey', conversationId: cid, key: liveKey })\n }\n renderer.render(store)\n // Keep seenSeq in sync so the chat list shows accurate unread counts\n })()\n },\n })\n\n\n conn.connect()\n // Show restored 'pending' bubbles (if any) immediately, before the socket opens.\n renderer.render(store)\n\n const slot = opts.launcher ? launcherSlot(opts) : null\n const handle: WidgetHandle = { close: () => {\n destroyed = true\n clearTimeout(deflectTimer)\n conn.close(); launcherEl?.remove(); renderer.destroy()\n if (_mql && _mqlHandler) _mql.removeEventListener('change', _mqlHandler)\n if (_escHandler) { document.removeEventListener('keydown', _escHandler); _escHandler = null }\n _registry.delete(opts.el)\n if (slot && _launcherRegistry.get(slot) === handle) _launcherRegistry.delete(slot)\n } }\n _registry.set(opts.el, handle)\n if (slot) _launcherRegistry.set(slot, handle)\n return handle\n}\n\nexport { ChatStore } from './store.js'\nexport { ConnectionManager } from './connection.js'\nexport { Renderer } from './renderer.js'\nexport { asConversationId }\nexport { E2ESession, extractX3DHInit, type X3DHBundle } from './e2e.js'\nexport { PersistentOutbox, type OutboxItem } from './outbox.js'\nexport { restoreHistory, httpBaseFromWsUrl, resolveRelayUrls } from './history.js'\n\n","// Relay embed API — the paste-anywhere install path.\n//\n// A junior drops two lines into ANY page (any framework, any backend) and gets a\n// working chat launcher. Identity is optional and upgrades in one string. This\n// mirrors how Intercom / Channel.io install: a global command function with a\n// pre-load queue, plus auto-boot from a settings object.\n//\n// <script>window.relaySettings = { profileId: \"p_your_chatroom\" }</script>\n// <script async src=\"https://relay.paramms.com/embed.js\"></script>\n//\n// or, programmatically (SPAs, identity that arrives after login):\n//\n// Relay('boot', { profileId: \"p_x\" })\n// Relay('identify', { userId: user.id }) // becomes them + merges their guest history\n// Relay('update', { listingId: car.id }) // switch subject on navigation\n// Relay('shutdown') // remove the widget (e.g. on logout)\n\nimport { mount, type WidgetHandle, type MountOptions, type UserInfo } from './index.js'\n\n/** Everything an embedder can pass. All optional except `profileId`. Field\n * names DELIBERATELY mirror the React props (`ChatWidgetProps` /\n * `MarketplaceChatProps` in react.tsx) so the same mental model — and often\n * the same field names — carries over whether you're using React or a plain\n * script tag. Where a name changed over time the old one still works (see\n * the `@deprecated` notes) — this is a published package embedded on live\n * customer sites (WordPress plugin, Shopify theme block), so nothing here is\n * ever removed, only added to. */\nexport interface RelaySettings {\n /** The chatroom id (from your Relay dashboard). Required. Matches the React\n * `profileId` prop name. `appId` is the original alias — still works. */\n profileId?: string\n /** @deprecated alias for `profileId` — kept working, `profileId` is now the\n * documented name (matches React). */\n appId?: string\n /** Relay server URL. Defaults to the hosted relay; set for self-hosted. */\n url?: string\n apiUrl?: string\n /** IDENTITY (optional, tiered): `token` (a signed JWT from your backend) is the\n * secure path; `userId` (any stable string you have) is the easy path; omit\n * both for an anonymous visitor. See EMBED.md. */\n token?: string\n userId?: string\n /** Called when a signed `token` is rejected (expired): return a fresh token\n * from your backend to renew the session without a reload. Matches the\n * React `refreshToken` prop. Only usable from `window.relaySettings` /\n * `Relay('boot', ...)` (a function can't be expressed as an HTML\n * attribute) — not available via `data-relay-*`. */\n refreshToken?: () => Promise<string | null>\n /** Display info shown to agents (not identity) — matches the React\n * `userName` / `userEmail` / `userAvatar` props. */\n userName?: string\n userEmail?: string\n userAvatar?: string\n /** @deprecated flat aliases for `userName` / `userEmail` / `userAvatar` —\n * kept working (the shipped Shopify integration used these names nested\n * under `user`, see `user` below, which is the fix for that; these bare\n * top-level fields predate that and still work standalone). */\n name?: string\n email?: string\n avatar?: string\n /** Same info as `userName`/`userEmail`/`userAvatar`, as one nested object —\n * matches `MountOptions.user` / React's internal shape exactly, and is\n * what a server-rendered snippet (e.g. Shopify Liquid, WordPress PHP) will\n * most naturally emit: `user: { name: \"...\", email: \"...\" }`. Takes\n * precedence over the flat fields if both are somehow given. */\n user?: UserInfo\n /** Subject the chat is about (e.g. a marketplace listing). `listingId` is\n * sugar for `subjectId: \"listing_<id>\"`. */\n subjectId?: string\n listingId?: string\n /** Context-card fields — matches React's `ChatWidget` `contextTitle` /\n * `contextSubtitle` / `contextStatus` props (a general \"here's what this\n * conversation is about\" card: an order, ticket, booking, etc). */\n contextTitle?: string\n contextSubtitle?: string\n contextStatus?: string\n /** Marketplace-card fields — matches React's `MarketplaceChat`\n * `listingTitle` / `listingMeta` / `listingPrice` / `listingStatus` props\n * (a specific-item card: price + status badge, e.g. \"2019 Camry — $12,500\n * — Available\"). Use these OR `contextTitle`/etc — both build the same\n * card, pick whichever vocabulary matches your use case. */\n listingTitle?: string\n listingMeta?: string\n listingPrice?: number\n listingStatus?: string\n /** @deprecated original flat names for the context/marketplace card —\n * kept working. `contextTitle`/`listingTitle` are now the documented\n * names (matching the two React components). */\n subjectTitle?: string\n subjectMeta?: string\n subjectPrice?: number\n subjectStatus?: string\n /** The context/marketplace card as one nested object, if you'd rather build\n * it yourself than use the flat fields above — matches\n * `MountOptions.subject` exactly. Takes precedence over every flat field\n * above if given. */\n subject?: { title?: string; subtitle?: string; tags?: string[]; status?: string; ownerLabel?: string }\n /** Pre-set reply chips shown above the input — matches the React\n * `quickReplies` prop. `window.relaySettings` / `Relay('boot', ...)` only\n * (an array can't be expressed as a single `data-relay-*` attribute). */\n quickReplies?: string[]\n /** i18n string overrides — matches the React `i18n` prop. Same restriction\n * as `quickReplies`: object, so JS-object form only. */\n i18n?: MountOptions['i18n']\n /** Per-tenant feature switches (default all ON). Object form only. Matches\n * the React `features` prop. Set a flag false to disable that feature. */\n features?: MountOptions['features']\n /** Appearance. `launcher` defaults to true (a floating bubble). */\n accent?: string\n /** Secondary accent (guest bubble + send button). Object/attr form; follows\n * `accent` when omitted. */\n accent2?: string\n /** Colour scheme: 'auto'|'light'|'dark'. Attr: data-relay-theme. */\n theme?: 'auto' | 'light' | 'dark'\n /** Load brand webfonts (default true). Attr: data-relay-webfont=\"false\". */\n webfont?: boolean\n launcher?: boolean\n position?: 'bottom-right' | 'bottom-left'\n /** Launcher teaser (\"optional message\" above the bubble). Matches the React\n * `launcherMessage` prop exactly: a bare string (title only), or\n * `{ title, subtitle }`. `launcherSubtitle` below is a SEPARATE flat\n * field kept only so `data-relay-launcher-message` /\n * `data-relay-launcher-subtitle` (two HTML attributes — an attribute\n * can't hold a nested object) can still combine into the same shape; in\n * JS-object form just pass the object directly, same as React. Omit to\n * use the chatroom's manifest value. */\n launcherMessage?: string | { title: string; subtitle?: string }\n /** @deprecated HTML-attribute-only companion to a string `launcherMessage`\n * — see the note above. Prefer `launcherMessage: { title, subtitle }` in\n * JS-object form. */\n launcherSubtitle?: string\n translateLang?: string\n /** Mount INLINE into an existing element instead of the auto-created,\n * body-appended host that the default floating launcher uses. A CSS\n * selector string (works from `data-relay-target` too) or an element\n * reference (JS-object form only). Ignored when `launcher` is true — same\n * restriction as `height`/`inbox` below: a floating launcher panel is a\n * fixed-size popup `mount()` owns, not something you place in the page. */\n el?: string | HTMLElement\n /** Inline container height — matches the React `height` prop. Only applies\n * when `launcher` is false/omitted. */\n height?: string\n /** Adds a back-chevron to the widget that swaps it for the full\n * conversation list — matches the React `ChatWidget`/`MarketplaceChat`\n * `inbox` prop, INCLUDING its one limitation: not supported in launcher\n * mode. (React itself requires a different component, `ChatAppLauncher`,\n * for a launcher+inbox combination — same scope boundary here.) Tapping a\n * row opens that conversation; its own back-chevron returns to the list; a\n * ✕ in the list view returns to this widget's original single-thread\n * view. Requires `launcher: false`. */\n inbox?: boolean\n /** Open DIRECTLY on the conversation list instead of a single thread —\n * what you want for a dedicated \"Messages\" page. `inbox: true` alone only\n * adds a back-chevron to a single thread, so the list is reachable but\n * never the landing view; that is the right default for a widget bolted\n * onto a product page, and the wrong one for a page whose whole job is the\n * inbox. Implies `inbox`. Requires `launcher: false` (same restriction as\n * `inbox`), and `profileId` OR `tenantId`.\n *\n * With `inboxStart`, tapping a row opens that conversation and its own\n * back-chevron returns to the list. There is no ✕ — the list IS the root\n * view here, so there is nothing behind it to close back to. */\n inboxStart?: boolean\n /** Inbox scope when `inbox` is set: `'tenant'` (default) lists the user's\n * threads across ALL your chatrooms; `'profile'` limits it to this one. */\n inboxScope?: 'tenant' | 'profile'\n /** Your business id — lists the visitor's threads across ALL your chatrooms\n * without naming one, and lets \"new conversation\" open against your default\n * chatroom (the server reports it). This is the vanilla equivalent of\n * React's `<ChatApp tenantId=… />`, which has always accepted a tenant with\n * no profile; the script tag previously could not express that at all and\n * hard-required a `profileId`.\n *\n * Only meaningful with `inboxStart` — a single-thread widget still needs a\n * `profileId`, because a lone thread has to belong to a specific chatroom. */\n tenantId?: string\n}\n\nconst DEFAULT_URL = 'wss://api.paramms.com/ws'\n\nfunction toMountOptions(s: RelaySettings, el: HTMLElement): MountOptions {\n const profileId = s.profileId ?? s.appId\n if (!profileId) throw new Error(\"Relay: `profileId` is required (your chatroom id, e.g. 'p_...').\")\n const subjectId = s.subjectId ?? (s.listingId ? `listing_${s.listingId}` : undefined)\n const launcher = s.launcher ?? true\n\n // Subject/context card: an explicit nested `subject` wins (it's the most\n // direct match for MountOptions.subject — e.g. what a Liquid/PHP template\n // naturally emits); otherwise build it from whichever flat vocabulary was\n // used — contextTitle (ChatWidget-style), listingTitle (MarketplaceChat-\n // style), or the original subjectTitle — checked in that order.\n const title = s.contextTitle ?? s.listingTitle ?? s.subjectTitle\n const subtitle = s.contextSubtitle ?? s.listingMeta ?? s.subjectMeta\n const status = s.contextStatus ?? s.listingStatus ?? s.subjectStatus\n const price = s.listingPrice ?? s.subjectPrice\n const builtSubject = title ? {\n title,\n ...(subtitle ? { subtitle } : {}),\n ...(price != null ? { tags: [`$${price.toLocaleString()}`] } : {}),\n ...(status ? { status } : {}),\n } : undefined\n const subject = s.subject ?? builtSubject\n\n // Display info: an explicit nested `user` wins (matches MountOptions.user\n // directly — what Shopify/WordPress-style server templates naturally emit);\n // otherwise build it from userName/userEmail/userAvatar, falling back to\n // the original flat name/email/avatar.\n const uName = s.userName ?? s.name\n const uEmail = s.userEmail ?? s.email\n const uAvatar = s.userAvatar ?? s.avatar\n const builtUser = (uName || uEmail || uAvatar) ? {\n ...(uName ? { name: uName } : {}),\n ...(uEmail ? { email: uEmail } : {}),\n ...(uAvatar ? { avatar: uAvatar } : {}),\n } : undefined\n const user = s.user ?? builtUser\n\n // Launcher teaser: an object form (JS-object install) passes straight\n // through, matching the React `launcherMessage` prop exactly. A bare string\n // combines with the separate `launcherSubtitle` field ONLY needed for\n // `data-relay-*` attributes (an HTML attribute can't hold a nested object).\n const launcherMessage = s.launcherMessage && typeof s.launcherMessage === 'object'\n ? s.launcherMessage\n : s.launcherMessage\n ? (s.launcherSubtitle ? { title: s.launcherMessage, subtitle: s.launcherSubtitle } : s.launcherMessage)\n : undefined\n\n return {\n el,\n url: s.url ?? DEFAULT_URL,\n profileId,\n ...(s.apiUrl ? { apiUrl: s.apiUrl } : {}),\n ...(subjectId ? { subjectId } : {}),\n ...(s.token ? { token: s.token } : {}),\n ...(s.refreshToken ? { refreshToken: s.refreshToken } : {}),\n ...(s.userId ? { userId: s.userId } : {}),\n ...(subject ? { subject } : {}),\n ...(user ? { user } : {}),\n ...(s.quickReplies ? { quickReplies: s.quickReplies } : {}),\n ...(s.i18n ? { i18n: s.i18n } : {}),\n ...(s.features ? { features: s.features } : {}),\n ...(s.accent ? { accent: s.accent } : {}),\n ...(s.accent2 ? { accent2: s.accent2 } : {}),\n ...(s.theme ? { theme: s.theme } : {}),\n ...(s.webfont === false ? { webfont: false } : {}),\n ...(s.translateLang ? { translateLang: s.translateLang } : {}),\n ...(launcherMessage ? { launcherMessage } : {}),\n // Inbox (inline only — matches React exactly, including its one limit:\n // launcher mode has no `inbox`, that's a separate component there too).\n ...(inboxEnabled(s) && !launcher ? { onBack: () => { showInboxList = true; listIsRoot = false; remount(current) } } : {}),\n launcher,\n position: s.position ?? 'bottom-right',\n }\n}\n\nlet handle: WidgetHandle | null = null\nlet hostEl: HTMLElement | null = null\n/** True when `hostEl` is an element the HOST PAGE owns (via `el`/`data-relay-target`)\n * rather than one we created — we never remove or take full ownership of it,\n * only mount into and clear it. */\nlet externalHost = false\nlet current: RelaySettings = {}\n/** Mirrors React's `showInbox` state: true while the inline widget is showing\n * the full conversation list (reached via the single thread's back-chevron)\n * instead of its own single thread. Reset to false on a fresh `boot`;\n * preserved across `update` (so identify/navigation while browsing the inbox\n * doesn't silently kick the visitor out of it — matches how ChatApp reacts\n * to prop changes without unmounting in React). */\nlet showInboxList = false\n/** True when the list is the ROOT view (`inboxStart`) rather than somewhere we\n * navigated to from a single thread. Drives whether the ✕ (\"back to the\n * original thread\") is offered at all — with no thread behind it, a ✕ would\n * close to nothing. */\nlet listIsRoot = false\n\n/** Inline inbox is enabled by either flag; `inboxStart` implies `inbox`. */\nfunction inboxEnabled(s: RelaySettings): boolean { return !!(s.inbox || s.inboxStart) }\n/** Cleanup for whatever `mountInboxStack` currently has mounted, so switching\n * back to the single-thread view (or shutting down) leaves the host clean. */\nlet inboxTeardown: (() => void) | null = null\n\nfunction ensureHost(s: RelaySettings, launcher: boolean): HTMLElement {\n const wantsExternal = !launcher && !!s.el\n // No longer targeting a page-owned element (launcher mode now, or `el`\n // cleared/unset since the last mount) — release it. We never remove it (we\n // don't own it), just stop treating it as ours so the auto-create path\n // below takes over. Safe to blank its contents here: by the time\n // ensureHost() runs, remount() has already closed whatever was live\n // (handle / inbox stack), so nothing is orphaned mid-connection.\n if (externalHost && !wantsExternal) {\n hostEl!.innerHTML = ''\n hostEl = null\n externalHost = false\n }\n // A target only applies inline — a floating launcher panel is a fixed popup\n // mount() owns, not something placed at a point in the page.\n if (wantsExternal) {\n const resolved = typeof s.el === 'string' ? document.querySelector(s.el) : s.el\n if (resolved instanceof HTMLElement) {\n if (hostEl && hostEl !== resolved && !externalHost) hostEl.remove() // drop any previously auto-created host\n hostEl = resolved\n externalHost = true\n } else {\n console.error(`[Relay] \\`el\\` (\"${String(s.el)}\") did not match any element — falling back to an auto-created host.`)\n }\n }\n if (!hostEl || (!externalHost && !hostEl.isConnected)) {\n hostEl = document.createElement('div')\n hostEl.id = 'relay-widget-root'\n document.body.appendChild(hostEl)\n externalHost = false\n }\n if (!launcher && s.height) {\n hostEl.style.height = s.height\n if (!hostEl.style.width) hostEl.style.width = '100%'\n }\n return hostEl\n}\n\nfunction remount(s: RelaySettings): void {\n try {\n const launcher = s.launcher ?? true\n // Always tear down whatever's currently mounted FIRST, before host\n // resolution — otherwise a host-target/launcher-mode switch can leave a\n // live socket (single-thread OR inbox list/thread) attached to DOM that\n // ensureHost() is about to blank or abandon underneath it.\n inboxTeardown?.(); inboxTeardown = null\n handle?.close(); handle = null\n\n const host = ensureHost(s, launcher)\n if (inboxEnabled(s) && !launcher && showInboxList) {\n void mountInboxStack(s, host)\n return\n }\n handle = mount(toMountOptions(s, host))\n } catch (e) {\n // Never throw into the host page — a misconfigured embed logs and no-ops.\n console.error('[Relay]', e instanceof Error ? e.message : e)\n }\n}\n\n/** The inbox stack (inline, `inbox: true`, back-chevron reached): a list pane\n * and a thread pane sharing one host, plus a ✕ that returns to the widget's\n * ORIGINAL single-thread view. This is deliberately the vanilla equivalent\n * of React's `<ChatApp>` used internally by `ChatWidget`'s `inbox` prop — two\n * ALREADY-BUILT, already-shared engines (`mount()` for a thread,\n * `mountChatList()` for the list, both used by the dashboard too) wired\n * together, not a new chat engine. `mountChatList` is imported dynamically\n * for code clarity (keeps this module's structure matching its own\n * `chatlist.ts` boundary) — NOTE this is NOT a bundle-size optimization here:\n * `vite.embed.config.ts` builds `embed.js` as a single IIFE with no chunk\n * splitting, so it gets inlined regardless of whether `inbox` is ever used\n * (confirmed: embed.js grew ~100KB→114KB, ~4KB gzipped, after this change).\n * A real lazy-load would need a different bundle format for embed.js — out\n * of scope here, flagged in the roadmap as a minor follow-up. */\nasync function mountInboxStack(s: RelaySettings, host: HTMLElement): Promise<void> {\n const profileId = s.profileId ?? s.appId\n // A tenant-level inbox needs no chatroom: the list spans all of them and the\n // server reports which one \"new conversation\" should open against. Matches\n // React's <ChatApp tenantId=… /> exactly.\n if (!profileId && !s.tenantId) {\n console.error('[Relay] `inbox` requires `profileId` or `tenantId`.')\n return\n }\n\n host.innerHTML = ''\n const wrap = document.createElement('div')\n wrap.style.cssText = 'position:relative;width:100%;height:100%;overflow:hidden;background:#fff'\n const listPane = document.createElement('div')\n listPane.style.cssText = 'position:absolute;inset:0'\n const threadPane = document.createElement('div')\n threadPane.style.cssText = 'position:absolute;inset:0;display:none'\n const closeBtn = document.createElement('button')\n closeBtn.type = 'button'\n closeBtn.setAttribute('aria-label', 'Close')\n closeBtn.textContent = '✕'\n closeBtn.style.cssText = 'position:absolute;top:8px;right:8px;z-index:20;width:32px;height:32px;border-radius:50%;'\n + 'display:flex;align-items:center;justify-content:center;background:rgba(0,0,0,.05);border:none;'\n + 'color:#1c1b1a;font-size:16px;line-height:1;cursor:pointer'\n // ✕ = leave the inbox stack entirely, back to the ORIGINAL single-thread\n // view (mirrors ChatApp's onClose, wired by ChatWidget to setShowInbox(false)).\n closeBtn.onclick = () => { showInboxList = false; remount(current) }\n wrap.append(listPane, threadPane)\n // ...but only when there IS a thread behind the list to go back to. With\n // `inboxStart` the list is the root view, so a ✕ would close to nothing —\n // and with a tenant-only config there is no single thread to construct at\n // all (`toMountOptions` would throw on the missing profileId).\n const canCloseToThread = !listIsRoot && !!profileId\n if (canCloseToThread) wrap.append(closeBtn)\n host.appendChild(wrap)\n\n let listHandle: import('./chatlist.js').ChatListHandle | null = null\n let threadHandle: WidgetHandle | null = null\n // Set BEFORE the await below: if shutdown() (or a superseding remount())\n // runs while the dynamic import is still in flight, there must already be\n // a way to clean up the synchronously-created `wrap` — otherwise, for an\n // EXTERNAL host (never `.remove()`d), it would sit there orphaned forever.\n // The closure reads `threadHandle`/`listHandle` at CALL time, so it's still\n // correct once they're actually assigned below.\n inboxTeardown = () => { threadHandle?.close(); listHandle?.close(); host.innerHTML = '' }\n\n // A failed dynamic import used to reject into nothing: the promise had no\n // catch, so the host page got a silent blank box and only an unhandled\n // rejection in the console. Say what happened, in the box the visitor is\n // looking at.\n let mountChatList: typeof import('./chatlist.js').mountChatList\n try {\n ({ mountChatList } = await import('./chatlist.js'))\n } catch (e) {\n console.error('[Relay] could not load the conversation list module.', e)\n if (listPane.isConnected) {\n listPane.style.cssText += ';display:flex;align-items:center;justify-content:center;'\n + 'padding:16px;font:13px system-ui;color:#b91c1c;text-align:center'\n listPane.textContent = 'Could not load conversations.'\n }\n return\n }\n type Entry = import('./chatlist.js').ChatListEntry\n // The dynamic import is async: if the stack was torn down (shutdown, or a\n // subsequent remount already cleared `host`) before it resolved, bail —\n // same guard React's own async effect uses (a `cancelled` flag there).\n if (!listPane.isConnected) return\n\n const openThread = (entry: Entry): void => {\n // Rows always carry their own chatroom and compose always sets one, so a\n // missing chatroom here means a malformed row rather than a normal state —\n // and with a tenant-only config there is no fallback to reach for. Refuse\n // loudly instead of mounting a thread against nothing.\n const roomId = entry.profileId ?? profileId\n if (!roomId) { console.error('[Relay] conversation row has no chatroom; cannot open it.', entry); return }\n closeBtn.style.display = 'none' // hidden while a thread is shown — matches React (`onClose && !selected`)\n threadHandle?.close()\n threadHandle = mount({\n el: threadPane,\n url: s.url ?? DEFAULT_URL,\n ...(s.apiUrl ? { apiUrl: s.apiUrl } : {}),\n profileId: roomId,\n // DM rows only open correctly via kind+peerId (their subjectId only\n // resolves for the participant that owns the thread key) — same\n // handling ChatApp itself uses.\n ...(entry.kind === 'direct' && entry.peerId\n ? { kind: 'direct' as const, peerId: entry.peerId }\n : entry.subjectId ? { subjectId: entry.subjectId } : {}),\n ...(s.token ? { token: s.token } : {}),\n ...(s.refreshToken ? { refreshToken: s.refreshToken } : {}),\n ...(s.userId ? { userId: s.userId } : {}),\n ...(s.userId || s.userName || s.userEmail || s.userAvatar ? {\n user: {\n ...(s.userName ? { name: s.userName } : {}),\n ...(s.userEmail ? { email: s.userEmail } : {}),\n ...(s.userAvatar ? { avatar: s.userAvatar } : {}),\n },\n } : {}),\n ...(entry.subjectTitle ? {\n subject: { title: entry.subjectTitle, ...(entry.subjectMeta ? { subtitle: entry.subjectMeta } : {}) },\n } : {}),\n ...(s.accent ? { accent: s.accent } : {}),\n launcher: false,\n // Row's own back-chevron: return to the LIST (not the original single\n // thread — that needs the ✕ above), matching ChatApp's setSelected(null).\n onBack: () => {\n threadHandle?.close(); threadHandle = null\n threadPane.style.display = 'none'\n listPane.style.display = ''\n closeBtn.style.display = '' // visible again now that the list is showing\n listHandle?.refresh() // reflects what just happened (read state, preview)\n },\n })\n listPane.style.display = 'none'\n threadPane.style.display = ''\n }\n\n listHandle = mountChatList({\n el: listPane,\n url: s.url ?? DEFAULT_URL,\n ...(s.apiUrl ? { apiUrl: s.apiUrl } : {}),\n ...(profileId ? { profileId } : {}),\n ...(s.tenantId ? { tenantId: s.tenantId } : {}),\n scope: s.inboxScope ?? 'tenant',\n // Only when the ✕ is actually drawn (see canCloseToThread) — otherwise the\n // reserved gap would be empty space for no reason.\n ...(canCloseToThread ? { reserveCloseSpace: true } : {}),\n onSelect: openThread,\n // ✎ compose: open a fresh thread against this widget's own chatroom when\n // one is configured; with a tenant-only config, against the server-reported\n // default (the tenant's oldest chatroom), exactly like <ChatApp/>. That\n // default only exists after the first successful fetch, so bail quietly\n // until then rather than opening a thread with no chatroom.\n onNewChat: () => {\n const target = profileId ?? listHandle?.defaultProfileId()\n if (!target) return\n openThread({ id: '__new__', profileId: target, state: 'open', updatedAt: Date.now() })\n },\n ...(s.token ? { token: s.token } : {}),\n ...(s.userId ? { userId: s.userId } : {}),\n ...(s.accent ? { accent: s.accent } : {}),\n })\n}\n\n/** Mount (or re-mount) with a fresh set of settings. */\nfunction boot(s: RelaySettings): void {\n // `inboxStart` lands ON the list. `inbox` alone still lands on the single\n // thread (the list is behind its back-chevron) — unchanged, because that is\n // what every currently-deployed embed expects.\n listIsRoot = !!(s.inboxStart && !(s.launcher ?? true))\n showInboxList = listIsRoot\n current = { ...s }\n remount(current)\n}\n\n/** Merge new settings over the current ones and re-mount. Used for identify\n * (add a userId after login) and navigation (switch listingId). Preserves\n * `showInboxList` — identify/navigation shouldn't silently kick a visitor\n * out of the inbox they're currently browsing. */\nfunction update(s: RelaySettings): void {\n current = { ...current, ...s }\n remount(current)\n}\n\n/** Tear the widget down completely (e.g. on logout). */\nfunction shutdown(): void {\n inboxTeardown?.(); inboxTeardown = null\n handle?.close(); handle = null\n if (hostEl && !externalHost) hostEl.remove()\n hostEl = null; externalHost = false\n showInboxList = false\n listIsRoot = false\n current = {}\n}\n\nexport type RelayCommand = 'boot' | 'update' | 'identify' | 'shutdown'\n\n/** The public command dispatcher exposed as `window.Relay`. */\nexport function Relay(command: RelayCommand | string, arg?: unknown): void {\n switch (command) {\n case 'boot': boot((arg ?? {}) as RelaySettings); break\n case 'update':\n case 'identify': update((arg ?? {}) as RelaySettings); break // identify == update with a userId\n case 'shutdown': shutdown(); break\n default: console.warn('[Relay] unknown command:', command)\n }\n}\n\n/** Read settings from a `<script data-relay-app=\"p_x\">` (or\n * `data-relay-profile-id=\"p_x\"`, same thing) tag — the zero-JavaScript\n * install: every field here is a plain string/number, so it's exactly what a\n * server template (WordPress/Shopify/Liquid/PHP/ERB) can drop straight into\n * an attribute without writing any script. Fields that need a nested object,\n * an array, or a function (`user`, `subject`, `quickReplies`, `i18n`,\n * `refreshToken`) have NO attribute form — those need the JS-object install\n * (`window.relaySettings` / `Relay('boot', ...)`) instead. */\nfunction readDataAttrs(): RelaySettings | null {\n if (typeof document === 'undefined') return null\n const s = (document.querySelector('script[data-relay-app]')\n ?? document.querySelector('script[data-relay-profile-id]')\n // An inbox page names a business, not a chatroom — that tag has neither of\n // the two attributes above, so it needs its own lookup or it is invisible\n // to the zero-JS install path.\n ?? document.querySelector('script[data-relay-tenant-id]')) as HTMLElement | null\n const d = s?.dataset\n const app = d?.['relayApp'] ?? d?.['relayProfileId']\n const tenant = d?.['relayTenantId']\n // A tenant-only tag is valid for an inbox page (no chatroom to name).\n if (!app && !tenant) return null\n const out: RelaySettings = app ? { profileId: app } : {}\n if (tenant) out.tenantId = tenant\n if (d!['relayUser']) out.userId = d!['relayUser']\n if (d!['relayToken']) out.token = d!['relayToken']\n if (d!['relayListing']) out.listingId = d!['relayListing']\n if (d!['relayAccent']) out.accent = d!['relayAccent']\n if (d!['relayAccent2']) out.accent2 = d!['relayAccent2']\n if (d!['relayTheme']) out.theme = d!['relayTheme'] as 'auto'|'light'|'dark'\n if (d!['relayWebfont'] === 'false') out.webfont = false\n if (d!['relayUrl']) out.url = d!['relayUrl']\n const pos = d!['relayPosition']\n if (pos === 'bottom-left' || pos === 'bottom-right') out.position = pos\n if (d!['relayLauncherMessage']) out.launcherMessage = d!['relayLauncherMessage']\n if (d!['relayLauncherSubtitle']) out.launcherSubtitle = d!['relayLauncherSubtitle']\n if (d!['relayLauncher'] === 'false') out.launcher = false\n // Display info — matches userName/userEmail/userAvatar in the JS-object form.\n if (d!['relayUserName']) out.userName = d!['relayUserName']\n if (d!['relayUserEmail']) out.userEmail = d!['relayUserEmail']\n if (d!['relayUserAvatar']) out.userAvatar = d!['relayUserAvatar']\n // Context/listing card — either vocabulary, matching the JS-object form.\n if (d!['relayContextTitle']) out.contextTitle = d!['relayContextTitle']\n if (d!['relayContextSubtitle']) out.contextSubtitle = d!['relayContextSubtitle']\n if (d!['relayContextStatus']) out.contextStatus = d!['relayContextStatus']\n if (d!['relayListingTitle']) out.listingTitle = d!['relayListingTitle']\n if (d!['relayListingMeta']) out.listingMeta = d!['relayListingMeta']\n if (d!['relayListingPrice']) out.listingPrice = Number(d!['relayListingPrice'])\n if (d!['relayListingStatus']) out.listingStatus = d!['relayListingStatus']\n // Inline placement/sizing/inbox — all plain strings, so all attribute-safe.\n if (d!['relayTarget']) out.el = d!['relayTarget']\n if (d!['relayHeight']) out.height = d!['relayHeight']\n if (d!['relayInbox'] === 'true') out.inbox = true\n if (d!['relayInbox'] === 'false') out.inbox = false\n if (d!['relayInboxStart'] === 'true') out.inboxStart = true\n if (d!['relayInboxStart'] === 'false') out.inboxStart = false\n const scope = d!['relayInboxScope']\n if (scope === 'tenant' || scope === 'profile') out.inboxScope = scope\n\n // Translation: ISO code of the language to auto-translate INCOMING messages\n // into (shows a 🌐 button per message). The interface and mount path already\n // supported translateLang for React and JS config; the zero-JS script-tag\n // path could not set it at all until this line — a field-parity gap.\n if (d!['relayTranslateLang']) out.translateLang = d!['relayTranslateLang']\n return out\n}\n\n// ── Install: take over the loader stub's queue, then replay it ───────────────\n// The paste-in loader defines `window.Relay` as a queue so calls made before\n// this script finishes loading aren't lost. We swap in the real dispatcher and\n// flush anything queued, then auto-boot from `window.relaySettings` OR a\n// `data-relay-app` script attribute if the embedder never called boot() — the\n// two zero-JS install paths.\ntype Queue = { q?: IArguments[] }\ntype Win = typeof window & { Relay?: ((...a: unknown[]) => void) & Queue; relaySettings?: RelaySettings }\n\nif (typeof window !== 'undefined') {\n const w = window as Win\n const queued: IArguments[] = (w.Relay && w.Relay.q) ? w.Relay.q : []\n w.Relay = Relay as ((...a: unknown[]) => void) & Queue\n\n let explicitBoot = false\n for (const call of queued) {\n const [cmd, arg] = call as unknown as [string, unknown]\n if (cmd === 'boot') explicitBoot = true\n Relay(cmd, arg)\n }\n if (!explicitBoot) {\n const auto = w.relaySettings ?? readDataAttrs()\n if (auto) boot(auto)\n }\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:not([data-theme=\"light\"]) { ${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; color:var(--ocl-accent); }\n.ocl-title svg { width:24px; height:24px; display:block; }\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:not([data-theme=\"light\"]) .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","/**\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// Inline, dependency-free chat-bubble glyph. `currentColor` picks up the\n// header's accent tint. No external font/emoji so it renders identically\n// across platforms (the old '💬'/text wordmark varied per-OS).\nconst CHAT_ICON_SVG =\n '<svg viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\" aria-hidden=\"true\">' +\n '<path d=\"M21 11.5a8.38 8.38 0 0 1-.9 3.8 8.5 8.5 0 0 1-7.6 4.7 8.38 8.38 0 0 1-3.8-.9L3 21l1.9-5.7a8.38 8.38 0 0 1-.9-3.8 8.5 8.5 0 0 1 4.7-7.6 8.38 8.38 0 0 1 3.8-.9h.5a8.48 8.48 0 0 1 8 8v.5z\" ' +\n 'fill=\"currentColor\" fill-opacity=\"0.12\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/></svg>'\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 if (opts.theme && opts.theme !== 'auto') root.dataset.theme = opts.theme\n if (opts.reserveCloseSpace) root.classList.add('ocl-has-close')\n const head = el('div', 'ocl-head')\n // Header shows a chat icon (accent-tinted) rather than a \"Messages\" wordmark.\n // The i18n title is still exposed as the accessible label for screen readers.\n const titleEl = el('span', 'ocl-title')\n titleEl.setAttribute('role', 'img')\n titleEl.setAttribute('aria-label', i18n.title ?? 'Messages')\n titleEl.innerHTML = CHAT_ICON_SVG\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":["KEY","readCookie","name","m","writeCookie","value","secure","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","data","__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","i","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","e","MORE_DATA","sharedCachedKeyDecoder","Decoder","remainingData","newData","posToShow","stream","decoded","headByte","totalPos","isArray","isArrayHeaderRequired","arrayItemsLeft","DECODE","stack","headerOffset","_a","headOffset","extType","CLIENT_FRAME_TYPES","isClientFrame","frame","encodeFrame","mpEncode","decodeFrame","mpDecode","ChatStore","me","a","b","ap","bp","clientMsgId","content","msg","confirmed","reactions","users","u","uptoSeq","status","targetRank","rank","changed","k","s","ConnectionManager","opts","_b","sock","defaultFactory","ev","FATAL_ERRORS","_d","_c","fresh","friendlyError","conversationId","pending","f","cap","base","max","delay","code","url","MAX_ITEMS","MAX_AGE_MS","PersistentOutbox","token","raw","items","cutoff","subtle","b64encode","buf","b64decode","bin","out","generateKeyPair","kp","exportPublicKey","importPeerPublicKey","b64","deriveSharedKey","privateKey","peerPublicKeyB64","peer","encrypt","plaintext","iv","ct","decrypt","plain","loadOrCreateKeyPair","storageKey","pub","priv","publicKey","signPrekey","signingPrivateKey","spkPublicKey","spkRaw","sig","generateIdentityKeyPair","ecdhKP","ecdsaKP","loadOrCreateIdentityKeyPair","d","ecdhPub","ecdhPriv","ecdsaPub","ecdsaPriv","ikp","x3dhSend","senderIK","recipientBundle","ek","epkB64","ik_r","spk_r","opk_r","dh1","rawDH","dh2","dh3","dh4","ikm","concatBuffers","hkdfDeriveKey","x3dhReceive","recipientIK","recipientSPK","senderIKb64","ephemeralKeyB64","recipientOPK","ik_s","ek_s","bufs","total","n","ikmKey","OTP_BATCH_SIZE","E2ESession","peerKeyB64","signedPrekeyPub","signature","oneTimePrekeys","bundle","sharedKey","ephemeralPublicKey","spkId","usedOTP","otp","ephemeralKey","text","x3dhInit","extractX3DHInit","c","LIGHT","DARK","FB","vars","prefix","t","v","lightTokens","darkTokens","CSS","STYLE_ID","REACTION_EMOJIS","COMPACT_BREAKPOINT","SEND_ICON_SVG","injectStyles","FONT_ID","injectFonts","l","el","tag","cls","fmtTime","ts","contentText","Renderer","root","h","cfg","accent2","head","back","avatarEl","img","hm","_e","_f","_g","typingBubble","q","_h","sendBtn","sendLabel","_i","attachBtn","fileInput","inputRow","footer","_j","_k","ta","applyCompact","w","entries","fn","sh","preview","store","ownerLabel","actions","prevScrollHeight","prevScrollTop","sentinel","maxOther","prevSender","showLabel","typingNames","bubble","guestHasSpoken","copy","terminalStates","isTerminal","note","fatal","form","inputs","inp","topicSel","ph","o","callbackCb","phoneForCb","row","submit","email","callback","phone","articles","card","stars","btns","bb","idx","title","tags","btn","label","resolve","overlay","cancel","ok","close","panel","sel","opt","sys","mine","isNote","col","who","bubbleWrap","replyCtx","textNode","links","gLink","iLink","original","translateBtn","cached","menu","editBtn","saveBtn","cancelBtn","btnRow","editPanel","restore","newText","ke","delBtn","reactWrap","reactRow","emoji","pill","addBtn","picker","pb","alreadyReacted","opening","meta","tick","PAGE","resolveRelayUrls","input","apiBaseOverride","trimmed","scheme","authorityAndPath","httpBase","httpBaseFromWsUrl","wsUrl","historyUrl","beforeSeq","limit","qs","fetchPage","lastError","sawResponse","res","restoreHistory","renderer","apiBase","page","loading","loadOlder","oldest","page2","scrollEl","armed","onScroll","_registry","_launcherRegistry","launcherSlot","_audioCtx","getAudioContext","mount","anonId","deflectTimer","destroyed","linkFrom","outboxKey","outbox","cid","outboxRestored","_mql","_mqlHandler","_escHandler","_paintTeaser","launcherEl","badgeEl","unread","open","isRight","mql","applyPanelLayout","mobile","mqlHandler","CHAT_SVG","CLOSE_SVG","paintBubble","teaserKey","optMsg","teaserEl","teaserDismissed","CHAT_MINI_SVG","paintTeaser","sub","ic","st","x","openFromTeaser","showPanel","show","addUnread","playSound","ctx","osc","gain","preSendQueue","flushPreSendQueue","conn","e2e","e2eStarted","x3dhPending","x3dhBundleFetched","sendSealed","sendSealedX3DH","flushPending","p","fetchAndX3DH","targetUserId","i18n","rtlLocales","browserLang","preChatKey","file","uploadUrl","mime","actionId","isTyping","first","query","r","seq","messageId","remove","score","translated","userInfo","openFrame","toSend","x3dh","prekeyPayload","liveKey","slot","handle","DEFAULT_URL","toMountOptions","profileId","subjectId","launcher","subtitle","price","builtSubject","subject","uName","uEmail","uAvatar","builtUser","user","launcherMessage","inboxEnabled","showInboxList","listIsRoot","remount","current","hostEl","externalHost","inboxTeardown","ensureHost","wantsExternal","resolved","host","mountInboxStack","wrap","listPane","threadPane","closeBtn","canCloseToThread","listHandle","threadHandle","mountChatList","chatlist","openThread","entry","roomId","target","boot","update","shutdown","Relay","command","arg","readDataAttrs","app","tenant","scope","queued","explicitBoot","call","cmd","auto","statusChip","timeAgo","days","CHAT_ICON_SVG","accent","titleEl","compose","searchWrap","searchIn","body","compactObserver","serverDefaultProfileId","seenKey","seenSeq","saveSeenSeq","allEntries","fetchEntries","headers","renderRows","filtered","rowName","empty","start","isUnread","read","buildRow","initial","lastSeq","unreadCount","av","info","stateMap","right","chip","refresh","errBox","retry","reconnectTimer","refreshTimer","attempt","connectedBefore","debouncedRefresh","connectInbox","scheduleReconnect"],"mappings":"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","x_google_ignoreList":[1,2,3,4,5,6,7,8,9,10,11,12,13]}
1
+ {"version":3,"file":"embed.js","sources":["../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/store.ts","../src/connection.ts","../src/outbox.ts","../src/crypto.ts","../src/e2e.ts","../src/theme-tokens.ts","../src/renderer.styles.ts","../src/renderer.ts","../src/history.ts","../src/index.ts","../src/embed.ts","../src/chatlist.styles.ts","../src/chatlist.ts"],"sourcesContent":["/** 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","import type {\n ServerFrame, Message, ManifestAction, MessageContent,\n ConversationId, MessageId, UserId, Subject,\n} from './protocol/index.js'\n\nexport type SendStatus = 'pending' | 'sent' | 'delivered' | 'read'\n\nexport interface RenderMessage extends Message {\n clientMsgId?: string\n status?: SendStatus\n}\n\n/** Pure, DOM-free conversation state. Feed it ServerFrames (and local optimistic\n * sends); read an ordered, de-duplicated view out. Ordering is by `seq`; the\n * same message arriving twice (live + sync on reconnect) is collapsed by id —\n * the structural fix for the old duplicate-bubble bug. */\nexport class ChatStore {\n conversationId?: ConversationId\n state = ''\n version = 0\n hasMoreHistory = false\n lastReadByOthers = 0\n assignedAgentId: UserId | undefined\n accent: string | undefined\n subject: Subject | undefined\n name: string | undefined\n e2e = false\n offline = false\n offlineMessage = ''\n launcherMessage: { title: string; subtitle?: string } | null = null\n preChat: import('./protocol/frames.js').PreChatConfig | null = null\n whiteLabel = false\n readonly typing = new Set<string>()\n readonly online = new Set<string>()\n /** Live sentiment of the guest's latest message (agent-side only). */\n sentiment: 'positive' | 'neutral' | 'frustrated' | undefined\n sentimentScore: number | undefined\n\n private actions: ManifestAction[] = []\n private readonly byId = new Map<string, RenderMessage>()\n private readonly keyByClient = new Map<string, string>()\n private _maxSeq = 0\n private _sorted: RenderMessage[] | null = null\n\n constructor(private readonly me: UserId) {}\n\n messages(): RenderMessage[] {\n if (!this._sorted) {\n this._sorted = [...this.byId.values()].sort((a, b) => {\n const ap = a.status === 'pending', bp = b.status === 'pending'\n if (ap !== bp) return ap ? 1 : -1\n if (ap && bp) return a.ts - b.ts\n return a.seq - b.seq\n })\n }\n return this._sorted\n }\n\n visibleActions(): ManifestAction[] {\n return this.actions.filter(a => !a.availableInStates || a.availableInStates.includes(this.state))\n }\n\n highestSeq(): number { return this._maxSeq }\n\n addOptimistic(clientMsgId: string, content: MessageContent): RenderMessage {\n const msg: RenderMessage = {\n id: clientMsgId as MessageId, conversationId: this.conversationId as ConversationId,\n seq: 0, senderId: this.me, senderRole: 'guest', content, ts: Date.now(),\n clientMsgId, status: 'pending',\n }\n this.byId.set(clientMsgId, msg)\n this.keyByClient.set(clientMsgId, clientMsgId)\n this._sorted = null\n return msg\n }\n\n apply(frame: ServerFrame): void {\n switch (frame.type) {\n case 'opened':\n this.conversationId = frame.conversation.id\n this.state = frame.conversation.state\n if (frame.subject) this.subject = frame.subject\n return\n case 'manifest':\n this.actions = frame.actions\n this.version = frame.version\n if (frame.name) this.name = frame.name\n if (frame.theme?.accent) this.accent = frame.theme.accent\n if (frame.e2e) this.e2e = true\n // Track the manifest EXACTLY: a sticky `offline` (only ever set, never\n // cleared) kept the widget in away-mode for the whole session once a\n // single manifest said so — which used to hide the composer entirely.\n this.offline = frame.offline === true\n this.offlineMessage = frame.offlineMessage ?? ''\n if (frame.launcherMessage) this.launcherMessage = frame.launcherMessage\n if (frame.whiteLabel) this.whiteLabel = true\n if (frame.preChat) this.preChat = frame.preChat\n return\n case 'message':\n this.upsert({ ...frame.message })\n return\n case 'ack': {\n const key = this.keyByClient.get(frame.clientMsgId)\n const msg = key ? this.byId.get(key) : undefined\n if (msg && key) {\n this.byId.delete(key)\n const confirmed: RenderMessage = { ...msg, id: frame.messageId, seq: frame.seq, ts: frame.ts, status: 'sent' }\n this.byId.set(frame.messageId, confirmed)\n this.keyByClient.set(frame.clientMsgId, frame.messageId)\n if (frame.seq > this._maxSeq) this._maxSeq = frame.seq\n }\n this._sorted = null\n return\n }\n case 'delivered':\n this.markOwnStatus(frame.seq, 'delivered')\n return\n case 'read':\n if (frame.by !== this.me) {\n this.lastReadByOthers = Math.max(this.lastReadByOthers, frame.seq)\n this.markOwnStatus(frame.seq, 'read')\n }\n return\n case 'sync':\n for (const m of frame.messages) this.upsert({ ...m })\n return\n case 'history':\n for (const m of frame.messages) this.upsert({ ...m })\n this.hasMoreHistory = frame.hasMore\n return\n case 'typing':\n if (frame.userId !== this.me) {\n if (frame.isTyping) this.typing.add(frame.userId)\n else this.typing.delete(frame.userId)\n }\n return\n case 'reaction': {\n const m = this.byId.get(frame.messageId)\n if (!m) return\n const reactions: Record<string, UserId[]> = { ...(m.reactions ?? {}) }\n const users = (reactions[frame.emoji] ?? []).filter(u => u !== frame.by)\n if (!frame.removed) users.push(frame.by)\n if (users.length) reactions[frame.emoji] = users; else delete reactions[frame.emoji]\n this.byId.set(frame.messageId, { ...m, reactions })\n this._sorted = null\n return\n }\n case 'edited': {\n const m = this.byId.get(frame.messageId)\n if (m) { this.byId.set(frame.messageId, { ...m, content: frame.content, editedAt: frame.editedAt }); this._sorted = null }\n return\n }\n case 'deleted': {\n const m = this.byId.get(frame.messageId)\n if (m) { this.byId.set(frame.messageId, { ...m, deletedAt: frame.ts }); this._sorted = null }\n return\n }\n case 'state':\n this.state = frame.state\n return\n case 'assigned':\n this.assignedAgentId = frame.agentId ?? undefined\n return\n case 'presence':\n if (frame.status === 'online') this.online.add(frame.userId)\n else this.online.delete(frame.userId)\n return\n case 'subjectState':\n case 'invoked':\n case 'authed':\n case 'error':\n case 'pong':\n return\n case 'sentiment':\n this.sentiment = frame.label\n this.sentimentScore = frame.score\n return\n default:\n return\n }\n }\n\n private upsert(msg: RenderMessage): void {\n const existing = this.byId.get(msg.id)\n this.byId.set(msg.id, existing ? { ...existing, ...msg } : msg)\n if (msg.seq > this._maxSeq) this._maxSeq = msg.seq\n this._sorted = null\n }\n\n private markOwnStatus(uptoSeq: number, status: SendStatus): void {\n const targetRank = rank(status)\n let changed = false\n for (const [k, m] of this.byId) {\n if (m.senderId !== this.me || m.seq <= 0 || m.seq > uptoSeq) continue\n if (rank(m.status) >= targetRank) continue // already at or above target — skip\n this.byId.set(k, { ...m, status })\n changed = true\n }\n if (changed) this._sorted = null\n }\n}\nfunction rank(s: SendStatus | undefined): number {\n switch (s) { case 'read': return 3; case 'delivered': return 2; case 'sent': return 1; default: return 0 }\n}\n","import {\n encodeFrame, decodeFrame, isClientFrame,\n type ClientFrame, type ServerFrame,\n} from './protocol/index.js'\n\n// Minimal socket surface so tests can inject a fake without a real WebSocket.\nexport interface SocketLike {\n binaryType: string\n send(data: Uint8Array): void\n close(): void\n onopen: (() => void) | null\n onclose: (() => void) | null\n onerror: (() => void) | null\n onmessage: ((ev: { data: ArrayBuffer }) => void) | null\n}\nexport type SocketFactory = (url: string) => SocketLike\n\nexport interface ConnectionOptions {\n url: string\n token: string\n /** Authenticated embeds: called when the server rejects the token\n * (typically an expired signed JWT). Return a freshly minted token to\n * resume seamlessly, or null to give up (shows the fatal error). */\n refreshToken?: () => Promise<string | null>\n open: ClientFrame // frame sent right after auth (e.g. open a conversation, or subscribe_inbox)\n onFrame: (frame: ServerFrame) => void\n getCursor: () => number // highest seq seen (for sync on reconnect)\n onStatusChange?: (status: 'connecting' | 'open' | 'reconnecting' | 'error', message?: string) => void\n socketFactory?: SocketFactory\n backoffBaseMs?: number\n backoffMaxMs?: number\n maxOutbox?: number\n}\n\ntype State = 'idle' | 'connecting' | 'open' | 'closed'\n\nexport class ConnectionManager {\n private socket: SocketLike | null = null\n private state: State = 'idle'\n private authed = false\n private everAuthed = false\n private attempt = 0\n private outbox: ClientFrame[] = []\n private stopped = false\n private timer: ReturnType<typeof setTimeout> | null = null\n\n constructor(private readonly opts: ConnectionOptions) {}\n\n connect(): void {\n if (this.state === 'connecting' || this.state === 'open') return\n this.stopped = false\n this.state = 'connecting'\n this.authed = false\n this.opts.onStatusChange?.(this.attempt > 0 ? 'reconnecting' : 'connecting')\n const make = this.opts.socketFactory ?? defaultFactory\n const sock = make(this.opts.url)\n sock.binaryType = 'arraybuffer'\n this.socket = sock\n\n sock.onopen = () => {\n // Don't reset attempt here — reset only after successful auth ('authed').\n // A connection that opens but fails during auth (bad token, server restart)\n // should still back off, not immediately retry at base delay.\n this.raw({ type: 'auth', token: this.opts.token })\n }\n sock.onmessage = (ev) => {\n const frame = decodeFrame(new Uint8Array(ev.data))\n if (!frame || isClientFrame(frame)) return // ignore non-server frames\n this.handle(frame)\n }\n sock.onclose = () => this.onClosed()\n sock.onerror = () => { try { sock.close() } catch { /* */ } }\n }\n\n /** Queue a frame; sent immediately if open, else flushed on (re)connect.\n * The outbox is bounded so a prolonged outage can't grow memory without limit\n * — oldest queued frames are dropped past the cap. */\n send(frame: ClientFrame): void {\n if (this.state === 'open' && this.authed) { this.raw(frame); return }\n // Evicts the oldest half when full to amortise the O(n) cost of overflow.\n this.queue(frame)\n }\n\n /** How many frames are waiting to go out. Useful for a host that wants to\n * show \"message pending\" state, and for asserting the outbox stays bounded. */\n pendingCount(): number { return this.outbox.length }\n\n close(): void {\n this.stopped = true\n if (this.timer) clearTimeout(this.timer)\n this.state = 'closed'\n try { this.socket?.close() } catch { /* */ }\n }\n\n private handle(frame: ServerFrame): void {\n if (frame.type === 'authed') {\n this.attempt = 0 // reset backoff only after a fully successful auth\n this.state = 'open'\n this.authed = true; this.everAuthed = true\n this.opts.onStatusChange?.('open')\n // Open/resolve the conversation. The catch-up `sync` is sent on 'opened'\n // (below), i.e. only after the server has joined us to the room — sending\n // it here would race the async open and be rejected as \"not joined\".\n this.raw(this.opts.open)\n // The QUEUED frames need exactly the same treatment, and used to not get\n // it: flushing here fired them straight after `open`, before the server\n // had joined us, so the engine answered FORBIDDEN 'Open the conversation\n // first' and the message was gone — no ack, no requeue. This is the\n // reconnect-drops-your-message bug. Frames now wait for 'opened' below.\n //\n // EXCEPT when the open frame doesn't produce a join at all: an inbox\n // subscription (`subscribe_inbox`) never gets an 'opened' reply, so\n // waiting for one would strand the queue forever. Nothing needs joining\n // in that case, so flushing immediately is both safe and required.\n if (this.opts.open.type !== 'open') this.flush()\n }\n // 'opened' confirms we're joined — now catch up from our cursor, then\n // release anything queued while we were disconnected.\n if (frame.type === 'opened') {\n this.raw({ type: 'sync', conversationId: frame.conversation.id, sinceSeq: this.opts.getCursor() })\n this.flush(frame.conversation.id)\n }\n // A CONNECTION-FATAL error (bad or rejected token, closed or missing\n // chatroom) will never succeed on retry — stop the reconnect loop and report\n // a clear reason instead of spinning on \"connecting…\" forever. Per-frame\n // errors (rate limit, one bad message) are NOT fatal and fall through.\n if (frame.type === 'error' && FATAL_ERRORS.has(frame.code)) {\n // Token refresh (authenticated embeds): a signed JWT expiring mid-session\n // used to be a dead end — the widget showed a fatal error until reload.\n // If the host supplied refreshToken, ask it to mint a fresh one and\n // reconnect. One in-flight attempt at a time; a refresh that returns\n // null/throws (user logged out, backend down) falls through to fatal.\n if (frame.code === 'UNAUTHORIZED' && this.opts.refreshToken && !this.refreshing) {\n this.refreshing = true\n this.opts.onStatusChange?.('reconnecting', 'Renewing session…')\n void this.opts.refreshToken()\n .then((fresh) => {\n this.refreshing = false\n if (!fresh) { this.fatal(frame); return }\n this.opts.token = fresh\n try { this.socket?.close() } catch { /* */ }\n // onClosed schedules the reconnect, which re-auths with the new token.\n })\n .catch(() => { this.refreshing = false; this.fatal(frame) })\n return\n }\n this.fatal(frame)\n return\n }\n this.opts.onFrame(frame)\n }\n\n private refreshing = false\n\n private fatal(frame: Extract<ServerFrame, { type: 'error' }>): void {\n this.stopped = true\n try { this.socket?.close() } catch { /* */ }\n this.state = 'closed'\n this.opts.onStatusChange?.('error', friendlyError(frame.code))\n this.opts.onFrame(frame)\n }\n\n /** Release queued frames. When called from 'opened' we know the canonical\n * conversation id the server just resolved us to, and queued `send` frames\n * are retargeted to it. A manager only ever opens ONE conversation (its\n * `opts.open`), so every queued send belongs to that thread by\n * construction — but the id it was queued with can be STALE (queued against\n * the previous session's conversation before a reconnect). Retargeting is a\n * no-op in the normal case and rescues the message in the stale one. */\n private flush(conversationId?: string): void {\n const pending = this.outbox\n this.outbox = []\n for (const f of pending) {\n this.raw(\n conversationId && f.type === 'send' && f.conversationId !== conversationId\n ? { ...f, conversationId: conversationId as typeof f.conversationId }\n : f,\n )\n }\n }\n\n /** Bounded enqueue — the cap lives here so EVERY path that queues respects\n * it (a failed `raw` used to push straight onto the array, bypassing it). */\n private queue(frame: ClientFrame): void {\n const cap = this.opts.maxOutbox ?? 1_000\n if (this.outbox.length >= cap) {\n this.outbox = this.outbox.slice(this.outbox.length - (cap >> 1))\n }\n this.outbox.push(frame)\n }\n\n private raw(frame: ClientFrame): void {\n // `this.socket?.send(...)` silently DROPPED the frame whenever the socket\n // was null (post-disconnect, pre-reconnect): optional chaining short-\n // circuits, so nothing throws and the catch that re-queues never runs.\n // A null socket is exactly when a frame most needs to be kept.\n if (!this.socket) { this.queue(frame); return }\n try { this.socket.send(encodeFrame(frame)) } catch { this.queue(frame) }\n }\n\n private onClosed(): void {\n this.authed = false\n this.socket = null\n if (this.stopped) { this.state = 'closed'; return }\n this.state = 'idle'\n // Exponential backoff with jitter; reconnect re-auths, re-opens, re-syncs.\n const base = this.opts.backoffBaseMs ?? 500\n const max = this.opts.backoffMaxMs ?? 15_000\n const delay = Math.min(max, base * 2 ** this.attempt) * (0.5 + Math.random() * 0.5)\n this.attempt++\n // If we've never once connected after several tries, the relay is likely\n // unreachable (wrong URL, server down, blocked) — say so, but keep retrying.\n if (this.attempt >= 3 && !this.everAuthed) {\n this.opts.onStatusChange?.('reconnecting', \"Can't reach chat — retrying…\")\n }\n this.timer = setTimeout(() => this.connect(), delay)\n }\n}\n\n/** Connection-fatal error codes — retrying can't fix these. ONLY auth-handshake\n * failure qualifies: FORBIDDEN / NOT_FOUND are per-REQUEST errors (a stale\n * reference, one permission check) and must NOT tear down the whole socket. */\nconst FATAL_ERRORS = new Set(['UNAUTHORIZED'])\nfunction friendlyError(code: string): string {\n switch (code) {\n case 'UNAUTHORIZED': return 'Chat unavailable — sign-in/token was rejected'\n default: return 'Chat unavailable'\n }\n}\n\nfunction defaultFactory(url: string): SocketLike {\n return new WebSocket(url) as unknown as SocketLike\n}\n","import type { MessageContent } from './protocol/index.js'\n\nexport interface OutboxItem {\n clientMsgId: string\n content: MessageContent\n ts: number\n}\n\nconst MAX_ITEMS = 200 // cap so a long outage can't grow storage unboundedly\nconst MAX_AGE_MS = 7 * 86_400_000 // drop anything older than 7 days on load\n\n/** Persists not-yet-acknowledged outgoing messages to localStorage, keyed by\n * guest token, so a page reload during a connectivity drop doesn't silently\n * lose what the user typed (the \"WhatsApp\" guarantee: your message is queued\n * until it's confirmed sent, even across app restarts). */\nexport class PersistentOutbox {\n private readonly key: string\n\n constructor(token: string) {\n this.key = `ocw_outbox_${token}`\n }\n\n /** All pending items, oldest first, with stale (>7d) entries dropped. */\n load(): OutboxItem[] {\n try {\n const raw = localStorage.getItem(this.key)\n if (!raw) return []\n const items = JSON.parse(raw) as OutboxItem[]\n const cutoff = Date.now() - MAX_AGE_MS\n const fresh = items.filter(i => i.ts >= cutoff)\n if (fresh.length !== items.length) this.save(fresh)\n return fresh\n } catch {\n return []\n }\n }\n\n add(item: OutboxItem): void {\n try {\n const items = this.load()\n items.push(item)\n // Evict oldest when full — matches the in-memory ConnectionManager outbox policy.\n this.save(items.length > MAX_ITEMS ? items.slice(items.length - MAX_ITEMS) : items)\n } catch { /* localStorage unavailable (private mode, quota) — best-effort only */ }\n }\n\n /** Remove an item once it's been acknowledged by the server. */\n remove(clientMsgId: string): void {\n try {\n const items = this.load().filter(i => i.clientMsgId !== clientMsgId)\n this.save(items)\n } catch { /* best-effort */ }\n }\n\n private save(items: OutboxItem[]): void {\n try { localStorage.setItem(this.key, JSON.stringify(items)) } catch { /* quota exceeded — drop silently */ }\n }\n}\n","/**\n * End-to-end encryption primitives (Web Crypto): ECDH P-256 for key agreement\n * + AES-GCM for message content. The server only ever relays public keys and\n * stores ciphertext — it cannot read messages.\n *\n * Scope/limitations (honest): this secures a *live 1:1* session — the guest and\n * one agent exchange public keys while both are connected, then messages between\n * them are encrypted. True asynchronous E2E (encrypting to an offline party)\n * needs a prekey/X3DH scheme, which is out of scope here. When E2E is on, the\n * AI assistant cannot read the room (by design).\n */\n\nconst subtle = (): SubtleCrypto => globalThis.crypto.subtle\n\nfunction b64encode(buf: ArrayBuffer | Uint8Array): string {\n const bytes = buf instanceof Uint8Array ? buf : new Uint8Array(buf)\n let s = ''\n for (const b of bytes) s += String.fromCharCode(b)\n return btoa(s)\n}\nfunction b64decode(s: string): Uint8Array<ArrayBuffer> {\n const bin = atob(s)\n const buf = new ArrayBuffer(bin.length)\n const out = new Uint8Array(buf)\n for (let i = 0; i < bin.length; i++) out[i] = bin.charCodeAt(i)\n return out\n}\n\nexport interface KeyPair { publicKey: CryptoKey; privateKey: CryptoKey }\n\nexport async function generateKeyPair(): Promise<KeyPair> {\n const kp = await subtle().generateKey({ name: 'ECDH', namedCurve: 'P-256' }, true, ['deriveKey', 'deriveBits'])\n return { publicKey: kp.publicKey, privateKey: kp.privateKey }\n}\n\n/** Export a public key to a compact base64 string (raw, 65 bytes for P-256). */\nexport async function exportPublicKey(key: CryptoKey): Promise<string> {\n return b64encode(await subtle().exportKey('raw', key))\n}\n\nasync function importPeerPublicKey(b64: string): Promise<CryptoKey> {\n return subtle().importKey('raw', b64decode(b64), { name: 'ECDH', namedCurve: 'P-256' }, false, [])\n}\n\n/** Derive the shared AES-GCM key from our private key + the peer's public key. */\nexport async function deriveSharedKey(privateKey: CryptoKey, peerPublicKeyB64: string): Promise<CryptoKey> {\n const peer = await importPeerPublicKey(peerPublicKeyB64)\n return subtle().deriveKey(\n { name: 'ECDH', public: peer },\n privateKey,\n { name: 'AES-GCM', length: 256 },\n false,\n ['encrypt', 'decrypt'],\n )\n}\n\nexport interface Ciphertext { ct: string; iv: string }\n\nexport async function encrypt(key: CryptoKey, plaintext: string): Promise<Ciphertext> {\n const iv = globalThis.crypto.getRandomValues(new Uint8Array(12))\n const data = new TextEncoder().encode(plaintext)\n const ct = await subtle().encrypt({ name: 'AES-GCM', iv }, key, data)\n return { ct: b64encode(ct), iv: b64encode(iv) }\n}\n\nexport async function decrypt(key: CryptoKey, ct: string, iv: string): Promise<string> {\n const plain = await subtle().decrypt({ name: 'AES-GCM', iv: b64decode(iv) }, key, b64decode(ct))\n return new TextDecoder().decode(plain)\n}\n\n/** Persist/restore our keypair across reloads (so prior ciphertext stays readable). */\nexport async function loadOrCreateKeyPair(storageKey: string): Promise<KeyPair> {\n try {\n const raw = globalThis.localStorage?.getItem(storageKey)\n if (raw) {\n const { pub, priv } = JSON.parse(raw) as { pub: JsonWebKey; priv: JsonWebKey }\n const publicKey = await subtle().importKey('jwk', pub, { name: 'ECDH', namedCurve: 'P-256' }, true, [])\n const privateKey = await subtle().importKey('jwk', priv, { name: 'ECDH', namedCurve: 'P-256' }, true, ['deriveKey', 'deriveBits'])\n return { publicKey, privateKey }\n }\n } catch { /* fall through to fresh keys */ }\n const kp = await generateKeyPair()\n try {\n const pub = await subtle().exportKey('jwk', kp.publicKey)\n const priv = await subtle().exportKey('jwk', kp.privateKey)\n globalThis.localStorage?.setItem(storageKey, JSON.stringify({ pub, priv }))\n } catch { /* non-persistent environment is fine */ }\n return kp\n}\n\n// ── X3DH async E2E ────────────────────────────────────────────────────────────\n// Extended Triple Diffie-Hellman (X3DH) allows encrypting to an *offline* peer\n// using their published prekey bundle. This enables asynchronous E2E: the sender\n// can encrypt before the recipient connects.\n//\n// Key roles:\n// IK = long-term identity key (ECDH P-256, persistent in localStorage)\n// SPK = signed prekey (ECDH P-256, rotated periodically, server-stored)\n// OPK = one-time prekey (ECDH P-256, single-use pool, server-stored)\n// EK = ephemeral key (ECDH P-256, generated per-message, discarded after)\n//\n// X3DH shared secret = KDF(DH(IK_s, SPK_r) || DH(EK, IK_r) || DH(EK, SPK_r) || DH(EK, OPK_r))\n// Where _s = sender, _r = recipient.\n\n/** Sign a prekey public key bytes using ECDSA P-256 SHA-256.\n * The signingKey must be an ECDSA P-256 private key (not ECDH).\n * In the full X3DH setup the identity key pair contains both an ECDH key\n * (for DH) and an ECDSA key (for signing). We keep them separate here. */\nexport async function signPrekey(signingPrivateKey: CryptoKey, spkPublicKey: CryptoKey): Promise<string> {\n const spkRaw = await subtle().exportKey('raw', spkPublicKey)\n const sig = await subtle().sign({ name: 'ECDSA', hash: 'SHA-256' }, signingPrivateKey, spkRaw)\n return b64encode(sig)\n}\n\n/** Verify an SPK signature. verifyPublicKey must be an ECDSA P-256 public key. */\nexport async function verifyPrekeySignature(verifyPublicKeyB64: string, spkPublicKeyB64: string, signatureB64: string): Promise<boolean> {\n try {\n const verKey = await subtle().importKey('raw', b64decode(verifyPublicKeyB64), { name: 'ECDSA', namedCurve: 'P-256' }, false, ['verify'])\n return await subtle().verify({ name: 'ECDSA', hash: 'SHA-256' }, verKey, b64decode(signatureB64), b64decode(spkPublicKeyB64))\n } catch { return false }\n}\n\n/** A full identity keypair for X3DH: ECDH key for DH computations + ECDSA key\n * for signing prekeys. The two key objects share the same P-256 curve but have\n * different usages, so Web Crypto treats them separately. */\nexport interface IdentityKeyPair {\n ecdhKP: KeyPair // for DH in X3DH\n ecdsaKP: { publicKey: CryptoKey; privateKey: CryptoKey } // for signing SPKs\n /** The ECDH public key exported as base64 — used as the X3DH identity key. */\n publicKeyB64: string\n /** The ECDSA public key exported as base64 — used for SPK signature verification. */\n sigPublicKeyB64: string\n}\n\n/** Generate a full X3DH identity keypair (ECDH + ECDSA on the same P-256 curve). */\nexport async function generateIdentityKeyPair(): Promise<IdentityKeyPair> {\n const ecdhKP = await generateKeyPair()\n const ecdsaKP = await subtle().generateKey({ name: 'ECDSA', namedCurve: 'P-256' }, true, ['sign', 'verify'])\n return {\n ecdhKP,\n ecdsaKP: { publicKey: ecdsaKP.publicKey, privateKey: ecdsaKP.privateKey },\n publicKeyB64: await exportPublicKey(ecdhKP.publicKey),\n sigPublicKeyB64: await exportPublicKey(ecdsaKP.publicKey),\n }\n}\n\n/** Load or generate an identity keypair, persisting both components. */\nexport async function loadOrCreateIdentityKeyPair(storageKey: string): Promise<IdentityKeyPair> {\n try {\n const raw = globalThis.localStorage?.getItem(`${storageKey}-identity`)\n if (raw) {\n const d = JSON.parse(raw) as { ecdhPub: JsonWebKey; ecdhPriv: JsonWebKey; ecdsaPub: JsonWebKey; ecdsaPriv: JsonWebKey }\n const ecdhPub = await subtle().importKey('jwk', d.ecdhPub, { name: 'ECDH', namedCurve: 'P-256' }, true, [])\n const ecdhPriv = await subtle().importKey('jwk', d.ecdhPriv, { name: 'ECDH', namedCurve: 'P-256' }, true, ['deriveKey', 'deriveBits'])\n const ecdsaPub = await subtle().importKey('jwk', d.ecdsaPub, { name: 'ECDSA', namedCurve: 'P-256' }, true, ['verify'])\n const ecdsaPriv = await subtle().importKey('jwk', d.ecdsaPriv, { name: 'ECDSA', namedCurve: 'P-256' }, true, ['sign'])\n return {\n ecdhKP: { publicKey: ecdhPub, privateKey: ecdhPriv },\n ecdsaKP: { publicKey: ecdsaPub, privateKey: ecdsaPriv },\n publicKeyB64: await exportPublicKey(ecdhPub),\n sigPublicKeyB64: await exportPublicKey(ecdsaPub),\n }\n }\n } catch { /* generate fresh */ }\n const ikp = await generateIdentityKeyPair()\n try {\n const ecdhPub = await subtle().exportKey('jwk', ikp.ecdhKP.publicKey)\n const ecdhPriv = await subtle().exportKey('jwk', ikp.ecdhKP.privateKey)\n const ecdsaPub = await subtle().exportKey('jwk', ikp.ecdsaKP.publicKey)\n const ecdsaPriv = await subtle().exportKey('jwk', ikp.ecdsaKP.privateKey)\n globalThis.localStorage?.setItem(`${storageKey}-identity`, JSON.stringify({ ecdhPub, ecdhPriv, ecdsaPub, ecdsaPriv }))\n } catch { /* non-persistent ok */ }\n return ikp\n}\n\nexport interface X3DHBundle {\n identityKey: string // base64 raw P-256 public key\n signedPrekey: string // base64 raw P-256 public key\n signedPrekeyId: string // opaque ID for key rotation tracking\n signature: string // base64 ECDSA signature of SPK by IK\n oneTimePrekey?: string // base64 raw P-256 public key (optional)\n}\n\n/** X3DH sender side: derive a shared key from the recipient's prekey bundle.\n * Returns the shared AES-GCM key and the ephemeral public key to transmit. */\nexport async function x3dhSend(\n senderIK: KeyPair,\n recipientBundle: X3DHBundle,\n): Promise<{ sharedKey: CryptoKey; ephemeralPublicKey: string }> {\n const ek = await generateKeyPair()\n const epkB64 = await exportPublicKey(ek.publicKey)\n\n // Import recipient keys for DH.\n const ik_r = await importPeerPublicKey(recipientBundle.identityKey)\n const spk_r = await importPeerPublicKey(recipientBundle.signedPrekey)\n const opk_r = recipientBundle.oneTimePrekey ? await importPeerPublicKey(recipientBundle.oneTimePrekey) : null\n\n // Four DH computations per spec (three if no OPK).\n const dh1 = await rawDH(senderIK.privateKey, spk_r) // DH(IK_s, SPK_r)\n const dh2 = await rawDH(ek.privateKey, ik_r) // DH(EK, IK_r)\n const dh3 = await rawDH(ek.privateKey, spk_r) // DH(EK, SPK_r)\n const dh4 = opk_r ? await rawDH(ek.privateKey, opk_r) : null // DH(EK, OPK_r)\n\n const ikm = concatBuffers(dh1, dh2, dh3, ...(dh4 ? [dh4] : []))\n const sharedKey = await hkdfDeriveKey(ikm)\n\n return { sharedKey, ephemeralPublicKey: epkB64 }\n}\n\n/** X3DH recipient side: rederive the shared key from an init message.\n * Returns the shared AES-GCM key. */\nexport async function x3dhReceive(\n recipientIK: KeyPair,\n recipientSPK: KeyPair,\n senderIKb64: string,\n ephemeralKeyB64: string,\n recipientOPK?: KeyPair,\n): Promise<CryptoKey> {\n const ik_s = await importPeerPublicKey(senderIKb64)\n const ek_s = await importPeerPublicKey(ephemeralKeyB64)\n\n const dh1 = await rawDH(recipientSPK.privateKey, ik_s) // DH(SPK_r, IK_s)\n const dh2 = await rawDH(recipientIK.privateKey, ek_s) // DH(IK_r, EK)\n const dh3 = await rawDH(recipientSPK.privateKey, ek_s) // DH(SPK_r, EK)\n const dh4 = recipientOPK ? await rawDH(recipientOPK.privateKey, ek_s) : null\n\n const ikm = concatBuffers(dh1, dh2, dh3, ...(dh4 ? [dh4] : []))\n return hkdfDeriveKey(ikm)\n}\n\nasync function rawDH(privateKey: CryptoKey, publicKey: CryptoKey): Promise<ArrayBuffer> {\n return subtle().deriveBits({ name: 'ECDH', public: publicKey }, privateKey, 256)\n}\n\nfunction concatBuffers(...bufs: ArrayBuffer[]): ArrayBuffer {\n const total = bufs.reduce((n, b) => n + b.byteLength, 0)\n const out = new Uint8Array(total)\n let offset = 0\n for (const b of bufs) { out.set(new Uint8Array(b), offset); offset += b.byteLength }\n return out.buffer\n}\n\nasync function hkdfDeriveKey(ikm: ArrayBuffer): Promise<CryptoKey> {\n const ikmKey = await subtle().importKey('raw', ikm, 'HKDF', false, ['deriveKey'])\n return subtle().deriveKey(\n { name: 'HKDF', hash: 'SHA-256', salt: new Uint8Array(32), info: new TextEncoder().encode('ObjectChat X3DH v1') },\n ikmKey,\n { name: 'AES-GCM', length: 256 },\n false,\n ['encrypt', 'decrypt'],\n )\n}\n","import type { MessageContent, UserId } from './protocol/index.js'\nimport type { ServerFrame } from './protocol/index.js'\nimport {\n type KeyPair, loadOrCreateKeyPair, exportPublicKey, deriveSharedKey, encrypt, decrypt,\n generateKeyPair, signPrekey, x3dhSend, x3dhReceive, type X3DHBundle,\n loadOrCreateIdentityKeyPair, type IdentityKeyPair,\n} from './crypto.js'\n\n// Number of one-time prekeys to generate per upload batch.\nconst OTP_BATCH_SIZE = 20\n\n/**\n * Per-user E2E session. Supports two modes:\n *\n * LIVE (original): Both parties are online. ECDH P-256 key exchange via the\n * `pubkey`/`peerkey` frames. Instant but requires both parties to be connected.\n *\n * ASYNC (X3DH): The sender encrypts to the recipient's prekey bundle while the\n * recipient is offline. Uses X3DH (Extended Triple DH) with identity keys,\n * signed prekeys, and one-time prekeys. The recipient derives the same shared\n * key from the init message when they come online.\n *\n * Both modes produce an AES-GCM 256 shared key for message encryption.\n */\nexport class E2ESession {\n // Live ECDH mode state\n private kp?: KeyPair\n private shared?: CryptoKey\n\n // X3DH async mode state\n private identityKP: IdentityKeyPair | undefined = undefined\n private signedPreKP: KeyPair | undefined = undefined\n private signedPrekeyId: string | undefined = undefined\n private readonly otpKeys: KeyPair[] = [] // one-time prekeys awaiting matching\n private x3dhShared?: CryptoKey\n // Queued init messages arriving before we could derive (shouldn't happen, but safe)\n private pendingX3DH: { senderIK: string; ephemeralKey: string; spkId: string; usedOTP: boolean } | undefined = undefined\n\n constructor(private readonly storageKey: string) {}\n\n get ready(): boolean { return !!(this.shared ?? this.x3dhShared) }\n\n /** Live ECDH mode: Generate/restore our keypair and return our public key to publish. */\n async begin(): Promise<string> {\n this.kp = await loadOrCreateKeyPair(this.storageKey)\n return exportPublicKey(this.kp.publicKey)\n }\n\n /** Live ECDH mode: A peer published their key — derive the shared secret. */\n async onPeerKey(peerKeyB64: string): Promise<void> {\n if (!this.kp) return\n this.shared = await deriveSharedKey(this.kp.privateKey, peerKeyB64)\n }\n\n // ── X3DH async mode ────────────────────────────────────────────────────────\n\n /** X3DH: Generate identity key, signed prekey, and OTP prekeys.\n * Returns the upload frame payload the caller should send to the server. */\n async initX3DH(): Promise<{\n identityKey: string; signedPrekey: string; signedPrekeyId: string;\n signature: string; oneTimePrekeys: string[]\n }> {\n // Restore or generate persistent identity keypair (ECDH + ECDSA).\n this.identityKP = await loadOrCreateIdentityKeyPair(this.storageKey)\n // Always generate a fresh signed prekey (rotation).\n this.signedPreKP = await generateKeyPair()\n this.signedPrekeyId = `spk-${Date.now()}-${Math.random().toString(36).slice(2)}`\n // Batch of one-time prekeys.\n for (let i = 0; i < OTP_BATCH_SIZE; i++) this.otpKeys.push(await generateKeyPair())\n\n const signedPrekeyPub = await exportPublicKey(this.signedPreKP.publicKey)\n const signature = await signPrekey(this.identityKP.ecdsaKP.privateKey, this.signedPreKP.publicKey)\n const oneTimePrekeys = await Promise.all(this.otpKeys.map(kp => exportPublicKey(kp.publicKey)))\n\n return {\n identityKey: this.identityKP.publicKeyB64,\n signedPrekey: signedPrekeyPub,\n signedPrekeyId: this.signedPrekeyId,\n signature,\n oneTimePrekeys,\n }\n }\n\n /** X3DH sender: given a recipient's prekey bundle, derive the shared key and\n * return the init message fields to embed in the first encrypted message. */\n async x3dhSendTo(bundle: X3DHBundle): Promise<{ ephemeralKey: string; spkId: string; usedOTP: boolean; senderIK: string }> {\n if (!this.identityKP) this.identityKP = await loadOrCreateIdentityKeyPair(this.storageKey)\n const { sharedKey, ephemeralPublicKey } = await x3dhSend(this.identityKP.ecdhKP, bundle)\n this.x3dhShared = sharedKey\n return { ephemeralKey: ephemeralPublicKey, spkId: bundle.signedPrekeyId, usedOTP: !!bundle.oneTimePrekey, senderIK: this.identityKP.publicKeyB64 }\n }\n\n /** X3DH recipient: given an init message's sender IK + EK + SPK ID, derive\n * the shared key. `usedOTP` MUST reflect whether the SENDER actually\n * included a one-time prekey in its DH computation (carried on the wire\n * as `x3dhOTP`, see `X3DHInitFields`) — it must never be inferred from\n * whether we happen to still have OTP keys locally. Popping one\n * unconditionally was the bug here: our OTP pool almost always has spare\n * keys (we upload a batch of 20 and only the sender's own choice consumes\n * one), so we'd derive dh4 against an OTP the sender never included,\n * producing a shared key that doesn't match the sender's — every\n * message would come back \"🔒 unable to decrypt\" — while also burning a\n * one-time key that was never actually used. */\n async x3dhReceiveFrom(senderIKb64: string, ephemeralKeyB64: string, spkId: string, usedOTP: boolean): Promise<void> {\n if (!this.identityKP || !this.signedPreKP) {\n // Keys not yet initialised — queue for when initX3DH completes.\n this.pendingX3DH = { senderIK: senderIKb64, ephemeralKey: ephemeralKeyB64, spkId, usedOTP }\n return\n }\n // Only consume an OTP when the sender's own message says it used one.\n const otp = usedOTP ? this.otpKeys.shift() : undefined\n this.x3dhShared = await x3dhReceive(this.identityKP.ecdhKP, this.signedPreKP, senderIKb64, ephemeralKeyB64, otp)\n void spkId // we matched by position; full impl would look up by ID\n }\n\n /** Flush pending X3DH derivation after initX3DH() completes. */\n async flushPendingX3DH(): Promise<void> {\n if (!this.pendingX3DH) return\n const { senderIK, ephemeralKey, spkId, usedOTP } = this.pendingX3DH\n this.pendingX3DH = undefined\n await this.x3dhReceiveFrom(senderIK, ephemeralKey, spkId, usedOTP)\n }\n\n /** Encrypt outgoing text into a wire content object. For X3DH init messages,\n * the caller should pass x3dhInit fields to embed in the content. */\n async sealText(text: string, x3dhInit?: { ephemeralKey: string; spkId: string; senderIK: string; usedOTP: boolean }): Promise<MessageContent> {\n const key = this.x3dhShared ?? this.shared\n if (!key) throw new Error('secure channel not ready')\n const { ct, iv } = await encrypt(key, text)\n return {\n kind: 'text', text: ct, enc: true, iv,\n ...(x3dhInit ? { x3dhEK: x3dhInit.ephemeralKey, x3dhSPK: x3dhInit.spkId, x3dhIK: x3dhInit.senderIK, x3dhOTP: x3dhInit.usedOTP } as never : {}),\n }\n }\n\n /** Decrypt one content object if it is encrypted (otherwise pass through). */\n private async openContent(content: MessageContent): Promise<MessageContent> {\n if (content.kind !== 'text' || !content.enc || !content.iv) return content\n const key = this.x3dhShared ?? this.shared\n if (!key) return { kind: 'text', text: '🔒 encrypted' }\n try { return { kind: 'text', text: await decrypt(key, content.text, content.iv) } }\n catch { return { kind: 'text', text: '🔒 unable to decrypt' } }\n }\n\n /** Decrypt any encrypted message content carried by an incoming frame, in place. */\n async openFrame(frame: ServerFrame): Promise<void> {\n if (frame.type === 'message') frame.message.content = await this.openContent(frame.message.content)\n else if (frame.type === 'sync') {\n for (const m of frame.messages) m.content = await this.openContent(m.content)\n }\n }\n}\n\n/** X3DH init fields embedded in a text MessageContent (as extra properties).\n * Present only on the very first message from a sender to an offline peer. */\nexport interface X3DHInitFields {\n x3dhEK: string // sender's ephemeral public key (base64)\n x3dhSPK: string // recipient's signed prekey ID used\n x3dhIK: string // sender's identity public key (base64)\n /** Whether the sender's DH computation included a one-time prekey (dh4).\n * The receiver MUST honor this exactly — it decides whether to consume\n * one of its own OTP keys, and doing so when the sender didn't include\n * one derives a mismatched shared key (see x3dhReceiveFrom). Absent on\n * messages from a build predating this field: treated as `false`, which\n * is only correct if that sender also never used an OTP — a fresh E2E\n * session on both sides (the normal case) is unaffected either way. */\n x3dhOTP: boolean\n}\n\nexport function extractX3DHInit(content: MessageContent): X3DHInitFields | null {\n if (content.kind !== 'text' || !content.enc) return null\n const c = content as MessageContent & Partial<X3DHInitFields>\n if (!c.x3dhEK || !c.x3dhSPK || !c.x3dhIK) return null\n return { x3dhEK: c.x3dhEK, x3dhSPK: c.x3dhSPK, x3dhIK: c.x3dhIK, x3dhOTP: c.x3dhOTP ?? false }\n}\n\nexport { type X3DHBundle } from './crypto.js'\nexport { type UserId }\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 widget (`.ocw`). Extracted from renderer.ts\n// to keep the renderer focused on behaviour. Tokens come from the single\n// source of truth in theme-tokens.ts.\nimport { lightTokens, darkTokens } from './theme-tokens.js'\n\nexport const CSS = `\n.ocw { ${lightTokens('ocw')}\n position:relative;\n display:flex; flex-direction:column; height:100%; min-height:320px; background:var(--ocw-bg);\n font-family:var(--ocw-fb); color:var(--ocw-ink); overflow:hidden; }\n@media (prefers-color-scheme: dark) { .ocw[data-theme=\"auto\"] { ${darkTokens('ocw')} } }\n.ocw[data-theme=\"dark\"] { ${darkTokens('ocw')} }\n/* ── Responsive sizing ──────────────────────────────────────────────────────\n * Sizing is driven by the WIDGET'S OWN width (ResizeObserver toggles\n * .ocw-compact below 400px), not the viewport — so a widget embedded in a\n * narrow desktop sidebar sizes the same as one on a phone, and a tablet in\n * landscape keeps comfortable desktop sizing. A viewport query alone can't\n * see the container. Fullscreen (launcher on mobile) additionally gets\n * .ocw-fs from the launcher, which is the only case that should remove the\n * corner radius — an INLINE embed on a phone must NOT take over the page\n * (the old blanket min-height:100dvh rule did exactly that). */\n.ocw.ocw-fs { border-radius:0 !important; }\n.ocw-compact .ocw-bubble { font-size:15px; }\n.ocw-compact.ocw .ocw-input textarea { font-size:16px; } /* ≥16px prevents iOS zoom on focus */\n.ocw-compact .ocw-chip { padding:9px 14px; font-size:14px; }\n.ocw-compact .ocw-modal-card { width:90%; }\n.ocw-compact .ocw-row { max-width:94%; }\n.ocw-compact .ocw-sendbtn { min-width:44px; height:44px; }\n.ocw-compact .ocw-back { width:34px; height:34px; }\n.ocw-compact .ocw-quick button { padding:9px 15px; font-size:14px; }\n/* RTL support: when the host element has dir=rtl, flip layout direction */\n[dir=\"rtl\"] .ocw-row.mine { flex-direction:row; }\n[dir=\"rtl\"] .ocw-row.theirs { flex-direction:row-reverse; }\n[dir=\"rtl\"] .mine .ocw-bubble { border-bottom-right-radius:18px; border-bottom-left-radius:4px; }\n[dir=\"rtl\"] .theirs .ocw-bubble { border-bottom-left-radius:18px; border-bottom-right-radius:4px; }\n[dir=\"rtl\"] .ocw-input { flex-direction:row-reverse; }\n[dir=\"rtl\"] .mine .ocw-meta { text-align:left; }\n.ocw-head { display:flex; align-items:center; gap:10px; padding:12px 14px; background:var(--ocw-card); border-bottom:1px solid var(--ocw-line); }\n.ocw-back { flex:none; width:30px; height:30px; margin:-2px -2px -2px -4px; border:none; background:none; color:var(--ocw-ink); font-size:26px; line-height:1; cursor:pointer; border-radius:50%; display:flex; align-items:center; justify-content:center; }\n.ocw-back:hover { background:var(--ocw-bg); }\n.ocw-avatar { width:34px; height:34px; border-radius:50%; background:var(--ocw-tint); color:var(--ocw-accent); font-family:var(--ocw-fh); font-weight:600; display:flex; align-items:center; justify-content:center; font-size:13px; flex:none; }\n.ocw-head-main { flex:1; min-width:0; }\n.ocw-head-name { font-family:var(--ocw-fh); font-weight:600; font-size:15px; }\n.ocw-head-meta { color:var(--ocw-mut); font-size:12px; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }\n.ocw-head-status { font-size:10.5px; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }\n.ocw-head-status.online { color:#5cb37a; }\n.ocw-head-status.away { color:#c98b2e; }\n.ocw-msg-sender { font-size:10px; color:var(--ocw-mut); margin-bottom:2px; }\n.ocw-resolved-note { text-align:center; font-size:10.5px; color:var(--ocw-mut); margin:6px 0 12px; }\n.ocw-reopen { display:none; width:calc(100% - 32px); margin:0 16px 14px; height:40px; border:1.5px solid var(--ocw-accent); color:var(--ocw-accent); background:none; border-radius:20px; font:inherit; font-size:13.5px; font-weight:600; cursor:pointer; }\n.ocw-reopen:hover { background:var(--ocw-tint); }\n.ocw-badge { font-size:11px; font-weight:600; color:#2f8a52; background:#eafaf0; border-radius:20px; padding:5px 12px; }\n.ocw-e2e { font-size:11px; font-weight:700; color:var(--ocw-accent); background:var(--ocw-tint); border-radius:20px; padding:5px 12px; align-items:center; }\n.ocw-menu { color:var(--ocw-mut); width:30px; height:30px; border-radius:50%; border:1px solid var(--ocw-line); background:var(--ocw-card); cursor:pointer; }\n.ocw-chiprow { display:flex; gap:8px; padding:10px 12px; background:var(--ocw-card); border-bottom:1px solid var(--ocw-line); overflow-x:auto; }\n.ocw-chip { flex:none; display:flex; align-items:center; gap:6px; border:none; background:var(--ocw-tint); color:var(--ocw-accent); border-radius:999px; padding:7px 13px; font-size:12px; font-weight:600; cursor:pointer; white-space:nowrap; }\n.ocw-chip:hover { border-color:var(--ocw-accent); color:var(--ocw-accent); }\n.ocw-scroll { flex:1; min-height:0; overflow-y:auto; padding:16px 14px; display:flex; flex-direction:column; gap:10px; }\n.ocw-subject { background:var(--ocw-tint); border:none; border-radius:16px; padding:10px 12px; }\n.ocw-subject-title { font-family:var(--ocw-fh); font-weight:600; font-size:13px; margin-bottom:2px; }\n.ocw-subject-sub { color:var(--ocw-mut); font-size:10.5px; margin-bottom:6px; }\n.ocw-tags { display:flex; flex-wrap:wrap; gap:6px; }\n.ocw-tag { font-size:12px; color:#5b554e; background:#efeae3; border-radius:8px; padding:4px 10px; }\n.ocw-row { display:flex; align-items:flex-end; gap:8px; max-width:86%; }\n.ocw-row.mine { align-self:flex-end; flex-direction:row-reverse; }\n.ocw-row.theirs { align-self:flex-start; }\n.ocw-bubble { padding:10px 14px; border-radius:18px; font-size:13.5px; line-height:1.45; word-wrap:break-word; max-width:80%; }\n.theirs .ocw-bubble { background:var(--ocw-tint); border-bottom-left-radius:4px; }\n.mine .ocw-bubble { background:var(--ocw-accent2); color:#fff; border-bottom-right-radius:4px; }\n.ocw-sys { align-self:center; color:var(--ocw-mut); font-size:12.5px; font-style:italic; text-align:center; max-width:90%; }\n.ocw-bot .ocw-bubble { background:var(--ocw-tint); }\n.ocw-note .ocw-bubble { background:#fffbeb; border:1.5px dashed #f59e0b; color:#78350f; border-radius:12px !important; }\n.ocw-note .ocw-bubble::before { content:'🔒 Note — '; font-size:11px; font-weight:700; color:#b45309; display:block; margin-bottom:3px; letter-spacing:.3px; }\n.ocw-time { font-size:10.5px; color:var(--ocw-mut); margin-top:3px; }\n.mine .ocw-meta { text-align:right; }\n.ocw-tick { margin-left:4px; font-size:11px; color:var(--ocw-mut); }\n.ocw-tick.read { color:#3b82f6; }\n.ocw-tick.delivered { color:var(--ocw-mut); }\n.ocw-deleted { font-style:italic; color:var(--ocw-mut); }\n.ocw-edited { font-size:10px; color:var(--ocw-mut); margin-left:4px; }\n.ocw-react { font-size:12px; margin-top:3px; display:flex; flex-wrap:wrap; gap:3px; }\n.ocw-react-pill { display:inline-flex; align-items:center; gap:3px; border:1px solid var(--ocw-line); border-radius:999px; padding:2px 7px; background:var(--ocw-card); font-size:12px; cursor:pointer; }\n.ocw-react-pill:hover { border-color:var(--ocw-accent); }\n.ocw-react-pill.mine { border-color:var(--ocw-accent); background:#fff8f5; }\n.ocw-react-wrap { position:relative; }\n.ocw-react-wrap:not(:hover) .ocw-react-picker { display:none; }\n.ocw-react-picker { position:absolute; bottom:calc(100% + 4px); left:0; background:var(--ocw-card); border:1px solid var(--ocw-line); border-radius:14px; padding:6px 8px; box-shadow:0 4px 16px rgba(0,0,0,.12); display:flex; gap:4px; z-index:10; white-space:nowrap; }\n.ocw-react-picker button { background:none; border:none; font-size:16px; cursor:pointer; padding:2px; border-radius:6px; }\n.ocw-react-picker button:hover { background:var(--ocw-bg); }\n.ocw-react-btn { background:none; border:1px solid var(--ocw-line); border-radius:999px; padding:2px 7px; font-size:12px; cursor:pointer; color:var(--ocw-mut); }\n.ocw-react-btn:hover { border-color:var(--ocw-accent); color:var(--ocw-accent); }\n.ocw-msg-menu { position:absolute; top:0; right:0; display:none; gap:3px; }\n.ocw-row.mine:hover .ocw-msg-menu { display:flex; }\n.ocw-row.theirs:hover .ocw-msg-menu { display:flex; left:0; right:auto; }\n.ocw-msg-menu button { background:var(--ocw-card); border:1px solid var(--ocw-line); border-radius:6px; font-size:11px; padding:2px 6px; cursor:pointer; color:var(--ocw-mut); }\n.ocw-msg-menu button:hover { border-color:var(--ocw-accent); color:var(--ocw-accent); }\n.ocw-msg-menu button.del:hover { border-color:#e74c3c; color:#e74c3c; }\n.ocw-bubble-wrap { position:relative; }\n.ocw-seen { font-size:10.5px; color:var(--ocw-mut); }\n.ocw-appt { background:#f0f7ff; border:1px solid #c7deff; border-radius:12px; padding:12px 14px; max-width:260px; }\n.ocw-appt-title { font-weight:700; font-size:14px; margin-bottom:4px; }\n.ocw-appt-time { font-size:12px; color:#1d4ed8; margin-bottom:4px; }\n.ocw-appt-loc { font-size:12px; color:var(--ocw-mut); margin-bottom:4px; }\n.ocw-appt-desc { font-size:12px; color:var(--ocw-mut); margin-bottom:10px; white-space:pre-wrap; }\n.ocw-appt-links { display:flex; flex-direction:column; gap:6px; }\n.ocw-appt-btn { display:block; text-align:center; padding:8px 12px; border-radius:8px; font-size:13px; font-weight:600; text-decoration:none; background:var(--ocw-accent); color:#fff; }\n.ocw-appt-btn-sec { background:var(--ocw-card); color:var(--ocw-accent); border:1px solid var(--ocw-accent); }\n.ocw-conn-status { font-size:10px; color:var(--ocw-mut); margin-left:4px; }\n.ocw-conn-status.warn { color:#e67e22; }\n.ocw-conn-status.err { color:#c0392b; font-weight:600; }\n.ocw-load-more { display:block; width:100%; background:none; border:1px solid var(--ocw-line); border-radius:10px; padding:6px 0; font-size:12px; color:var(--ocw-mut); cursor:pointer; margin-bottom:8px; }\n.ocw-load-more:hover { border-color:var(--ocw-accent); color:var(--ocw-accent); }\n.ocw-away { margin:0 14px 8px; padding:9px 12px; background:#fff8e6; border:1px solid #f0e2bd; border-radius:10px; font-size:12px; color:#7a5c17; display:flex; gap:7px; align-items:flex-start; line-height:1.45; }\n.ocw button:focus-visible, .ocw textarea:focus-visible, .ocw a:focus-visible, .ocw [tabindex]:focus-visible { outline:2px solid var(--ocw-accent); outline-offset:2px; border-radius:8px; }\n.ocw-sendbtn:active { transform:scale(.92); }\n.ocw-quick button:active, .ocw-chip:active { transform:scale(.97); }\n@media (prefers-color-scheme: dark) { .ocw[data-theme=\"auto\"] .ocw-away { background:#3a3018; border-color:#5a4a1f; color:#e8d9a8; } .ocw[data-theme=\"auto\"] .ocw-note .ocw-bubble { background:#332b12; border-color:#7a5c17; color:#f0e2bd; } .ocw[data-theme=\"auto\"] .ocw-note .ocw-bubble::before { color:#e0c060; } }\n.ocw[data-theme=\"dark\"] .ocw-away { background:#3a3018; border-color:#5a4a1f; color:#e8d9a8; }\n.ocw[data-theme=\"dark\"] .ocw-note .ocw-bubble { background:#332b12; border-color:#7a5c17; color:#f0e2bd; }\n.ocw[data-theme=\"dark\"] .ocw-note .ocw-bubble::before { color:#e0c060; }\n.ocw-away-icon { flex:none; }\n/* Shared form styles (used by the pre-chat panel; named for the retired offline form). */\n.ocw-offline-form { display:flex; flex-direction:column; gap:8px; text-align:left; }\n.ocw-offline-input { border:none; background:var(--ocw-tint); border-radius:14px; padding:10px 12px; font-size:13px; font-family:inherit; color:var(--ocw-ink); }\n.ocw-offline-input:focus { outline:none; box-shadow:inset 0 0 0 1.5px var(--ocw-accent); }\n.ocw-offline-submit { background:var(--ocw-accent); color:var(--ocw-onaccent); border:none; border-radius:20px; padding:11px; font-family:var(--ocw-fh); font-size:13.5px; font-weight:600; cursor:pointer; box-shadow:var(--ocw-shadow); }\n.ocw-prechat { margin:16px; padding:0; background:none; border:none; }\n.ocw-prechat-title { font-family:var(--ocw-fh); font-weight:600; font-size:20px; margin-bottom:10px; }\n.ocw-prechat select { border:none; border-radius:14px; padding:10px 12px; font:inherit; font-size:13px; background:var(--ocw-tint); color:var(--ocw-ink); }\n.ocw-prechat-cb { display:flex; align-items:center; gap:8px; font-size:13px; color:var(--ocw-ink); }\n.ocw-deflect { margin:0 14px 8px; display:flex; flex-direction:column; gap:6px; }\n.ocw-deflect-card { text-align:left; background:var(--ocw-card); border:1px solid var(--ocw-line); border-radius:12px; padding:10px 12px; font:inherit; font-size:13px; cursor:pointer; }\n.ocw-deflect-card:hover { border-color:var(--ocw-accent); }\n.ocw-deflect-q { font-weight:600; margin-bottom:2px; }\n.ocw-deflect-a { color:var(--ocw-mut); font-size:12.5px; display:none; white-space:pre-wrap; }\n.ocw-deflect-card.open .ocw-deflect-a { display:block; }\n.ocw-deflect-hint { font-size:11.5px; color:var(--ocw-mut); text-align:center; }\n.ocw-csat-title { font-size:13px; font-weight:600; margin-bottom:8px; }\n.ocw-csat-stars { display:flex; gap:6px; }\n.ocw-csat-star { background:none; border:none; font-size:22px; cursor:pointer; padding:2px; opacity:.4; transition:opacity .15s; }\n.ocw-csat-star:hover, .ocw-csat-star.lit { opacity:1; }\n.ocw-csat-done { font-size:12px; color:var(--ocw-mut); margin-top:6px; }\n\n.ocw-typing { min-height:22px; padding:0 16px 4px; display:flex; align-items:center; }\n.ocw-typing-bubble { display:none; align-items:center; gap:3px; background:var(--ocw-card); border:1px solid var(--ocw-line); border-radius:14px; border-bottom-left-radius:4px; padding:7px 12px; }\n.ocw-typing.active .ocw-typing-bubble { display:flex; }\n.ocw-typing-dot { width:6px; height:6px; border-radius:50%; background:var(--ocw-mut); animation:ocw-bounce 1.2s infinite ease-in-out; }\n.ocw-typing-dot:nth-child(2) { animation-delay:.2s; }\n.ocw-typing-dot:nth-child(3) { animation-delay:.4s; }\n@keyframes ocw-bounce { 0%,60%,100%{transform:translateY(0)} 30%{transform:translateY(-5px)} }\n.ocw-quick { display:flex; gap:8px; padding:8px 12px 6px; overflow-x:auto; scrollbar-width:none; flex-shrink:0; }\n.ocw-quick::-webkit-scrollbar { display:none; }\n.ocw-quick button { flex:none; border:none; background:var(--ocw-tint); border-radius:999px; padding:7px 14px; font-size:12px; font-weight:600; cursor:pointer; color:var(--ocw-accent); white-space:nowrap; transition:background .12s,color .12s; }\n.ocw-quick button:hover { background:var(--ocw-accent); color:var(--ocw-onaccent); }\n.ocw-form-host:empty { display:none; }\n.ocw-form { margin:6px 12px 0; padding:12px; background:var(--ocw-card); border:1px solid var(--ocw-line); border-radius:14px; }\n.ocw-form-title { font-weight:700; font-size:14px; margin-bottom:8px; }\n.ocw-form-row { display:flex; flex-direction:column; gap:3px; margin-bottom:8px; }\n.ocw-form-lbl { font-size:12px; color:var(--ocw-mut); }\n.ocw-form-input { border:1px solid var(--ocw-line); border-radius:9px; padding:9px 11px; font:inherit; font-size:14px; outline:none; }\n.ocw-form-input:focus { border-color:var(--ocw-accent); }\n.ocw-form-actions { display:flex; justify-content:flex-end; gap:8px; margin-top:4px; }\n.ocw-form-cancel { background:none; border:none; color:var(--ocw-mut); font-size:13px; cursor:pointer; padding:8px 10px; }\n.ocw-form-submit { background:var(--ocw-accent); color:#fff; border:none; border-radius:999px; padding:8px 18px; font-size:13px; font-weight:600; cursor:pointer; }\n.ocw-modal { position:absolute; inset:0; background:rgba(20,18,16,.42); display:flex; align-items:center; justify-content:center; z-index:50; }\n.ocw-modal-card { background:var(--ocw-card); border-radius:16px; padding:20px; width:78%; max-width:300px; box-shadow:0 14px 44px rgba(0,0,0,.22); }\n.ocw-modal-title { font-weight:700; font-size:16px; margin-bottom:6px; }\n.ocw-modal-body { color:var(--ocw-mut); font-size:14px; margin-bottom:16px; }\n.ocw-modal-actions { display:flex; justify-content:flex-end; gap:8px; }\n.ocw-modal-cancel { background:none; border:none; color:var(--ocw-mut); font-size:14px; cursor:pointer; padding:9px 12px; }\n.ocw-modal-ok { background:var(--ocw-accent); color:#fff; border:none; border-radius:999px; padding:9px 20px; font-size:14px; font-weight:600; cursor:pointer; }\n.ocw-input { display:flex; align-items:center; gap:10px; padding:12px; }\n.ocw-footer { text-align:center; font-size:11px; color:var(--ocw-mut); padding:6px 0 8px; }\n.ocw-footer a { color:var(--ocw-mut); text-decoration:none; font-weight:600; }\n.ocw-footer a:hover { color:var(--ocw-accent); }\n.ocw-attach { background:none;border:none;cursor:pointer;font-size:18px;padding:4px 6px;opacity:.6;flex-none; }\n.ocw-attach:hover { opacity:1; }\n.ocw-input textarea { flex:1; min-width:0; resize:none; border:none; border-radius:20px; padding:11px 16px; font:inherit; font-size:14px; line-height:1.4; background:var(--ocw-tint); outline:none; max-height:120px; overflow-y:auto; }\n.ocw-input textarea:focus { box-shadow:inset 0 0 0 1.5px var(--ocw-accent); }\n/* Send button auto-sizes to its label: the default is a fixed circle around an\n * inline SVG; a TEXT label (i18n.send: \"Send\", \"보내기\", \"Enviar\"…) switches to\n * .ocw-sendbtn-label — a pill whose width follows the text. A fixed 42px\n * circle with 18px type overflowed the moment anyone localized the label. */\n.ocw-sendbtn { min-width:38px; height:38px; border-radius:999px; border:none; background:var(--ocw-accent2); color:#fff; font:inherit; font-size:14px; font-weight:600; cursor:pointer; flex:none; display:flex; align-items:center; justify-content:center; padding:0; transition:opacity .15s, transform .1s; }\n.ocw-sendbtn-label { padding:0 16px; white-space:nowrap; }\n.ocw-sendbtn svg { width:19px; height:19px; display:block; }\n.ocw-sendbtn:not(:disabled):hover { transform:scale(1.05); }\n.ocw-sendbtn:not(:disabled):active { transform:scale(.96); }\n.ocw-sendbtn:disabled { opacity:.5; cursor:default; }\n.ocw-sendbtn:focus-visible, .ocw-back:focus-visible, .ocw-chip:focus-visible { outline:2px solid var(--ocw-accent); outline-offset:2px; }\n\n.ocw-translate-btn { position:absolute; bottom:2px; right:-26px; background:var(--ocw-card); border:1px solid var(--ocw-line); border-radius:50%; width:22px; height:22px; font-size:11px; cursor:pointer; color:var(--ocw-mut); display:flex; align-items:center; justify-content:center; opacity:0; transition:opacity .15s; padding:0; }\n.ocw-row.theirs .ocw-translate-btn { right:auto; left:-26px; }\n.ocw-bubble-wrap:hover .ocw-translate-btn { opacity:1; }\n.ocw-translation { margin-top:6px; padding-top:6px; border-top:1px solid var(--ocw-line); font-size:13px; line-height:1.45; }\n.ocw-translation::before { content:'🌐 '; opacity:.75; }\n`\n","import type { ManifestAction, MessageContent } from './protocol/index.js'\nimport type { ChatStore, RenderMessage } from './store.js'\nimport { CSS } from './renderer.styles.js'\n\nexport interface WidgetConfig {\n subject?: { title?: string; subtitle?: string; tags?: string[]; status?: string; ownerLabel?: string }\n quickReplies?: string[]\n accent?: string\n /** Secondary accent — the guest's OWN bubble + send button. Defaults to the\n * design blue; if omitted while `accent` is set, follows `accent` so a single\n * accent override re-themes cohesively. */\n accent2?: string\n /** Colour scheme. Default 'light'. 'auto' follows the OS (prefers-color-scheme);\n * 'dark'/'light' force it. Dark is never auto-applied unless the host opts in. */\n theme?: 'auto' | 'light' | 'dark'\n /** Load the brand webfonts (Baloo 2 + Nunito). Default true; set false for\n * strict-CSP / privacy-sensitive hosts (falls back to the system stack). */\n webfont?: boolean\n /** Identified user info — shown as the guest avatar/name in the widget header. */\n userInfo?: { name?: string; avatar?: string }\n /** i18n string overrides */\n i18n?: { placeholder?: string; send?: string; offline?: string; poweredBy?: string; online?: string; away?: string; aiAssistant?: string; resolved?: string; reopen?: string }\n\n}\n\nexport interface RendererHandlers {\n onSend(text: string): void\n onAttach?(file: File): void\n onInvoke(actionId: string, inputs?: Record<string, unknown>): void\n onTyping(isTyping: boolean, preview?: string): void\n onReadUpTo(seq: number): void\n onReact?(messageId: string, emoji: string, remove: boolean): void\n onCsat?(score: number): void\n onLoadMore?(): void\n onEdit?(messageId: string, newText: string): void\n onDelete?(messageId: string): void\n /** Pre-chat qualification submitted (values keyed by field; topic/callback included). */\n onPreChat?(values: { name?: string; email?: string; phone?: string; topic?: string; callback?: boolean }): void\n /** KB deflection: the guest is typing their FIRST message — look up articles. */\n onDeflectQuery?(q: string): void\n /** Translate a message's text for display. Return null if unavailable —\n * the renderer shows a brief \"unavailable\" hint and leaves the original. */\n onTranslate?(text: string): Promise<string | null>\n /** Stack navigation (chat-app surfaces): when set, the header shows a back\n * chevron on the left that calls this — tap a conversation → chatroom →\n * back → list, like a native messaging app. Omit for a standalone widget,\n * which has nothing to go \"back\" to. */\n onBack?(): void\n}\n\nconst STYLE_ID = 'objectchat-widget-styles'\nconst REACTION_EMOJIS = ['👍', '❤️', '😂', '😮', '😢', '🙏']\n/** Width below which the widget switches to compact (touch-friendly) sizing. */\nconst COMPACT_BREAKPOINT = 400\n// Inline, dependency-free send glyph — `currentColor` follows the button text\n// colour; no emoji/font dependency so it renders identically across platforms.\nconst SEND_ICON_SVG =\n '<svg viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\" aria-hidden=\"true\">' +\n '<path d=\"M22 2 11 13M22 2l-7 20-4-9-9-4 20-7z\" stroke=\"currentColor\" stroke-width=\"2\" ' +\n 'stroke-linecap=\"round\" stroke-linejoin=\"round\"/></svg>'\n// CSS lives in renderer.styles.ts (single source of truth for .ocw styling).\n\nfunction injectStyles(): void {\n if (typeof document === 'undefined' || document.getElementById(STYLE_ID)) return\n const s = document.createElement('style'); s.id = STYLE_ID; s.textContent = CSS; document.head.appendChild(s)\n}\n\n/** Load the brand webfonts (Baloo 2 + Nunito) once. The design's identity is its\n * rounded type — without this the widget falls back to system fonts and looks\n * generic. Injected as a <link> so a strict host CSP that blocks it degrades\n * gracefully to the system stack. Opt out with `webfont: false`. */\nconst FONT_ID = 'ocw-webfont'\nfunction injectFonts(): void {\n if (typeof document === 'undefined' || document.getElementById(FONT_ID)) return\n const l = document.createElement('link')\n l.id = FONT_ID; 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.appendChild(l)\n}\n\nfunction el<K extends keyof HTMLElementTagNameMap>(tag: K, cls?: string, text?: string): HTMLElementTagNameMap[K] {\n const n = document.createElement(tag); if (cls) n.className = cls; if (text !== undefined) n.textContent = text; return n\n}\nfunction fmtTime(ts: number): string {\n try { return new Date(ts).toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' }) } catch { return '' }\n}\nfunction contentText(c: MessageContent): string {\n switch (c.kind) {\n case 'text': return c.text\n case 'system': return typeof c.data?.['message'] === 'string' ? String(c.data['message']) : c.event\n case 'card': return [c.title, c.body].filter(Boolean).join(' — ')\n case 'attachment': return c.name ?? c.url\n case 'form': return c.prompt\n case 'appointment': return `📅 ${c.title} — ${new Date(c.startIso).toLocaleString()}`\n }\n}\n\n/** Renders a ChatStore into a host element in the Image-1 layout: header →\n * subject card → action chips → chat → quick replies → input. Self-injects its\n * stylesheet so it looks right wherever it mounts. Accent comes from the\n * dashboard-authored profile theme (via the manifest), falling back to config. */\nexport class Renderer {\n private readonly scroll: HTMLElement\n private readonly chips: HTMLElement\n private readonly typing: HTMLElement\n private readonly quick: HTMLElement\n private readonly formHost: HTMLElement\n private readonly csatPanel: HTMLElement\n private readonly awayNotice: HTMLElement\n private readonly headStatus: HTMLElement\n private readonly reopenBtn: HTMLButtonElement\n private readonly preChatPanel: HTMLElement\n private readonly deflectPanel: HTMLElement\n private preChatBuilt = false\n private preChatDone = false\n private readonly footer: HTMLElement\n private readonly input: HTMLTextAreaElement\n private readonly subjectCard: HTMLElement\n private readonly e2eBadge: HTMLElement\n private readonly statusBadge: HTMLElement\n private readonly headerName: HTMLElement\n private readonly connStatus: HTMLElement\n private typingTimer: ReturnType<typeof setTimeout> | null = null\n private csatSubmitted = false\n private readonly sendBtn: HTMLButtonElement\n /** Container-driven responsive sizing — toggles .ocw-compact (see CSS note). */\n private compactObserver: ResizeObserver | null = null\n private storeRef: ChatStore | null = null\n private readonly cfgAccent2: string | undefined\n private scrollCleanup: (() => void) | null = null\n\n /** Returns the scroll container so history.ts can attach scroll listeners. */\n getScrollEl(): HTMLElement | null { return this.scroll }\n\n /** Registers a cleanup fn removed on destroy() to prevent listener leaks. */\n setScrollCleanup(fn: () => void): void {\n this.scrollCleanup?.()\n this.scrollCleanup = fn\n }\n\n // ── Live translation ──────────────────────────────────────────────────-\n private readonly translationCache = new Map<string, string>()\n private readonly showingTranslation = new Set<string>()\n\n\n /** Last seq the guest has seen per conversationId — used to compute unread badges. */\n\n\n constructor(\n private readonly root: HTMLElement,\n private readonly me: string,\n private readonly h: RendererHandlers,\n private readonly cfg: WidgetConfig = {},\n ) {\n injectStyles()\n if (cfg.webfont !== false) injectFonts()\n // Clear any previous widget content on this element before building.\n // This is the last line of defence against double-mounts: even if mount()\n // is called twice on the same element (React StrictMode, HMR, caller bug),\n // the second Renderer wipes the first one's DOM so only one UI is visible.\n root.replaceChildren()\n root.classList.add('ocw')\n if (cfg.accent) root.style.setProperty('--ocw-accent', cfg.accent)\n // Two-accent model: explicit accent2 wins; else if only accent is set, accent2\n // follows it (single-token retheme); else the CSS defaults (indigo + blue) hold.\n const accent2 = cfg.accent2 ?? cfg.accent\n if (accent2) root.style.setProperty('--ocw-accent2', accent2)\n this.cfgAccent2 = cfg.accent2\n // Colour scheme is a deliberate choice, never auto-detected by default:\n // unset → 'light'. 'auto' is an explicit opt-in that follows the OS via the\n // prefers-color-scheme media query (which is scoped to [data-theme=\"auto\"]);\n // 'dark'/'light' force the scheme regardless of the OS.\n root.dataset.theme = cfg.theme ?? 'light'\n\n // Header\n const head = el('div', 'ocw-head')\n // Stack navigation: a back chevron returns to the conversation list. Only\n // shown when the host wired onBack (chat-app surfaces) — a standalone\n // support widget has no list to go back to.\n if (this.h.onBack) {\n const back = el('button', 'ocw-back', '‹') as HTMLButtonElement\n back.type = 'button'\n back.setAttribute('aria-label', 'Back')\n back.addEventListener('click', () => this.h.onBack!())\n head.append(back)\n }\n // Header identity is the party the guest is talking TO (the brand/room), so\n // the avatar mirrors the header name — a brand monogram (e.g. \"NM\"), never a\n // generic person glyph. Hidden entirely when there's no brand name to show.\n const brandName = cfg.subject?.ownerLabel ?? cfg.subject?.title ?? ''\n const avatarEl = el('div', 'ocw-avatar')\n if (brandName.trim()) {\n avatarEl.textContent = brandName.trim()[0]!.toUpperCase()\n head.append(avatarEl)\n }\n const hm = el('div', 'ocw-head-main')\n this.headerName = el('div', 'ocw-head-name', cfg.subject?.ownerLabel ?? cfg.subject?.title ?? '')\n hm.append(this.headerName)\n this.headStatus = el('div', 'ocw-head-status'); this.headStatus.style.display = 'none'\n hm.append(this.headStatus)\n if (cfg.subject?.subtitle) hm.append(el('div', 'ocw-head-meta', cfg.subject.subtitle))\n head.append(hm)\n this.statusBadge = el('span', 'ocw-badge', cfg.subject?.status ?? '')\n if (!cfg.subject?.status) this.statusBadge.style.display = 'none'\n head.append(this.statusBadge)\n this.e2eBadge = el('span', 'ocw-e2e', '🔒 E2E'); this.e2eBadge.style.display = 'none'; head.append(this.e2eBadge)\n this.connStatus = el('span', 'ocw-conn-status'); this.connStatus.style.display = 'none'; head.append(this.connStatus)\n\n head.append(el('button', 'ocw-menu', '⋯'))\n\n // Action chips (filled in render)\n this.chips = el('div', 'ocw-chiprow')\n\n // Scroll area with optional subject card + messages\n this.scroll = el('div', 'ocw-scroll')\n this.subjectCard = el('div', 'ocw-subject')\n this.typing = el('div', 'ocw-typing')\n const typingBubble = el('div', 'ocw-typing-bubble')\n typingBubble.append(el('div', 'ocw-typing-dot'), el('div', 'ocw-typing-dot'), el('div', 'ocw-typing-dot'))\n this.typing.append(typingBubble)\n this.quick = el('div', 'ocw-quick')\n for (const q of cfg.quickReplies ?? []) {\n const b = el('button', undefined, q)\n b.addEventListener('click', () => {\n this.h.onSend(q)\n // Hide quick replies immediately after one is tapped\n this.quick.style.display = 'none'\n })\n this.quick.append(b)\n }\n\n // Input\n this.formHost = el('div', 'ocw-form-host')\n this.csatPanel = el('div', 'ocw-csat'); this.csatPanel.style.display = 'none'\n // Away notice (outside office hours). INFORMATIONAL only — it never blocks\n // the composer: the message is delivered either way and an agent replies\n // when they're back. (It used to be a card that replaced the composer with\n // a name/email/message form; guests could not simply chat.)\n this.awayNotice = el('div', 'ocw-away'); this.awayNotice.style.display = 'none'\n this.preChatPanel = el('div', 'ocw-prechat'); this.preChatPanel.style.display = 'none'\n this.deflectPanel = el('div', 'ocw-deflect'); this.deflectPanel.style.display = 'none'\n this.input = el('textarea', undefined); this.input.rows = 1\n // i18n.placeholder was documented in MountOptions but never actually\n // applied — the composer always said \"Message…\" regardless.\n this.input.placeholder = cfg.i18n?.placeholder ?? 'Message…'\n const sendBtn = el('button', 'ocw-sendbtn') as HTMLButtonElement\n sendBtn.type = 'button'\n const sendLabel = cfg.i18n?.send\n if (sendLabel) {\n // Text label → auto-width pill (see the .ocw-sendbtn-label CSS note).\n sendBtn.textContent = sendLabel\n sendBtn.classList.add('ocw-sendbtn-label')\n sendBtn.setAttribute('aria-label', sendLabel)\n } else {\n // Default: inline SVG paper plane — renders identically on every\n // platform (the old '➤' text glyph varied per OS font).\n sendBtn.innerHTML = SEND_ICON_SVG\n sendBtn.setAttribute('aria-label', 'Send message')\n }\n // The :disabled style existed but nothing ever set the state — send is\n // inactive until there's something to send, like every mainstream chat UI.\n sendBtn.disabled = true\n this.sendBtn = sendBtn\n sendBtn.addEventListener('click', () => this.flushSend())\n this.input.addEventListener('input', () => {\n this.sendBtn.disabled = this.input.value.trim().length === 0\n this.autoGrowInput()\n // Deflection fires only for the FIRST message of an empty conversation —\n // once a thread exists, suggestions would just be noise.\n if (this.storeRef && !this.storeRef.messages().some(m => m.senderRole === 'guest')) this.h.onDeflectQuery?.(this.input.value)\n else this.hideDeflection()\n })\n this.input.addEventListener('keydown', (e) => {\n // Guard against IME composition (Korean/Japanese/Chinese input): while\n // the user is selecting a candidate from the IME's suggestion list,\n // pressing Enter to CONFIRM the candidate also fires a keydown with\n // key === 'Enter'. Without this check, that confirmation keystroke was\n // being treated as \"send the message\" — firing early with a partial\n // composition, and then firing again on the real Enter press with\n // whatever text was left, producing two bubbles for one message\n // (e.g. typing \"음식\" sends \"음식\" then \"식\").\n // e.isComposing covers most browsers; keyCode 229 is the long-standing\n // fallback for browsers/IMEs that don't set isComposing reliably.\n if (e.isComposing || e.keyCode === 229) return\n if (e.key === 'Enter' && !e.shiftKey) { e.preventDefault(); this.flushSend() } else this.signalTyping()\n })\n\n const attachBtn = el('button', 'ocw-attach', '📎'); attachBtn.title = 'Attach image or file'\n const fileInput = document.createElement('input'); fileInput.type = 'file'\n fileInput.accept = 'image/*,.pdf,.txt,.doc,.docx'; fileInput.style.display = 'none'\n attachBtn.addEventListener('click', () => fileInput.click())\n fileInput.addEventListener('change', () => { if (fileInput.files?.[0] && this.h.onAttach) this.h.onAttach(fileInput.files[0]); fileInput.value = '' })\n\n const inputRow = el('div', 'ocw-input'); inputRow.append(attachBtn, fileInput, this.input, sendBtn)\n\n const footer = el('div', 'ocw-footer')\n // i18n.poweredBy: if the caller provides it, treat as plain text — no innerHTML.\n // Only our own hardcoded default renders the anchor as HTML.\n if (cfg.i18n?.poweredBy !== undefined) {\n footer.textContent = cfg.i18n.poweredBy\n } else {\n footer.innerHTML = 'Powered by <a href=\"https://relay.paramms.com\" target=\"_blank\" rel=\"noopener\">Relay</a>'\n }\n this.footer = footer\n\n this.reopenBtn = el('button', 'ocw-reopen', this.cfg.i18n?.reopen ?? 'Reopen conversation') as HTMLButtonElement\n this.reopenBtn.type = 'button'\n this.reopenBtn.addEventListener('click', () => {\n this.reopenBtn.style.display = 'none'\n const ta = this.root.querySelector('.ocw-input textarea') as HTMLTextAreaElement | null\n ta?.focus()\n })\n root.append(head, this.chips, this.scroll, this.typing, this.quick, this.formHost, this.csatPanel, this.preChatPanel, this.deflectPanel, this.awayNotice, inputRow, this.reopenBtn, this.footer)\n\n // Container-driven responsive sizing: compact below COMPACT_BREAKPOINT of\n // the widget's OWN width. Covers phones AND narrow desktop embeds — a\n // viewport media query can't see the container. Guarded: jsdom/tests and\n // very old runtimes have no ResizeObserver; they keep desktop sizing.\n const applyCompact = (w: number): void => { root.classList.toggle('ocw-compact', w > 0 && w < COMPACT_BREAKPOINT) }\n applyCompact(root.clientWidth)\n if (typeof ResizeObserver !== 'undefined') {\n this.compactObserver = new ResizeObserver((entries) => {\n const w = entries[0]?.contentRect.width ?? root.clientWidth\n applyCompact(w)\n })\n this.compactObserver.observe(root)\n }\n }\n\n /** Call when the widget is unmounted. Disconnects scroll listeners and clears timers. */\n destroy(): void {\n this.scrollCleanup?.()\n this.scrollCleanup = null\n if (this.typingTimer) { clearTimeout(this.typingTimer); this.typingTimer = null }\n this.compactObserver?.disconnect()\n this.compactObserver = null\n }\n\n\n private flushSend(): void {\n this.hideDeflection()\n const text = this.input.value.trim()\n if (!text) return\n this.input.value = ''\n this.sendBtn.disabled = true\n this.autoGrowInput() // collapse back to one row\n this.h.onTyping(false)\n this.h.onSend(text)\n }\n\n /** Grow the composer with its content (up to the CSS max-height), collapse\n * when cleared. scrollHeight is 0 in non-layout environments (jsdom) —\n * skip there so tests and SSR-ish mounts are unaffected. */\n private autoGrowInput(): void {\n this.input.style.height = 'auto'\n const sh = this.input.scrollHeight\n if (sh > 0) this.input.style.height = `${Math.min(sh, 120)}px`\n else this.input.style.removeProperty('height')\n }\n private signalTyping(): void {\n const preview = this.input.value.trim().slice(0, 100) || undefined\n this.h.onTyping(true, preview)\n if (this.typingTimer) clearTimeout(this.typingTimer)\n this.typingTimer = setTimeout(() => this.h.onTyping(false), 2000)\n }\n\n render(store: ChatStore): void {\n this.storeRef = store\n if (store.accent) {\n this.root.style.setProperty('--ocw-accent', store.accent)\n this.root.style.setProperty('--ocw-accent2', this.cfgAccent2 ?? store.accent)\n }\n this.e2eBadge.style.display = store.e2e ? 'inline-flex' : 'none'\n this.buildSubjectCard(store)\n // Header: when a subject is attached, show ownerLabel (\"Seller\", \"Host\")\n // or nothing — the subject card below carries the identity.\n // Without a subject, the header is already set to cfg.subject?.ownerLabel\n // or \"Chat\" from the constructor — don't overwrite it with the domain name\n // which would duplicate the subject card title or clutter a plain chat.\n if (store.subject) {\n const ownerLabel = this.cfg.subject?.ownerLabel\n if (ownerLabel) this.headerName.textContent = ownerLabel\n // else leave constructor default (\"Chat\")\n }\n // Without a subject: leave header as-is (set once in constructor)\n\n // Quick replies are a first-touch affordance (\"Is this still available?\").\n // They belong only on an empty conversation — once there's any message,\n // hide them, and keep them hidden on every re-render (returning to the\n // widget, reload, back-nav). Without this they reappear each mount even\n // though the conversation is already underway.\n this.quick.style.display = store.messages().length === 0 ? 'flex' : 'none'\n\n // Action chips from the manifest (filtered by state in the store)\n this.chips.replaceChildren()\n const actions = store.visibleActions()\n this.chips.style.display = actions.length ? 'flex' : 'none'\n for (const a of actions) this.chips.append(this.chipEl(a))\n\n // Messages\n // Preserve scroll anchor when history is prepended: capture height before\n // replaceChildren so we can restore relative position after.\n const prevScrollHeight = this.scroll.scrollHeight\n const prevScrollTop = this.scroll.scrollTop\n\n this.scroll.replaceChildren()\n if (this.subjectCard.childNodes.length) this.scroll.append(this.subjectCard)\n if (store.hasMoreHistory) {\n // Sentinel at top — scroll to here triggers load-more via the scroll\n // listener set up by restoreHistory. Shows a subtle loading indicator\n // so the user knows older messages are available.\n const sentinel = el('div', 'ocw-load-more')\n sentinel.textContent = '↑ Loading earlier messages…'\n sentinel.style.pointerEvents = 'none'\n this.scroll.append(sentinel)\n }\n let maxOther = 0\n let prevSender: string | null = null\n for (const m of store.messages()) {\n const showLabel = m.senderRole !== 'system' && m.senderId !== this.me && !m.internal && m.senderId !== prevSender\n this.scroll.append(this.messageEl(m, store, showLabel))\n if (m.senderRole !== 'system') prevSender = m.senderId\n if (m.senderId !== this.me && m.seq > maxOther) maxOther = m.seq\n }\n // Auto-scroll to bottom only for new messages; restore anchor when history was prepended.\n if (prevScrollTop > 20) {\n this.scroll.scrollTop = this.scroll.scrollHeight - prevScrollHeight + prevScrollTop\n } else {\n this.scroll.scrollTop = this.scroll.scrollHeight\n }\n if (maxOther > 0) this.h.onReadUpTo(maxOther)\n\n const typingNames = [...store.typing]\n this.typing.classList.toggle('active', typingNames.length > 0)\n // Bubble is always present in DOM (hidden via CSS); just update label\n const bubble = this.typing.querySelector('.ocw-typing-bubble')\n if (bubble) bubble.setAttribute('aria-label', typingNames.length ? 'typing' : '')\n this.footer.style.display = store.whiteLabel ? 'none' : 'block'\n\n // Offline mode: show form instead of chat input\n // Pre-chat qualification (dashboard-configured, arrives in the manifest):\n // shown before the FIRST message when enabled — 'offline'-scoped configs\n // replace the default leave-a-message form; 'always' configs gate the\n // composer while the team is online too. Never re-shown once completed\n // or once the conversation has any history.\n // \"Before the first message\" means the GUEST hasn't spoken — a chatroom\n // welcomeMessage is a real stored system message, so counting ALL\n // messages suppressed pre-chat (and deflection) on exactly the chatrooms\n // most likely to configure them.\n const guestHasSpoken = store.messages().some(m => m.senderRole === 'guest')\n const preChatWanted = !!store.preChat?.enabled && !this.preChatDone && !guestHasSpoken &&\n (store.preChat!.showWhen !== 'offline' || store.offline)\n if (preChatWanted) {\n if (!this.preChatBuilt) this.buildPreChatPanel(store.preChat!)\n this.preChatPanel.style.display = 'block'\n this.awayNotice.style.display = 'none'\n ;(this.root.querySelector('.ocw-input') as HTMLElement | null)?.style.setProperty('display', 'none')\n } else {\n this.preChatPanel.style.display = 'none'\n // Being outside office hours only changes EXPECTATIONS, never capability:\n // say we're away, keep the composer, deliver the message, reply later.\n if (store.offline) {\n if (!this.awayNotice.firstChild) {\n this.awayNotice.append(el('span', 'ocw-away-icon', '🌙'), el('span', '', ''))\n }\n const copy = this.awayNotice.lastChild as HTMLElement\n copy.textContent = store.offlineMessage\n || this.cfg.i18n?.offline\n || \"We're away right now — send your message and we'll reply as soon as we're back.\"\n this.awayNotice.style.display = 'flex'\n } else {\n this.awayNotice.style.display = 'none'\n }\n ;(this.root.querySelector('.ocw-input') as HTMLElement | null)?.style.removeProperty('display')\n }\n\n // CSAT: show star-rating panel when conversation reaches a terminal state\n // and the user hasn't yet rated. Terminal states are heuristic: 'resolved',\n // 'closed', 'sold', 'issued', 'checked_out'. The panel self-dismisses on submit.\n const terminalStates = ['resolved', 'closed', 'sold', 'issued', 'checked_out']\n if (this.h.onCsat && !this.csatSubmitted && terminalStates.includes(store.state) && store.messages().length > 0) {\n if (this.csatPanel.style.display === 'none') this.buildCsatPanel()\n this.csatPanel.style.display = 'block'\n }\n\n // Header availability line: green when online, amber when the chatroom is\n // outside office hours. Server-provided offlineMessage (already localized)\n // is preferred for the away text; falls back to the i18n label.\n const isTerminal = terminalStates.includes(store.state)\n if (store.offline) {\n this.headStatus.textContent = `● ${store.offlineMessage || this.cfg.i18n?.away || 'Away'}`\n this.headStatus.className = 'ocw-head-status away'\n this.headStatus.style.display = ''\n } else if (store.conversationId) {\n this.headStatus.textContent = `● ${this.cfg.i18n?.online ?? 'Online'}`\n this.headStatus.className = 'ocw-head-status online'\n this.headStatus.style.display = ''\n } else {\n this.headStatus.style.display = 'none'\n }\n\n // Resolved: a legible divider in the thread + a one-tap reopen affordance.\n if (isTerminal && store.messages().length > 0) {\n const note = el('div', 'ocw-resolved-note', `— ${this.cfg.i18n?.resolved ?? 'Marked as resolved'} —`)\n this.scroll.append(note)\n this.reopenBtn.style.display = 'block'\n } else {\n this.reopenBtn.style.display = 'none'\n }\n }\n\n setConnStatus(status: 'connecting' | 'open' | 'reconnecting' | 'error', message?: string): void {\n if (status === 'open') { this.connStatus.style.display = 'none'; return }\n this.connStatus.style.display = ''\n // 'error' is a FATAL, non-transient state (bad token, closed chatroom, or the\n // relay is unreachable after repeated tries) — show a clear reason and don't\n // pretend we're still \"connecting…\". Anything else is transient.\n const fatal = status === 'error'\n this.connStatus.className = `ocw-conn-status${fatal ? ' err' : status === 'reconnecting' ? ' warn' : ''}`\n this.connStatus.textContent = fatal\n ? `⚠ ${message ?? 'Chat unavailable'}`\n : status === 'reconnecting' ? (message ?? '↻ reconnecting…') : '● connecting…'\n }\n\n private buildPreChatPanel(cfg: import('./protocol/frames.js').PreChatConfig): void {\n this.preChatBuilt = true\n this.preChatPanel.replaceChildren()\n this.preChatPanel.append(el('div', 'ocw-prechat-title', cfg.title ?? 'Before we start…'))\n const form = el('div', 'ocw-offline-form')\n const inputs: Partial<Record<'name' | 'email' | 'phone', HTMLInputElement>> = {}\n for (const f of cfg.fields ?? ['name', 'email']) {\n const inp = el('input', 'ocw-offline-input') as HTMLInputElement\n inp.type = f === 'email' ? 'email' : f === 'phone' ? 'tel' : 'text'\n inp.placeholder = f === 'name' ? 'Your name' : f === 'email' ? 'Your email' : 'Your phone number'\n inputs[f] = inp\n form.append(inp)\n }\n let topicSel: HTMLSelectElement | null = null\n if (cfg.topics?.length) {\n topicSel = el('select', undefined) as HTMLSelectElement\n const ph = document.createElement('option'); ph.value = ''; ph.textContent = 'What is this about?'; topicSel.append(ph)\n for (const t of cfg.topics) { const o = document.createElement('option'); o.value = t; o.textContent = t; topicSel.append(o) }\n form.append(topicSel)\n }\n let callbackCb: HTMLInputElement | null = null\n let phoneForCb: HTMLInputElement | null = null\n if (cfg.callbackOption) {\n const row = el('label', 'ocw-prechat-cb')\n callbackCb = document.createElement('input'); callbackCb.type = 'checkbox'\n row.append(callbackCb, document.createTextNode('📞 Request a call back'))\n form.append(row)\n if (!inputs.phone) {\n phoneForCb = el('input', 'ocw-offline-input') as HTMLInputElement\n phoneForCb.type = 'tel'; phoneForCb.placeholder = 'Phone number for the call'; phoneForCb.style.display = 'none'\n callbackCb.addEventListener('change', () => phoneForCb!.style.setProperty('display', callbackCb!.checked ? 'block' : 'none'))\n form.append(phoneForCb)\n }\n }\n const submit = el('button', 'ocw-offline-submit', 'Start chat') as HTMLButtonElement\n submit.type = 'button'\n submit.addEventListener('click', () => {\n const email = inputs.email?.value.trim()\n if (inputs.email && (!email || !/^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/.test(email))) { inputs.email.focus(); return }\n const callback = !!callbackCb?.checked\n const phone = (inputs.phone?.value ?? phoneForCb?.value ?? '').trim()\n if (callback && !phone) { (inputs.phone ?? phoneForCb)?.focus(); return }\n if (topicSel && cfg.topics?.length && !topicSel.value) { topicSel.focus(); return }\n submit.disabled = true // a double-click must not qualify twice\n this.completePreChat()\n this.h.onPreChat?.({\n ...(inputs.name?.value.trim() ? { name: inputs.name.value.trim() } : {}),\n ...(email ? { email } : {}),\n ...(phone ? { phone } : {}),\n ...(topicSel?.value ? { topic: topicSel.value } : {}),\n ...(callback ? { callback: true } : {}),\n })\n })\n form.append(submit)\n this.preChatPanel.append(form)\n }\n\n /** Mark pre-chat complete (submitted now or in a previous session). */\n completePreChat(): void {\n this.preChatDone = true\n this.preChatPanel.style.display = 'none'\n if (this.storeRef) this.render(this.storeRef)\n }\n\n /** KB deflection results (\"was this your question?\") above the composer. */\n showDeflection(articles: { id: string; title: string; answer: string }[]): void {\n if (!articles.length) return this.hideDeflection()\n this.deflectPanel.replaceChildren()\n this.deflectPanel.append(el('div', 'ocw-deflect-hint', 'Instant answers — tap to expand'))\n for (const a of articles.slice(0, 3)) {\n const card = el('button', 'ocw-deflect-card')\n card.append(el('div', 'ocw-deflect-q', a.title), el('div', 'ocw-deflect-a', a.answer))\n card.addEventListener('click', () => card.classList.toggle('open'))\n this.deflectPanel.append(card)\n }\n this.deflectPanel.style.display = 'flex'\n }\n\n hideDeflection(): void {\n this.deflectPanel.style.display = 'none'\n this.deflectPanel.replaceChildren()\n }\n\n private buildCsatPanel(): void {\n this.csatPanel.replaceChildren()\n this.csatPanel.append(el('div', 'ocw-csat-title', 'How did we do?'))\n const stars = el('div', 'ocw-csat-stars')\n const btns: HTMLButtonElement[] = []\n for (let i = 1; i <= 5; i++) {\n const b = el('button', 'ocw-csat-star', '★')\n b.dataset['score'] = String(i)\n b.addEventListener('mouseenter', () => btns.forEach((bb, idx) => bb.classList.toggle('lit', idx < i)))\n b.addEventListener('mouseleave', () => btns.forEach(bb => bb.classList.remove('lit')))\n b.addEventListener('click', () => {\n this.csatSubmitted = true\n this.csatPanel.replaceChildren(el('div', 'ocw-csat-done', `Thanks for your ${i}★ rating!`))\n this.h.onCsat?.(i)\n })\n btns.push(b); stars.append(b)\n }\n this.csatPanel.append(stars)\n }\n\n /** Whether the subject card (server Subject entity, mount config fallback)\n * has been built — built once when data first arrives. */\n private subjectBuilt = false\n\n private buildSubjectCard(store: ChatStore): void {\n if (this.subjectBuilt) return\n const s = store.subject\n const cfg = this.cfg.subject\n // Only show the subject card when there is actual subject data (from the\n // server) or an explicit subject config passed by the embedder (title,\n // tags, status). Never fall back to store.name — that's the domain/profile\n // name and is already shown in the header; rendering it here as well is\n // what caused the duplication seen in the Hotel front desk screenshot.\n const title = s?.title ?? cfg?.title\n if (!title) return\n this.subjectBuilt = true\n this.subjectCard.replaceChildren()\n this.subjectCard.append(el('div', 'ocw-subject-title', title))\n if (cfg?.subtitle) this.subjectCard.append(el('div', 'ocw-subject-sub', cfg.subtitle))\n const tags = el('div', 'ocw-tags')\n if (s) for (const [k, v] of Object.entries(s.fields)) tags.append(el('span', 'ocw-tag', `${k}: ${v}`))\n else for (const t of cfg?.tags ?? []) tags.append(el('span', 'ocw-tag', t))\n if (tags.childNodes.length) this.subjectCard.append(tags)\n const status = s?.state ?? cfg?.status\n if (status) { this.statusBadge.textContent = status; this.statusBadge.style.display = 'inline-flex' }\n }\n\n private chipEl(a: ManifestAction): HTMLButtonElement {\n const btn = el('button', 'ocw-chip', a.icon ? `${a.icon} ${a.label}` : a.label)\n btn.dataset['actionId'] = a.id\n btn.addEventListener('click', async () => {\n if (a.confirm && !(await this.confirm(a.label))) return\n if (a.input?.length) this.openForm(a)\n else this.h.onInvoke(a.id)\n })\n return btn\n }\n\n /** In-widget confirmation modal (replaces window.confirm). */\n private confirm(label: string): Promise<boolean> {\n return new Promise((resolve) => {\n const overlay = el('div', 'ocw-modal')\n const card = el('div', 'ocw-modal-card')\n card.append(el('div', 'ocw-modal-title', label))\n card.append(el('div', 'ocw-modal-body', `Confirm “${label}”?`))\n const row = el('div', 'ocw-modal-actions')\n const cancel = el('button', 'ocw-modal-cancel', 'Cancel')\n const ok = el('button', 'ocw-modal-ok', 'Confirm')\n const close = (v: boolean) => { overlay.remove(); resolve(v) }\n cancel.addEventListener('click', () => close(false))\n ok.addEventListener('click', () => close(true))\n overlay.addEventListener('click', (e) => { if (e.target === overlay) close(false) })\n row.append(cancel, ok); card.append(row); overlay.append(card)\n this.root.append(overlay)\n ok.focus()\n })\n }\n\n /** Inline form for a form-effect action: typed inputs (date picker, number,\n * text) rendered above the composer — no browser prompts. */\n private openForm(a: ManifestAction): void {\n this.formHost.replaceChildren()\n const panel = el('div', 'ocw-form')\n panel.append(el('div', 'ocw-form-title', a.icon ? `${a.icon} ${a.label}` : a.label))\n const inputs = new Map<string, HTMLInputElement>()\n for (const f of a.input ?? []) {\n const row = el('label', 'ocw-form-row'); row.append(el('span', 'ocw-form-lbl', f.label))\n if (f.type === 'select' && f.options?.length) {\n const sel = el('select', 'ocw-form-input')\n if (!f.required) sel.append(el('option', undefined, '— select —'))\n for (const opt of f.options) { const o = el('option'); o.value = opt; o.textContent = opt; sel.append(o) }\n if (f.required) sel.required = true\n row.append(sel)\n inputs.set(f.name, sel as unknown as HTMLInputElement)\n } else {\n const inp = el('input', 'ocw-form-input')\n inp.type = f.type === 'number' ? 'number' : f.type === 'date' ? 'datetime-local' : 'text'\n if (f.required) inp.required = true\n row.append(inp); inputs.set(f.name, inp)\n }\n panel.append(row)\n }\n const actions = el('div', 'ocw-form-actions')\n const cancel = el('button', 'ocw-form-cancel', 'Cancel')\n const submit = el('button', 'ocw-form-submit', 'Send')\n cancel.addEventListener('click', () => this.formHost.replaceChildren())\n submit.addEventListener('click', () => {\n const out: Record<string, unknown> = {}\n for (const [name, inp] of inputs) {\n if (inp.required && !inp.value) { inp.style.borderColor = '#e5484d'; return }\n out[name] = inp.type === 'number' ? Number(inp.value) : inp.value\n }\n this.formHost.replaceChildren()\n this.h.onInvoke(a.id, out)\n })\n actions.append(cancel, submit); panel.append(actions)\n this.formHost.append(panel)\n inputs.values().next().value?.focus()\n }\n\n private messageEl(m: RenderMessage, store: ChatStore, showLabel = false): HTMLElement {\n if (m.senderRole === 'system') {\n const sys = el('div', 'ocw-sys'); sys.textContent = m.deletedAt ? 'message deleted' : contentText(m.content); return sys\n }\n const mine = m.senderId === this.me\n const isNote = !!m.internal\n const row = el('div', `ocw-row ${isNote ? 'ocw-note mine' : mine ? 'mine' : 'theirs'} ${m.senderRole === 'bot' ? 'ocw-bot' : ''}`)\n const col = el('div')\n if (showLabel) {\n const who = m.senderRole === 'bot'\n ? (this.cfg.i18n?.aiAssistant ?? 'AI Assistant')\n : (this.cfg.subject?.ownerLabel ?? this.cfg.subject?.title ?? 'Support')\n col.append(el('div', 'ocw-msg-sender', who))\n }\n const bubbleWrap = el('div', 'ocw-bubble-wrap')\n // Reply-to context if present\n if (m.replyToId) {\n const replyCtx = el('div', 'ocw-reply-to', '↩ replying to a message')\n replyCtx.style.cssText = 'font-size:11px;color:var(--ocw-mut);margin-bottom:2px;font-style:italic'\n col.append(replyCtx)\n }\n const bubble = el('div', 'ocw-bubble')\n let textNode: Text | null = null\n if (m.deletedAt) bubble.append(el('span', 'ocw-deleted', 'message deleted'))\n else if (m.content.kind === 'attachment') {\n const c = m.content\n if (c.mime?.startsWith('image/')) {\n const img = document.createElement('img')\n img.src = c.url; img.alt = c.name ?? 'image'\n img.style.cssText = 'max-width:220px;max-height:160px;border-radius:10px;display:block;cursor:pointer'\n img.addEventListener('click', () => window.open(c.url, '_blank'))\n bubble.append(img)\n } else {\n const a = document.createElement('a')\n a.href = c.url; a.target = '_blank'; a.rel = 'noopener'\n a.style.cssText = 'display:flex;align-items:center;gap:8px;color:inherit;text-decoration:none'\n a.append(el('span', undefined, '📄'), el('span', undefined, c.name ?? 'file'))\n bubble.append(a)\n }\n } else {\n if (m.content.kind === 'appointment') {\n const ap = m.content\n const card = el('div', 'ocw-appt')\n card.append(el('div', 'ocw-appt-title', `\\u{1F4C5} ${ap.title}`))\n card.append(el('div', 'ocw-appt-time', new Date(ap.startIso).toLocaleString() + ' \\u2013 ' + new Date(ap.endIso).toLocaleTimeString()))\n if (ap.location) card.append(el('div', 'ocw-appt-loc', `\\u{1F4CD} ${ap.location}`))\n if (ap.description) card.append(el('div', 'ocw-appt-desc', ap.description))\n const links = el('div', 'ocw-appt-links')\n const gLink = document.createElement('a'); gLink.href = ap.googleUrl; gLink.target = '_blank'; gLink.rel = 'noopener'; gLink.className = 'ocw-appt-btn'; gLink.textContent = '\\u{1F4C5} Add to Google Calendar'\n const iLink = document.createElement('a'); iLink.href = ap.icalUrl; iLink.download = `${ap.title}.ics`; iLink.className = 'ocw-appt-btn ocw-appt-btn-sec'; iLink.textContent = '\\u{1F34E} Apple / iCal'\n links.append(gLink, iLink); card.append(links); bubble.append(card)\n } else {\n textNode = document.createTextNode(contentText(m.content))\n bubble.append(textNode)\n if (m.editedAt) bubble.append(el('span', 'ocw-edited', '(edited)'))\n }\n }\n bubbleWrap.append(bubble)\n\n // Live translation: only for the other party's plain-text messages (not notes).\n // The translation renders as its own line directly AFTER the original text —\n // both stay visible, the message is never overwritten — toggled by a button.\n if (!mine && !isNote && this.h.onTranslate && m.content.kind === 'text' && !m.deletedAt && m.seq > 0 && textNode) {\n const original = m.content.text\n if (original.trim()) {\n const translateBtn = el('button', 'ocw-translate-btn', '🌐')\n translateBtn.type = 'button'\n translateBtn.title = 'Translate'\n const transLine = el('div', 'ocw-translation')\n transLine.style.display = 'none'\n bubble.append(transLine)\n\n const showLine = (text: string): void => {\n transLine.textContent = text\n transLine.style.display = ''\n this.showingTranslation.add(m.id)\n translateBtn.textContent = '↩'\n translateBtn.title = 'Show original'\n }\n const hideLine = (): void => {\n transLine.style.display = 'none'\n this.showingTranslation.delete(m.id)\n translateBtn.textContent = '🌐'\n translateBtn.title = 'Translate'\n }\n\n translateBtn.addEventListener('click', (e) => {\n e.stopPropagation()\n if (this.showingTranslation.has(m.id)) { hideLine(); return }\n const cached = this.translationCache.get(m.id)\n if (cached !== undefined) { showLine(cached); return }\n translateBtn.textContent = '⏳'\n void this.h.onTranslate!(original).then((result) => {\n if (result === null) {\n translateBtn.textContent = '⚠️'\n translateBtn.title = 'Translation unavailable'\n setTimeout(() => { translateBtn.textContent = '🌐'; translateBtn.title = 'Translate' }, 1500)\n return\n }\n this.translationCache.set(m.id, result)\n showLine(result)\n })\n })\n bubbleWrap.append(translateBtn)\n\n // Keep a shown translation visible across re-renders.\n const cached = this.translationCache.get(m.id)\n if (this.showingTranslation.has(m.id) && cached !== undefined) showLine(cached)\n }\n }\n // Edit/delete context menu on own non-deleted messages\n if (mine && !m.deletedAt && m.seq > 0 && (this.h.onEdit ?? this.h.onDelete)) {\n const menu = el('div', 'ocw-msg-menu')\n if (this.h.onEdit) {\n const editBtn = el('button', undefined, '✏️')\n editBtn.title = 'Edit'\n editBtn.addEventListener('click', (e) => {\n e.stopPropagation()\n // Inline edit: replace bubble text with a small textarea + save/cancel\n const original = contentText(m.content)\n const ta = document.createElement('textarea')\n ta.value = original\n ta.rows = Math.min(4, Math.ceil(original.length / 40) + 1)\n ta.style.cssText = 'width:100%;resize:vertical;border:1px solid var(--ocw-accent);border-radius:8px;padding:6px 10px;font:inherit;font-size:14px;background:var(--ocw-card);color:#1c1b1a;box-sizing:border-box'\n const saveBtn = el('button', 'ocw-form-submit', 'Save')\n saveBtn.style.cssText = 'margin-top:6px;padding:5px 14px;font-size:13px'\n const cancelBtn = el('button', 'ocw-form-cancel', 'Cancel')\n cancelBtn.style.cssText = 'margin-top:6px;padding:5px 10px;font-size:13px'\n const btnRow = el('div'); btnRow.style.cssText = 'display:flex;gap:6px;justify-content:flex-end'\n btnRow.append(cancelBtn, saveBtn)\n const editPanel = el('div'); editPanel.append(ta, btnRow)\n bubble.replaceChildren(editPanel)\n ta.focus(); ta.select()\n const restore = () => bubble.replaceChildren(textNode ?? document.createTextNode(original))\n cancelBtn.addEventListener('click', restore)\n saveBtn.addEventListener('click', () => {\n const newText = ta.value.trim()\n if (newText && newText !== original) { this.h.onEdit!(m.id, newText); restore() }\n else restore()\n })\n ta.addEventListener('keydown', (ke) => {\n if (ke.key === 'Enter' && !ke.shiftKey) { ke.preventDefault(); saveBtn.click() }\n if (ke.key === 'Escape') restore()\n })\n })\n menu.append(editBtn)\n }\n if (this.h.onDelete) {\n const delBtn = el('button', 'del', '🗑')\n delBtn.title = 'Delete'\n delBtn.addEventListener('click', (e) => { e.stopPropagation(); this.h.onDelete!(m.id) })\n menu.append(delBtn)\n }\n bubbleWrap.append(menu)\n }\n col.append(bubbleWrap)\n\n // Reactions: existing pills + add-reaction picker (hover-revealed)\n if (this.h.onReact && !m.deletedAt && m.seq > 0) {\n const reactWrap = el('div', 'ocw-react-wrap')\n const reactRow = el('div', 'ocw-react')\n // Existing reaction pills\n if (m.reactions && Object.keys(m.reactions).length) {\n for (const [emoji, users] of Object.entries(m.reactions)) {\n const pill = el('button', `ocw-react-pill${(users as string[]).includes(this.me) ? ' mine' : ''}`, `${emoji} ${(users as string[]).length}`)\n pill.addEventListener('click', () => this.h.onReact?.(m.id, emoji, (users as string[]).includes(this.me)))\n reactRow.append(pill)\n }\n }\n // Add-reaction button + picker\n const addBtn = el('button', 'ocw-react-btn', '+')\n const picker = el('div', 'ocw-react-picker')\n for (const emoji of REACTION_EMOJIS) {\n const pb = el('button', undefined, emoji)\n pb.addEventListener('click', (e) => {\n e.stopPropagation()\n const alreadyReacted = m.reactions?.[emoji]?.includes(this.me as never)\n this.h.onReact?.(m.id, emoji, !!alreadyReacted)\n picker.style.display = 'none'\n })\n picker.append(pb)\n }\n picker.style.display = 'none'\n addBtn.addEventListener('click', (e) => {\n e.stopPropagation()\n const opening = picker.style.display === 'none'\n picker.style.display = opening ? 'flex' : 'none'\n // Close on the next outside click. Registered only when OPENING —\n // the old code added one document listener per message on EVERY\n // render, so long conversations piled up hundreds of stale handlers.\n if (opening) document.addEventListener('click', () => { picker.style.display = 'none' }, { once: true })\n })\n reactRow.append(addBtn)\n reactWrap.append(reactRow, picker)\n col.append(reactWrap)\n } else if (m.reactions && Object.keys(m.reactions).length) {\n col.append(el('div', 'ocw-react', Object.entries(m.reactions).map(([e, u]) => `${e}${(u as string[]).length}`).join(' ')))\n }\n const meta = el('div', 'ocw-time ocw-meta', fmtTime(m.ts))\n if (mine && m.status) {\n const t = el('span', `ocw-tick${m.status === 'read' ? ' read' : m.status === 'delivered' ? ' delivered' : ''}`, tick(m.status))\n meta.append(t)\n }\n // \"Seen\" indicator when agent has read past this message\n if (mine && m.seq > 0 && store.lastReadByOthers >= m.seq) {\n meta.append(el('span', 'ocw-seen', ' · Seen'))\n }\n col.append(meta)\n row.append(col)\n return row\n }\n}\n\nfunction tick(s: NonNullable<RenderMessage['status']>): string {\n switch (s) {\n case 'read': return '✓✓' // blue double tick rendered via CSS colour\n case 'delivered': return '✓✓'\n case 'sent': return '✓'\n default: return '🕓'\n }\n}\n","// 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","import { persistentUid } from './uid.js'\nimport {\n asConversationId,\n type ClientFrame, type ConversationId,\n} from './protocol/index.js'\nimport { ChatStore } from './store.js'\nimport { ConnectionManager } from './connection.js'\nimport { PersistentOutbox } from './outbox.js'\nimport { E2ESession, extractX3DHInit } from './e2e.js'\nimport { Renderer, type WidgetConfig } from './renderer.js'\nimport { restoreHistory, resolveRelayUrls } from './history.js'\n\nexport interface UserInfo {\n /** Display name shown in the conversation (e.g. \"Sarah Chen\"). */\n name?: string\n /** Email address — passed as conversation metadata for agent context. */\n email?: string\n /** Avatar URL — shown as the guest's avatar in both widget and dashboard. */\n avatar?: string\n /** Any custom key/value metadata to attach to the conversation\n * (e.g. plan tier, account ID, page URL). Shown to agents in the sidebar. */\n meta?: Record<string, string>\n}\n\nexport interface MountOptions {\n el: HTMLElement\n /** Relay URL. Any scheme works — `https://api.example.com` is fine; the widget\n * derives the WebSocket URL (`wss://…/ws`) and REST base from it. */\n url: string\n /** HTTP(S) base for REST calls — only needed when the REST API is on a\n * DIFFERENT origin than the socket. Normally leave unset. */\n apiUrl?: string\n profileId: string\n subjectId?: string\n /** Open a user↔user direct conversation with `peerId` instead of a support\n * thread. Requires signed identity on the chatroom (both `kind: 'direct'`\n * and `peerId` together; `subjectId` is ignored — the server derives the\n * symmetric DM key so both sides land in the SAME conversation). */\n kind?: 'direct'\n peerId?: string\n /** IDENTITY (tiered — the host owns identity, the widget never has to persist it):\n * 1. `token` — a signed identity token. Either a capability token, or (recommended\n * for embedders) an ES256 JWT `{sub,iat,exp}` signed by your backend with the\n * private key whose public half is set as the chatroom's `guestPublicKey`.\n * The server cryptographically verifies it. Works in ANY language/environment,\n * no cookies or storage required. This is the production path.\n * 2. `userId` — a stable id you already have for the visitor (e.g. your logged-in\n * user id). Unauthenticated (\"you vouch for it\") but works everywhere. Used\n * only when `token` is absent.\n * 3. Neither — the widget falls back to best-effort local identity on the host\n * origin (first-party cookie + localStorage). A returning visitor on the same\n * browser keeps their history; if storage is blocked they get a fresh chat. */\n token?: string\n /** Called when a signed token is rejected (expired): return a fresh token\n * from your backend to renew the session without a reload. */\n refreshToken?: () => Promise<string | null>\n userId?: string\n subject?: WidgetConfig['subject']\n quickReplies?: string[]\n accent?: string\n /** Secondary accent (guest bubble + send button). Defaults to the design\n * blue; omit and it follows `accent` for a cohesive single-token retheme. */\n accent2?: string\n /** Colour scheme. Default 'light'. 'auto' follows the OS; 'dark'/'light' force it. */\n theme?: 'auto' | 'light' | 'dark'\n /** Load Baloo 2 + Nunito webfonts (default true). false = system fonts only. */\n webfont?: boolean\n /** Stack navigation: when set, the chatroom header shows a back chevron that\n * calls this. Used by `<ChatApp>` so tapping a conversation opens the room and\n * the back arrow returns to the list — native-app style. */\n onBack?: () => void\n /** If set, shows a 🌐 translate button on incoming messages that translates\n * them into this language (ISO code or language name) via the server's\n * /translate endpoint. Omit to disable the feature. */\n translateLang?: string\n /** If true, mount as a floating launcher button that opens/closes the chat */\n launcher?: boolean\n /** Position of the launcher button: default 'bottom-right' */\n position?: 'bottom-right' | 'bottom-left'\n /** Launcher teaser — the \"optional message\" card shown ABOVE the closed\n * launcher button to invite a chat (like Channel.io's greeting). Pass a\n * string for just a title, or `{ title, subtitle }`. If omitted, the\n * widget uses `defaults.launcherMessage` from the chatroom manifest when\n * present. Dismissible by the visitor (remembered for the browser session);\n * auto-hides once the chat is opened. Only applies in `launcher` mode. */\n launcherMessage?: string | { title: string; subtitle?: string }\n /** Optional user info for identified users. When provided, the name/email/\n * avatar are shown to agents in the dashboard instead of the anonymous ID.\n * The token still controls identity — this is display metadata only.\n * Anonymous users (no token, no user) remain fully anonymous. */\n user?: UserInfo\n /** Optional per-tenant feature switches. All default to ON (omit for current\n * behavior). Set a flag to `false` to disable the feature — the widget then\n * does no work for it (no reaction picker built per message, no CSAT panel,\n * no KB-deflection lookups). Gating is by not wiring the handler, so the\n * renderer skips the feature entirely. */\n features?: {\n reactions?: boolean // emoji reactions on messages (default true)\n csat?: boolean // post-resolution satisfaction survey (default true)\n deflection?: boolean // pre-first-message KB article suggestions (default true)\n }\n /** i18n: override UI strings. All keys are optional — omitted keys fall\n * back to English defaults. */\n i18n?: {\n placeholder?: string // input placeholder, default \"Message…\"\n send?: string // send button label, default \"➤\"\n offline?: string // offline panel title, default \"We're offline right now\"\n poweredBy?: string // footer text, default \"Powered by Relay\"\n online?: string // header status when available, default \"Online\"\n away?: string // header status when offline, default \"Away\"\n aiAssistant?: string // speaker label for bot messages, default \"AI Assistant\"\n resolved?: string // resolved divider text, default \"Marked as resolved\"\n reopen?: string // reopen button label, default \"Reopen conversation\"\n }\n}\n\nexport interface WidgetHandle { close(): void }\n\n\n// ── Mount registry ────────────────────────────────────────────────────────────\n// Tracks active widget instances per host element. Prevents double-mounting\n// when React strict mode, HMR, or caller code calls mount() twice on the same\n// element — the most common cause of two widgets appearing on one page.\nconst _registry = new WeakMap<Element, WidgetHandle>()\n// Launcher widgets attach to document.body (not the ref div), and in launcher\n// mode React may re-create the ref div on re-render — so the el-keyed registry\n// above can't catch a stale launcher. This slot-keyed registry guarantees at\n// most ONE launcher per (profileId, subjectId), so an identity flicker or\n// re-render can never leave two stacked bubbles/panels on the page.\nconst _launcherRegistry = new Map<string, WidgetHandle>()\nfunction launcherSlot(opts: MountOptions): string {\n return `relay-launcher::${opts.profileId}::${opts.subjectId ?? ''}`\n}\n\n// One AudioContext for ALL widget instances on the page (notification blips\n// are fire-and-forget; nothing about them is per-instance).\nlet _audioCtx: AudioContext | null = null\nfunction getAudioContext(): AudioContext | null {\n if (_audioCtx && _audioCtx.state !== 'closed') return _audioCtx\n try { _audioCtx = new AudioContext(); return _audioCtx } catch { return null }\n}\n\n/** Unmount any widget currently mounted on `el`. No-op if nothing is mounted. */\nexport function unmount(el: Element): void {\n _registry.get(el)?.close()\n _registry.delete(el)\n}\n\nexport function mount(opts: MountOptions): WidgetHandle {\n // Auto-close any previous instance on this exact element before re-mounting.\n // Covers React double-invoke in StrictMode, HMR, and accidental duplicate calls.\n if (_registry.has(opts.el)) {\n _registry.get(opts.el)!.close()\n _registry.delete(opts.el)\n }\n // Launcher mode: also close any prior launcher for the same slot, even if it\n // was mounted on a now-detached div (React re-creates the ref div on\n // re-render). This is what prevents two stacked widgets after an identity\n // flicker (anonymous → logged-in).\n if (opts.launcher) _launcherRegistry.get(launcherSlot(opts))?.close()\n\n // Tiered identity (see MountOptions): a host-provided signed token wins, then a\n // host-vouched userId, then best-effort local persistence. The widget never\n // depends on its own storage when the host supplies identity — which is what\n // makes it safe to embed in any environment (iframes, webviews, SSR, etc.).\n // Always keep the stable per-browser anonymous id, even when the host\n // identifies the visitor — so on login we can tell the server to merge the\n // anonymous conversation into the user (Channel.io-style boot+identify).\n const anonId = persistentUid()\n let deflectTimer: ReturnType<typeof setTimeout> | undefined\n let destroyed = false\n const token = opts.token ?? opts.userId ?? anonId\n // If we're connecting as an identified user (token differs from the anon id),\n // pass the anon id as linkFrom so the server adopts any anonymous history.\n const linkFrom = token !== anonId ? anonId : undefined\n // Accept any scheme on `url` (https/http/wss/ws) and derive both the concrete\n // WebSocket URL and the REST base from it. `apiUrl` overrides the REST base\n // only when the API is on a different origin than the socket.\n const { wsUrl, httpBase } = resolveRelayUrls(opts.url, opts.apiUrl)\n let store = new ChatStore(token as never)\n // Key the outbox by token + subjectId so each listing has its own pending queue.\n // Without this, a pending message from listing A appears as a ghost on listing B.\n const outboxKey = opts.subjectId ? `${token}::${opts.subjectId}` : token\n const outbox = new PersistentOutbox(outboxKey)\n let cid: ConversationId | undefined\n let outboxRestored = false\n\n let _mql: MediaQueryList | null = null\n let _mqlHandler: ((e: MediaQueryListEvent) => void) | null = null\n let _escHandler: ((e: KeyboardEvent) => void) | null = null\n let _paintTeaser: (() => void) | null = null\n // (e.g. a bare `<div id=\"chat\"></div>` with no CSS). Without this the\n // widget's internal `height:100%` collapses to near-zero. Only applies\n // when the element truly has no height set — explicit CSS always wins.\n if (!opts.launcher && !opts.el.style.height && opts.el.clientHeight === 0) {\n opts.el.style.width = opts.el.style.width || '100%'\n opts.el.style.height = '600px'\n }\n\n // Restore pending outbox items for this specific listing/conversation.\n // The outbox is keyed by token+subjectId so ghost bubbles from other listings\n // never appear here.\n for (const item of outbox.load()) store.addOptimistic(item.clientMsgId, item.content)\n\n // ── Launcher mode ─────────────────────────────────────────────────────────\n let launcherEl: HTMLElement | null = null\n let badgeEl: HTMLElement | null = null\n let unread = 0\n let open = !opts.launcher // start open when not in launcher mode\n\n if (opts.launcher) {\n const pos = opts.position ?? 'bottom-right'\n const isRight = pos.includes('right')\n\n // Outer wrapper holds both the panel and the bubble button\n launcherEl = document.createElement('div')\n launcherEl.style.cssText = `position:fixed;${isRight ? 'right:20px' : 'left:20px'};bottom:20px;z-index:9999;display:flex;flex-direction:column;align-items:${isRight ? 'flex-end' : 'flex-start'};gap:12px`\n\n // ── Chat panel — sits above the bubble ─────────────────────────────────\n const panel = document.createElement('div')\n // Responsive panel: full-screen on mobile (<480px); on desktop 380×600\n // CLAMPED to the viewport (`min(…)`) so a short or narrow browser window\n // never clips the composer — same clamp the React launcher already uses.\n // A MediaQueryList keeps the layout live across rotation/resize.\n const mql = typeof window !== 'undefined' && typeof window.matchMedia === 'function'\n ? window.matchMedia('(max-width: 479px)') : null\n const applyPanelLayout = (mobile: boolean) => {\n // Fullscreen is the ONLY case that strips the widget's corner radius —\n // the renderer keys .ocw-fs, never a blanket viewport query, so inline\n // mobile embeds keep their normal in-page layout.\n opts.el.classList.toggle('ocw-fs', mobile)\n panel.style.cssText = mobile ? [\n 'position:fixed', 'inset:0', 'width:100%', 'height:100dvh',\n 'border-radius:0', 'overflow:hidden',\n 'box-shadow:none', 'display:none', 'flex-direction:column', 'background:#fff',\n 'transition:opacity .18s', 'opacity:0', 'z-index:9998',\n ].join(';') : [\n 'width:min(380px, calc(100vw - 40px))', 'height:min(600px, calc(100dvh - 108px))',\n 'border-radius:28px', 'overflow:hidden',\n 'box-shadow:0 12px 32px rgba(108,92,231,.14)',\n 'display:none', 'flex-direction:column', 'background:#fff',\n 'transform-origin:bottom ' + (isRight ? 'right' : 'left'),\n 'transition:opacity .18s,transform .18s', 'opacity:0', 'transform:scale(.95)',\n ].join(';')\n }\n applyPanelLayout(mql?.matches ?? false)\n const mqlHandler = (e: MediaQueryListEvent): void => applyPanelLayout(e.matches)\n mql?.addEventListener('change', mqlHandler)\n _mql = mql; _mqlHandler = mqlHandler\n\n // Move the mount target INSIDE the panel — not full-page\n opts.el.style.cssText = 'width:100%;height:100%;overflow:hidden'\n panel.append(opts.el)\n\n // ── Bubble button ─────────────────────────────────────────────────────\n // Inline SVGs, not emoji: '💬'/'✕' render differently on every OS (and as\n // colour emoji can clash with the accent); these are crisp everywhere.\n const CHAT_SVG =\n '<svg viewBox=\"0 0 24 24\" width=\"26\" height=\"26\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\" aria-hidden=\"true\">' +\n '<path d=\"M21 11.5a8.38 8.38 0 0 1-.9 3.8 8.5 8.5 0 0 1-7.6 4.7 8.38 8.38 0 0 1-3.8-.9L3 21l1.9-5.7a8.38 8.38 0 0 1-.9-3.8 8.5 8.5 0 0 1 4.7-7.6 8.38 8.38 0 0 1 3.8-.9h.5a8.48 8.48 0 0 1 8 8v.5z\" ' +\n 'fill=\"currentColor\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/></svg>'\n const CLOSE_SVG =\n '<svg viewBox=\"0 0 24 24\" width=\"22\" height=\"22\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\" aria-hidden=\"true\">' +\n '<path d=\"M18 6 6 18M6 6l12 12\" stroke=\"currentColor\" stroke-width=\"2.5\" stroke-linecap=\"round\"/></svg>'\n\n const btn = document.createElement('button')\n btn.type = 'button'\n btn.style.cssText = [\n `width:56px;height:56px;border-radius:50%`,\n `background:${opts.accent ?? '#6c5ce7'}`,\n `color:#fff;border:none;cursor:pointer`,\n `box-shadow:0 12px 32px rgba(108,92,231,.14)`,\n `position:relative;flex:none`,\n `display:flex;align-items:center;justify-content:center`,\n `transition:transform .15s`,\n ].join(';')\n btn.onmouseenter = () => { btn.style.transform = 'scale(1.08)' }\n btn.onmouseleave = () => { btn.style.transform = 'scale(1)' }\n\n badgeEl = document.createElement('span')\n badgeEl.style.cssText = `position:absolute;top:-4px;right:-4px;background:#4c6fff;color:#fff;border-radius:50%;width:20px;height:20px;font-size:11px;font-weight:700;display:none;align-items:center;justify-content:center`\n\n // (Re)build the bubble's content for the current open state. innerHTML\n // wipes children, so the badge is re-appended each time.\n const paintBubble = () => {\n btn.innerHTML = open ? CLOSE_SVG : CHAT_SVG\n btn.setAttribute('aria-label', open ? 'Close chat' : 'Open chat')\n btn.setAttribute('aria-expanded', String(open))\n btn.append(badgeEl!)\n }\n paintBubble()\n\n launcherEl.append(panel, btn)\n document.body.append(launcherEl)\n\n // ── Launcher teaser (the \"optional message\" card) ─────────────────────\n // A small dismissible card above the button inviting a chat. Source of\n // truth: the explicit `launcherMessage` option (instant), else the\n // chatroom manifest's `defaults.launcherMessage` (arrives on connect).\n // Dismissal is per browser session so it doesn't nag across page nav.\n const teaserKey = `ocw-teaser-dismissed::${opts.profileId}`\n const optMsg = typeof opts.launcherMessage === 'string'\n ? { title: opts.launcherMessage }\n : opts.launcherMessage\n let teaserEl: HTMLElement | null = null\n const teaserDismissed = (): boolean => {\n try { return sessionStorage.getItem(teaserKey) === '1' } catch { return false }\n }\n const CHAT_MINI_SVG =\n '<svg viewBox=\"0 0 24 24\" width=\"15\" height=\"15\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\" aria-hidden=\"true\">' +\n '<path d=\"M21 11.5a8.38 8.38 0 0 1-.9 3.8 8.5 8.5 0 0 1-7.6 4.7 8.38 8.38 0 0 1-3.8-.9L3 21l1.9-5.7a8.38 8.38 0 0 1-.9-3.8 8.5 8.5 0 0 1 4.7-7.6 8.38 8.38 0 0 1 3.8-.9h.5a8.48 8.48 0 0 1 8 8v.5z\" ' +\n 'fill=\"currentColor\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/></svg>'\n const paintTeaser = (): void => {\n const msg = optMsg?.title ? optMsg : (store.launcherMessage ?? undefined)\n const shouldShow = !!msg?.title && !open && !teaserDismissed()\n if (!shouldShow) { if (teaserEl) { teaserEl.remove(); teaserEl = null } return }\n if (teaserEl) return // already shown; don't rebuild (avoids flicker)\n teaserEl = document.createElement('div')\n teaserEl.setAttribute('role', 'button')\n teaserEl.setAttribute('tabindex', '0')\n teaserEl.setAttribute('aria-label', msg!.title)\n teaserEl.style.cssText = [\n 'max-width:280px', 'background:#fff', 'border-radius:16px',\n 'box-shadow:0 12px 32px rgba(108,92,231,.14)', 'padding:14px 40px 14px 16px',\n 'position:relative', 'cursor:pointer', 'font-family:inherit',\n `align-self:${isRight ? 'flex-end' : 'flex-start'}`,\n 'animation:ocw-teaser-in .22s ease-out',\n ].join(';')\n const title = document.createElement('div')\n title.textContent = msg!.title\n title.style.cssText = 'font-size:15px;font-weight:600;color:#111;line-height:1.35'\n teaserEl.append(title)\n if (msg!.subtitle) {\n const sub = document.createElement('div')\n sub.style.cssText = 'display:flex;align-items:center;gap:6px;margin-top:6px;font-size:13px;color:#6b7280'\n const ic = document.createElement('span'); ic.innerHTML = CHAT_MINI_SVG; ic.style.cssText = `color:${opts.accent ?? '#6c5ce7'};display:inline-flex`\n const st = document.createElement('span'); st.textContent = msg!.subtitle\n sub.append(ic, st); teaserEl.append(sub)\n }\n // Close (×) — dismiss for the session without opening the chat.\n const x = document.createElement('button')\n x.type = 'button'\n x.setAttribute('aria-label', 'Dismiss')\n x.innerHTML = '<svg viewBox=\"0 0 24 24\" width=\"14\" height=\"14\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\"><path d=\"M18 6 6 18M6 6l12 12\" stroke=\"currentColor\" stroke-width=\"2.5\" stroke-linecap=\"round\"/></svg>'\n x.style.cssText = 'position:absolute;top:8px;right:8px;width:24px;height:24px;border:none;border-radius:50%;background:#f3f4f6;color:#6b7280;cursor:pointer;display:flex;align-items:center;justify-content:center;padding:0'\n x.addEventListener('click', (e) => {\n e.stopPropagation()\n try { sessionStorage.setItem(teaserKey, '1') } catch { /* storage blocked — dismiss for this pageview only */ }\n if (teaserEl) { teaserEl.remove(); teaserEl = null }\n })\n teaserEl.append(x)\n const openFromTeaser = (): void => {\n if (open) return\n open = true; showPanel(true); paintBubble()\n unread = 0; if (badgeEl) badgeEl.style.display = 'none'\n if (teaserEl) { teaserEl.remove(); teaserEl = null }\n }\n teaserEl.addEventListener('click', openFromTeaser)\n teaserEl.addEventListener('keydown', (e) => { if (e.key === 'Enter' || e.key === ' ') { e.preventDefault(); openFromTeaser() } })\n // Insert ABOVE the button (button is the last child of launcherEl).\n launcherEl!.insertBefore(teaserEl, btn)\n }\n // Keyframes for the gentle pop-in (injected once).\n if (!document.getElementById('ocw-teaser-style')) {\n const st = document.createElement('style'); st.id = 'ocw-teaser-style'\n st.textContent = '@keyframes ocw-teaser-in{from{opacity:0;transform:translateY(8px)}to{opacity:1;transform:translateY(0)}}'\n document.head.append(st)\n }\n _paintTeaser = paintTeaser\n paintTeaser() // shows immediately when the option is set; manifest repaints later\n\n const showPanel = (show: boolean) => {\n if (show) {\n panel.style.display = 'flex'\n requestAnimationFrame(() => { panel.style.opacity = '1'; panel.style.transform = 'scale(1)' })\n } else {\n panel.style.opacity = '0'; panel.style.transform = 'scale(.95)'\n setTimeout(() => { if (!open) panel.style.display = 'none' }, 180)\n }\n }\n\n btn.addEventListener('click', () => {\n open = !open\n showPanel(open)\n paintBubble()\n if (open) {\n unread = 0; if (badgeEl) badgeEl.style.display = 'none'\n // Opening satisfies the teaser's whole purpose — retire it for the session.\n try { sessionStorage.setItem(teaserKey, '1') } catch { /* ignore */ }\n }\n _paintTeaser?.()\n })\n\n // Close on Escape. Kept as a named handler so close() can REMOVE it —\n // the old anonymous listener outlived the widget (leaked on every\n // remount/identify, and a stale one could still flip `open`).\n _escHandler = (e: KeyboardEvent) => {\n if (e.key === 'Escape' && open) { open = false; showPanel(false); paintBubble() }\n }\n document.addEventListener('keydown', _escHandler)\n }\n\n const addUnread = () => {\n if (open) return\n unread++\n if (badgeEl) { badgeEl.textContent = String(unread); badgeEl.style.display = 'flex' }\n }\n\n // ── Notification sound ────────────────────────────────────────────────────\n const playSound = () => {\n try {\n // ONE lazy shared context, resumed on each play. The old code created a\n // fresh AudioContext per message; browsers cap concurrent contexts (~6\n // in Chrome), after which construction throws and chat goes silent.\n const ctx = getAudioContext()\n if (!ctx) return\n if (ctx.state === 'suspended') void ctx.resume().catch(() => {})\n const osc = ctx.createOscillator(); const gain = ctx.createGain()\n osc.connect(gain); gain.connect(ctx.destination)\n osc.frequency.setValueAtTime(880, ctx.currentTime)\n osc.frequency.exponentialRampToValueAtTime(440, ctx.currentTime + 0.15)\n gain.gain.setValueAtTime(0.3, ctx.currentTime)\n gain.gain.exponentialRampToValueAtTime(0.001, ctx.currentTime + 0.3)\n osc.start(); osc.stop(ctx.currentTime + 0.3)\n } catch { /* audio not available */ }\n }\n\n // Messages typed before the 'opened' frame arrives are queued here and\n // flushed once cid is known. This prevents silent message loss when the\n // user types immediately after the widget mounts (before WS handshake).\n const preSendQueue: { clientMsgId: string; content: import('./protocol/index.js').MessageContent }[] = []\n\n const flushPreSendQueue = (conversationId: ConversationId) => {\n while (preSendQueue.length) {\n const item = preSendQueue.shift()!\n outbox.add({ clientMsgId: item.clientMsgId, content: item.content, ts: Date.now() })\n conn.send({ type: 'send', conversationId, clientMsgId: item.clientMsgId, content: item.content })\n }\n }\n\n let conn: ConnectionManager\n // E2E is compiled out of the 'lite' build (__E2E__=false) via dead-code\n // elimination — non-encrypted chatrooms don't ship the crypto. In the lite\n // build e2e is null and encrypted rooms are refused (never sent as plaintext).\n const e2e = __E2E__ ? new E2ESession(`ocw-e2e-${opts.profileId}`) : null\n let e2eStarted = false\n // Live ECDH pending (peer not yet online)\n const pending: { clientMsgId: string; text: string }[] = []\n // X3DH async: pending send awaiting the peer's prekey bundle\n const x3dhPending: { clientMsgId: string; text: string }[] = []\n let x3dhBundleFetched = false\n\n const sendSealed = (clientMsgId: string, text: string): void => {\n void e2e!.sealText(text).then((content) => {\n if (cid) conn.send({ type: 'send', conversationId: cid, clientMsgId, content })\n })\n }\n\n const sendSealedX3DH = (clientMsgId: string, text: string, x3dhInit: { ephemeralKey: string; spkId: string; senderIK: string; usedOTP: boolean }): void => {\n void e2e!.sealText(text, x3dhInit).then((content) => {\n if (cid) conn.send({ type: 'send', conversationId: cid, clientMsgId, content })\n })\n }\n\n const flushPending = (): void => {\n while (pending.length) { const p = pending.shift()!; sendSealed(p.clientMsgId, p.text) }\n while (x3dhPending.length) { const p = x3dhPending.shift()!; sendSealed(p.clientMsgId, p.text) }\n }\n\n /** Fetch the peer's prekey bundle and perform X3DH sender init. */\n const fetchAndX3DH = (targetUserId: string): void => {\n conn.send({ type: 'fetchPrekey', targetUserId: targetUserId as never })\n }\n\n const i18n = opts.i18n ?? {}\n // Auto-detect RTL for Arabic/Hebrew/Persian/Urdu regardless of i18n strings\n const rtlLocales = ['ar', 'he', 'fa', 'ur']\n const browserLang = typeof navigator !== 'undefined' ? (navigator.language ?? '').slice(0, 2).toLowerCase() : ''\n if (rtlLocales.includes(browserLang) && !opts.el.dir) {\n opts.el.dir = 'rtl'\n opts.el.style.fontFamily = opts.el.style.fontFamily || 'Tahoma,Arial,system-ui,sans-serif'\n }\n // Pre-chat completion is per (chatroom, identity) — a returning visitor who\n // already qualified goes straight to the composer.\n const preChatKey = `oc_prechat_${opts.profileId}_${token.slice(-8)}`\n\n const renderer = new Renderer(opts.el, token, {\n onSend(text) {\n const clientMsgId = `cm_${Math.random().toString(36).slice(2)}`\n const content: import('./protocol/index.js').MessageContent = { kind: 'text', text }\n store.addOptimistic(clientMsgId, content)\n renderer.render(store)\n if (store.e2e) {\n if (!__E2E__) {\n console.error('[relay] this chat is end-to-end encrypted — use the full widget build')\n return\n }\n if (e2e!.ready) {\n sendSealed(clientMsgId, text)\n } else if (x3dhBundleFetched) {\n x3dhPending.push({ clientMsgId, text })\n } else {\n pending.push({ clientMsgId, text })\n if (store.assignedAgentId) fetchAndX3DH(store.assignedAgentId)\n }\n } else if (!cid) {\n // Connection not yet opened — queue the message; flushed on 'opened'\n preSendQueue.push({ clientMsgId, content })\n } else {\n outbox.add({ clientMsgId, content, ts: Date.now() })\n conn.send({ type: 'send', conversationId: cid, clientMsgId, content })\n }\n },\n async onAttach(file: File) {\n if (!cid) return\n const uploadUrl = `${httpBase}/upload?name=${encodeURIComponent(file.name)}`\n const clientMsgId = `cm_${Math.random().toString(36).slice(2)}`\n // Optimistic: show uploading state\n store.addOptimistic(clientMsgId, { kind: 'text', text: `📎 Uploading ${file.name}…` })\n renderer.render(store)\n try {\n const res = await fetch(uploadUrl, {\n method: 'POST',\n // Use the resolved connection token (a signed JWT, an explicit userId,\n // or the anonymous persistent uid) — NOT just opts.token. The server\n // requires an Authorization header, and the verifier accepts an\n // anonymous id as a guest; keying off opts.token alone meant anonymous\n // visitors (the common case) sent no auth and every upload 401'd.\n headers: { 'content-type': file.type, authorization: `Bearer ${token}` },\n body: file,\n })\n if (!res.ok) throw new Error(`Upload failed: ${res.status}`)\n const { url, name, mime, size } = await res.json() as { url: string; name: string; mime: string; size: number }\n // Swap the \"📎 Uploading…\" placeholder for the REAL attachment content,\n // keyed by the SAME clientMsgId, BEFORE we send. Without this the\n // optimistic entry stayed as placeholder text: the server's `ack`\n // carries no content (see frames.ts), so reconciliation did\n // `{...msg, status:'sent'}` and kept the \"Uploading…\" text forever. The\n // real attachment only appeared on the next history fetch — i.e. after\n // a refresh — which reads exactly as \"the upload is slow\" even though\n // it already succeeded. Re-seeding here means the ack confirms an\n // attachment, and it renders immediately in the live view.\n store.addOptimistic(clientMsgId, { kind: 'attachment', url, name, mime, size })\n renderer.render(store)\n conn.send({ type: 'send', conversationId: cid, clientMsgId, content: { kind: 'attachment', url, name, mime, size } })\n } catch (e) {\n store.addOptimistic(clientMsgId, { kind: 'text', text: `⚠️ Upload failed: ${(e as Error).message}` })\n renderer.render(store)\n }\n },\n onInvoke(actionId, inputs) {\n if (!cid) return\n conn.send({ type: 'invoke', conversationId: cid, actionId, clientInvokeId: `iv_${Math.random().toString(36).slice(2)}`, ...(inputs ? { inputs } : {}) })\n },\n onTyping(isTyping, preview) { if (cid) conn.send({ type: 'typing', conversationId: cid, isTyping, ...(preview ? { preview } : {}) }) },\n onPreChat(values) {\n // Persist \"done\" per (chatroom, browser identity) so reloads skip the form.\n try { localStorage.setItem(preChatKey, '1') } catch { /* private mode */ }\n // Identity fields flow through the SAME open+userInfo path the host's\n // `user` config uses — the engine sanitizes and stores them on the\n // conversation (guestName/guestEmail; phone lands in guest meta).\n conn.send({\n type: 'open', profileId: opts.profileId as never,\n ...(opts.subjectId ? { subjectId: opts.subjectId as never } : {}),\n userInfo: {\n ...(values.name ? { name: values.name } : {}),\n ...(values.email ? { email: values.email } : {}),\n ...(values.phone || values.topic ? { meta: {\n ...(values.phone ? { phone: values.phone } : {}),\n ...(values.topic ? { topic: values.topic } : {}),\n } } : {}),\n },\n } as never)\n // Topic / callback become the visible first line so agents see the\n // qualification without opening the CRM pane. A callback request is\n // explicit and carries the number.\n const first = values.callback\n ? `📞 Call-back requested${values.phone ? `: ${values.phone}` : ''}${values.topic ? ` — ${values.topic}` : ''}`\n : values.topic ? `Topic: ${values.topic}` : ''\n // E2E rooms: identity fields still flow (userInfo above), but the\n // qualification line must not be sent as plaintext into an encrypted\n // conversation — agents see topic/phone in the CRM pane instead.\n if (first && cid && !store.e2e) {\n conn.send({ type: 'send', conversationId: cid, clientMsgId: `pc_${Math.random().toString(36).slice(2, 12)}`, content: { kind: 'text', text: first } })\n }\n },\n ...(opts.features?.deflection !== false ? {\n onDeflectQuery(q: string) {\n if (destroyed) return\n // Debounced keyword lookup against the chatroom's KB — \"was this your\n // question?\" before the first message ever sends. Fails silent: a KB\n // hiccup must never affect typing.\n clearTimeout(deflectTimer)\n const query = q.trim()\n if (query.length < 3) { renderer.hideDeflection(); return }\n deflectTimer = setTimeout(() => {\n void fetch(`${httpBase}/kb/search?profileId=${encodeURIComponent(opts.profileId)}&q=${encodeURIComponent(query.slice(0, 200))}`)\n .then(r => (r.ok ? r.json() : { articles: [] }))\n .then((d: { articles?: { id: string; title: string; answer: string }[] }) => renderer.showDeflection(d.articles ?? []))\n .catch(() => renderer.hideDeflection())\n }, 350)\n },\n } : {}),\n onReadUpTo(seq) { if (cid) conn.send({ type: 'read', conversationId: cid, seq }) },\n onLoadMore() {\n // WS fallback for E2E rooms where REST history can't be decrypted.\n // Non-E2E rooms use scroll-triggered REST pagination from restoreHistory().\n if (!cid || !store.e2e) return\n const oldest = store.messages()[0]\n if (oldest) conn.send({ type: 'history', conversationId: cid, beforeSeq: oldest.seq, limit: 20 })\n },\n onEdit(messageId, newText) {\n if (cid) conn.send({ type: 'edit', conversationId: cid, messageId: messageId as never, content: { kind: 'text', text: newText } })\n },\n onDelete(messageId) {\n if (cid) conn.send({ type: 'delete', conversationId: cid, messageId: messageId as never })\n },\n ...(opts.features?.reactions !== false ? {\n onReact(messageId: string, emoji: string, remove: boolean) {\n if (!cid) return\n conn.send({ type: 'react', conversationId: cid, messageId: messageId as never, emoji, remove })\n },\n } : {}),\n ...(opts.features?.csat !== false ? {\n onCsat(score: number) {\n if (!cid) return\n fetch(`${httpBase}/conversations/${cid}/csat`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${token}` },\n body: JSON.stringify({ score }),\n }).catch(() => {})\n },\n } : {}),\n ...(opts.translateLang ? {\n async onTranslate(text: string) {\n try {\n const res = await fetch(`${httpBase}/translate`, {\n method: 'POST',\n headers: { 'content-type': 'application/json', authorization: `Bearer ${token}` },\n body: JSON.stringify({ text, targetLang: opts.translateLang }),\n })\n if (!res.ok) return null\n const { translated } = await res.json() as { translated: string | null }\n return translated\n } catch { return null }\n },\n } : {}),\n ...(opts.onBack ? { onBack: opts.onBack } : {}),\n }, {\n ...(opts.subject ? { subject: opts.subject } : {}),\n ...(opts.quickReplies ? { quickReplies: opts.quickReplies } : {}),\n ...(opts.accent ? { accent: opts.accent } : {}),\n ...(opts.accent2 ? { accent2: opts.accent2 } : {}),\n ...(opts.theme ? { theme: opts.theme } : {}),\n ...(opts.webfont === false ? { webfont: false } : {}),\n ...(opts.user?.name || opts.user?.avatar ? { userInfo: { ...(opts.user.name ? { name: opts.user.name } : {}), ...(opts.user.avatar ? { avatar: opts.user.avatar } : {}) } } : {}),\n i18n,\n\n })\n\n // Returning visitor who already completed pre-chat → straight to composer.\n try { if (localStorage.getItem(preChatKey)) renderer.completePreChat() } catch { /* private mode */ }\n\n // Identified-user display info rides on the open frame itself: the server\n // persists it onto the conversation (sanitized) so agents see who they're\n // talking to. The previous approach — sending a `note` frame after 'opened' —\n // never worked: `note` is agent-only, so the server answered FORBIDDEN and\n // the info was silently dropped. Carrying it on `open` also means it reaches\n // the dashboard for EXISTING conversations (e.g. a visitor who logs in after\n // chatting anonymously), not just brand-new empty ones.\n const userInfo = opts.user && (opts.user.name || opts.user.email || opts.user.avatar || opts.user.meta)\n ? {\n ...(opts.user.name ? { name: opts.user.name } : {}),\n ...(opts.user.email ? { email: opts.user.email } : {}),\n ...(opts.user.avatar ? { avatar: opts.user.avatar } : {}),\n ...(opts.user.meta ? { meta: opts.user.meta } : {}),\n }\n : undefined\n\n const openFrame: Extract<ClientFrame, { type: 'open' }> = {\n type: 'open', profileId: opts.profileId as never,\n // Direct conversations use the kind/peerId pair; the dm:… subject key is\n // server-derived and owner-keyed, so passing it as subjectId from the\n // NON-owner side would find-or-create a junk duplicate thread.\n ...(opts.kind === 'direct' && opts.peerId\n ? { kind: 'direct' as const, peerId: opts.peerId as never }\n : opts.subjectId ? { subjectId: opts.subjectId as never } : {}),\n ...(linkFrom ? { linkFrom: linkFrom as never } : {}),\n ...(userInfo ? { userInfo } : {}),\n ...(typeof location !== 'undefined' ? { pageUrl: location.href } : {}),\n ...(typeof document !== 'undefined' && document.title ? { pageTitle: document.title } : {}),\n // Pass subject display info so the server can persist it to the Subject record.\n // This is how listingTitle and listingMeta get saved without a separate API call.\n ...(opts.subject?.title ? { subjectTitle: opts.subject.title } : {}),\n ...(opts.subject?.subtitle ? { subjectMeta: opts.subject.subtitle } : {}),\n }\n\n conn = new ConnectionManager({\n ...(opts.refreshToken ? { refreshToken: opts.refreshToken } : {}),\n url: wsUrl, token, open: openFrame,\n getCursor: () => store.highestSeq(),\n onStatusChange: (s, msg) => renderer.setConnStatus(s, msg),\n onFrame(frame) {\n if (frame.type === 'opened') {\n cid = frame.conversation.id\n\n // Flush persistent outbox exactly once (idempotent: items are ack-removed).\n if (!outboxRestored) {\n outboxRestored = true\n for (const item of outbox.load()) {\n conn.send({ type: 'send', conversationId: cid, clientMsgId: item.clientMsgId, content: item.content })\n }\n }\n\n // Restore history on EVERY successful open (covers reconnects too).\n // On reconnect the store still has messages in memory so this is a\n // no-op if there's nothing newer — cheap REST call, correct behaviour.\n void restoreHistory(wsUrl, token, cid, store, renderer, httpBase)\n\n // Flush any messages typed while the connection was still opening.\n if (preSendQueue.length) flushPreSendQueue(cid)\n }\n\n if (frame.type === 'ack') outbox.remove(frame.clientMsgId)\n\n // X3DH: handle incoming prekey bundle response\n if (__E2E__ && frame.type === 'prekeyBundle') {\n if (frame.bundle) {\n x3dhBundleFetched = true\n void e2e!.x3dhSendTo(frame.bundle).then((x3dhInit) => {\n // Drain any X3DH-pending messages with the derived key.\n const toSend = [...pending.splice(0), ...x3dhPending.splice(0)]\n for (const p of toSend) sendSealedX3DH(p.clientMsgId, p.text, x3dhInit)\n renderer.render(store)\n })\n }\n // If no bundle, peer has no prekeys; fall back to live ECDH queue\n return\n }\n\n // X3DH recipient: detect init message in incoming encrypted messages\n if (__E2E__ && frame.type === 'message' && store.e2e) {\n const x3dh = extractX3DHInit(frame.message.content)\n if (x3dh && !e2e!.ready) {\n void e2e!.x3dhReceiveFrom(x3dh.x3dhIK, x3dh.x3dhEK, x3dh.x3dhSPK, x3dh.x3dhOTP).then(async () => {\n // Now decrypt the message that carried the init\n await e2e!.openFrame(frame)\n store.apply(frame)\n renderer.render(store)\n })\n return\n }\n }\n\n if (__E2E__ && frame.type === 'peerkey') {\n void e2e!.onPeerKey(frame.key).then(() => { flushPending(); renderer.render(store) })\n return\n }\n void (async () => {\n if (__E2E__ && store.e2e) await e2e!.openFrame(frame)\n store.apply(frame)\n // The manifest carries the launcher teaser (defaults.launcherMessage);\n // repaint so a manifest-configured message appears over the closed launcher.\n if (frame.type === 'manifest') _paintTeaser?.()\n // Trigger badge + sound for new messages from others.\n // In chatList mode, skip the badge if the user is already in the chat\n // screen for this conversation — they can see the message immediately.\n if (frame.type === 'message' && frame.message.senderId !== (token as never) && !frame.message.internal) {\n addUnread()\n playSound()\n }\n // Once we learn the room is E2E, run the key handshake exactly once.\n if (__E2E__ && store.e2e && cid && !e2eStarted) {\n e2eStarted = true\n // Upload our prekey bundle for async E2E support.\n const prekeyPayload = await e2e!.initX3DH()\n conn.send({ type: 'uploadPrekeys', ...prekeyPayload })\n // Also do live ECDH handshake in case peer is already online.\n const liveKey = await e2e!.begin()\n conn.send({ type: 'pubkey', conversationId: cid, key: liveKey })\n }\n renderer.render(store)\n // Keep seenSeq in sync so the chat list shows accurate unread counts\n })()\n },\n })\n\n\n conn.connect()\n // Show restored 'pending' bubbles (if any) immediately, before the socket opens.\n renderer.render(store)\n\n const slot = opts.launcher ? launcherSlot(opts) : null\n const handle: WidgetHandle = { close: () => {\n destroyed = true\n clearTimeout(deflectTimer)\n conn.close(); launcherEl?.remove(); renderer.destroy()\n if (_mql && _mqlHandler) _mql.removeEventListener('change', _mqlHandler)\n if (_escHandler) { document.removeEventListener('keydown', _escHandler); _escHandler = null }\n _registry.delete(opts.el)\n if (slot && _launcherRegistry.get(slot) === handle) _launcherRegistry.delete(slot)\n } }\n _registry.set(opts.el, handle)\n if (slot) _launcherRegistry.set(slot, handle)\n return handle\n}\n\nexport { ChatStore } from './store.js'\nexport { ConnectionManager } from './connection.js'\nexport { Renderer } from './renderer.js'\nexport { asConversationId }\nexport { E2ESession, extractX3DHInit, type X3DHBundle } from './e2e.js'\nexport { PersistentOutbox, type OutboxItem } from './outbox.js'\nexport { restoreHistory, httpBaseFromWsUrl, resolveRelayUrls } from './history.js'\n\n","// Relay embed API — the paste-anywhere install path.\n//\n// A junior drops two lines into ANY page (any framework, any backend) and gets a\n// working chat launcher. Identity is optional and upgrades in one string. This\n// mirrors how Intercom / Channel.io install: a global command function with a\n// pre-load queue, plus auto-boot from a settings object.\n//\n// <script>window.relaySettings = { profileId: \"p_your_chatroom\" }</script>\n// <script async src=\"https://relay.paramms.com/embed.js\"></script>\n//\n// or, programmatically (SPAs, identity that arrives after login):\n//\n// Relay('boot', { profileId: \"p_x\" })\n// Relay('identify', { userId: user.id }) // becomes them + merges their guest history\n// Relay('update', { listingId: car.id }) // switch subject on navigation\n// Relay('shutdown') // remove the widget (e.g. on logout)\n\nimport { mount, type WidgetHandle, type MountOptions, type UserInfo } from './index.js'\n\n/** Everything an embedder can pass. All optional except `profileId`. Field\n * names DELIBERATELY mirror the React props (`ChatWidgetProps` /\n * `MarketplaceChatProps` in react.tsx) so the same mental model — and often\n * the same field names — carries over whether you're using React or a plain\n * script tag. Where a name changed over time the old one still works (see\n * the `@deprecated` notes) — this is a published package embedded on live\n * customer sites (WordPress plugin, Shopify theme block), so nothing here is\n * ever removed, only added to. */\nexport interface RelaySettings {\n /** The chatroom id (from your Relay dashboard). Required. Matches the React\n * `profileId` prop name. `appId` is the original alias — still works. */\n profileId?: string\n /** @deprecated alias for `profileId` — kept working, `profileId` is now the\n * documented name (matches React). */\n appId?: string\n /** Relay server URL. Defaults to the hosted relay; set for self-hosted. */\n url?: string\n apiUrl?: string\n /** IDENTITY (optional, tiered): `token` (a signed JWT from your backend) is the\n * secure path; `userId` (any stable string you have) is the easy path; omit\n * both for an anonymous visitor. See EMBED.md. */\n token?: string\n userId?: string\n /** Called when a signed `token` is rejected (expired): return a fresh token\n * from your backend to renew the session without a reload. Matches the\n * React `refreshToken` prop. Only usable from `window.relaySettings` /\n * `Relay('boot', ...)` (a function can't be expressed as an HTML\n * attribute) — not available via `data-relay-*`. */\n refreshToken?: () => Promise<string | null>\n /** Display info shown to agents (not identity) — matches the React\n * `userName` / `userEmail` / `userAvatar` props. */\n userName?: string\n userEmail?: string\n userAvatar?: string\n /** @deprecated flat aliases for `userName` / `userEmail` / `userAvatar` —\n * kept working (the shipped Shopify integration used these names nested\n * under `user`, see `user` below, which is the fix for that; these bare\n * top-level fields predate that and still work standalone). */\n name?: string\n email?: string\n avatar?: string\n /** Same info as `userName`/`userEmail`/`userAvatar`, as one nested object —\n * matches `MountOptions.user` / React's internal shape exactly, and is\n * what a server-rendered snippet (e.g. Shopify Liquid, WordPress PHP) will\n * most naturally emit: `user: { name: \"...\", email: \"...\" }`. Takes\n * precedence over the flat fields if both are somehow given. */\n user?: UserInfo\n /** Subject the chat is about (e.g. a marketplace listing). `listingId` is\n * sugar for `subjectId: \"listing_<id>\"`. */\n subjectId?: string\n listingId?: string\n /** Context-card fields — matches React's `ChatWidget` `contextTitle` /\n * `contextSubtitle` / `contextStatus` props (a general \"here's what this\n * conversation is about\" card: an order, ticket, booking, etc). */\n contextTitle?: string\n contextSubtitle?: string\n contextStatus?: string\n /** Marketplace-card fields — matches React's `MarketplaceChat`\n * `listingTitle` / `listingMeta` / `listingPrice` / `listingStatus` props\n * (a specific-item card: price + status badge, e.g. \"2019 Camry — $12,500\n * — Available\"). Use these OR `contextTitle`/etc — both build the same\n * card, pick whichever vocabulary matches your use case. */\n listingTitle?: string\n listingMeta?: string\n listingPrice?: number\n listingStatus?: string\n /** @deprecated original flat names for the context/marketplace card —\n * kept working. `contextTitle`/`listingTitle` are now the documented\n * names (matching the two React components). */\n subjectTitle?: string\n subjectMeta?: string\n subjectPrice?: number\n subjectStatus?: string\n /** The context/marketplace card as one nested object, if you'd rather build\n * it yourself than use the flat fields above — matches\n * `MountOptions.subject` exactly. Takes precedence over every flat field\n * above if given. */\n subject?: { title?: string; subtitle?: string; tags?: string[]; status?: string; ownerLabel?: string }\n /** Pre-set reply chips shown above the input — matches the React\n * `quickReplies` prop. `window.relaySettings` / `Relay('boot', ...)` only\n * (an array can't be expressed as a single `data-relay-*` attribute). */\n quickReplies?: string[]\n /** i18n string overrides — matches the React `i18n` prop. Same restriction\n * as `quickReplies`: object, so JS-object form only. */\n i18n?: MountOptions['i18n']\n /** Per-tenant feature switches (default all ON). Object form only. Matches\n * the React `features` prop. Set a flag false to disable that feature. */\n features?: MountOptions['features']\n /** Appearance. `launcher` defaults to true (a floating bubble). */\n accent?: string\n /** Secondary accent (guest bubble + send button). Object/attr form; follows\n * `accent` when omitted. */\n accent2?: string\n /** Colour scheme: 'auto'|'light'|'dark' (default 'light'; 'auto' follows OS). Attr: data-relay-theme. */\n theme?: 'auto' | 'light' | 'dark'\n /** Load brand webfonts (default true). Attr: data-relay-webfont=\"false\". */\n webfont?: boolean\n launcher?: boolean\n position?: 'bottom-right' | 'bottom-left'\n /** Launcher teaser (\"optional message\" above the bubble). Matches the React\n * `launcherMessage` prop exactly: a bare string (title only), or\n * `{ title, subtitle }`. `launcherSubtitle` below is a SEPARATE flat\n * field kept only so `data-relay-launcher-message` /\n * `data-relay-launcher-subtitle` (two HTML attributes — an attribute\n * can't hold a nested object) can still combine into the same shape; in\n * JS-object form just pass the object directly, same as React. Omit to\n * use the chatroom's manifest value. */\n launcherMessage?: string | { title: string; subtitle?: string }\n /** @deprecated HTML-attribute-only companion to a string `launcherMessage`\n * — see the note above. Prefer `launcherMessage: { title, subtitle }` in\n * JS-object form. */\n launcherSubtitle?: string\n translateLang?: string\n /** Mount INLINE into an existing element instead of the auto-created,\n * body-appended host that the default floating launcher uses. A CSS\n * selector string (works from `data-relay-target` too) or an element\n * reference (JS-object form only). Ignored when `launcher` is true — same\n * restriction as `height`/`inbox` below: a floating launcher panel is a\n * fixed-size popup `mount()` owns, not something you place in the page. */\n el?: string | HTMLElement\n /** Inline container height — matches the React `height` prop. Only applies\n * when `launcher` is false/omitted. */\n height?: string\n /** Adds a back-chevron to the widget that swaps it for the full\n * conversation list — matches the React `ChatWidget`/`MarketplaceChat`\n * `inbox` prop, INCLUDING its one limitation: not supported in launcher\n * mode. (React itself requires a different component, `ChatAppLauncher`,\n * for a launcher+inbox combination — same scope boundary here.) Tapping a\n * row opens that conversation; its own back-chevron returns to the list; a\n * ✕ in the list view returns to this widget's original single-thread\n * view. Requires `launcher: false`. */\n inbox?: boolean\n /** Open DIRECTLY on the conversation list instead of a single thread —\n * what you want for a dedicated \"Messages\" page. `inbox: true` alone only\n * adds a back-chevron to a single thread, so the list is reachable but\n * never the landing view; that is the right default for a widget bolted\n * onto a product page, and the wrong one for a page whose whole job is the\n * inbox. Implies `inbox`. Requires `launcher: false` (same restriction as\n * `inbox`), and `profileId` OR `tenantId`.\n *\n * With `inboxStart`, tapping a row opens that conversation and its own\n * back-chevron returns to the list. There is no ✕ — the list IS the root\n * view here, so there is nothing behind it to close back to. */\n inboxStart?: boolean\n /** Inbox scope when `inbox` is set: `'tenant'` (default) lists the user's\n * threads across ALL your chatrooms; `'profile'` limits it to this one. */\n inboxScope?: 'tenant' | 'profile'\n /** Your business id — lists the visitor's threads across ALL your chatrooms\n * without naming one, and lets \"new conversation\" open against your default\n * chatroom (the server reports it). This is the vanilla equivalent of\n * React's `<ChatApp tenantId=… />`, which has always accepted a tenant with\n * no profile; the script tag previously could not express that at all and\n * hard-required a `profileId`.\n *\n * Only meaningful with `inboxStart` — a single-thread widget still needs a\n * `profileId`, because a lone thread has to belong to a specific chatroom. */\n tenantId?: string\n}\n\nconst DEFAULT_URL = 'wss://api.paramms.com/ws'\n\nfunction toMountOptions(s: RelaySettings, el: HTMLElement): MountOptions {\n const profileId = s.profileId ?? s.appId\n if (!profileId) throw new Error(\"Relay: `profileId` is required (your chatroom id, e.g. 'p_...').\")\n const subjectId = s.subjectId ?? (s.listingId ? `listing_${s.listingId}` : undefined)\n const launcher = s.launcher ?? true\n\n // Subject/context card: an explicit nested `subject` wins (it's the most\n // direct match for MountOptions.subject — e.g. what a Liquid/PHP template\n // naturally emits); otherwise build it from whichever flat vocabulary was\n // used — contextTitle (ChatWidget-style), listingTitle (MarketplaceChat-\n // style), or the original subjectTitle — checked in that order.\n const title = s.contextTitle ?? s.listingTitle ?? s.subjectTitle\n const subtitle = s.contextSubtitle ?? s.listingMeta ?? s.subjectMeta\n const status = s.contextStatus ?? s.listingStatus ?? s.subjectStatus\n const price = s.listingPrice ?? s.subjectPrice\n const builtSubject = title ? {\n title,\n ...(subtitle ? { subtitle } : {}),\n ...(price != null ? { tags: [`$${price.toLocaleString()}`] } : {}),\n ...(status ? { status } : {}),\n } : undefined\n const subject = s.subject ?? builtSubject\n\n // Display info: an explicit nested `user` wins (matches MountOptions.user\n // directly — what Shopify/WordPress-style server templates naturally emit);\n // otherwise build it from userName/userEmail/userAvatar, falling back to\n // the original flat name/email/avatar.\n const uName = s.userName ?? s.name\n const uEmail = s.userEmail ?? s.email\n const uAvatar = s.userAvatar ?? s.avatar\n const builtUser = (uName || uEmail || uAvatar) ? {\n ...(uName ? { name: uName } : {}),\n ...(uEmail ? { email: uEmail } : {}),\n ...(uAvatar ? { avatar: uAvatar } : {}),\n } : undefined\n const user = s.user ?? builtUser\n\n // Launcher teaser: an object form (JS-object install) passes straight\n // through, matching the React `launcherMessage` prop exactly. A bare string\n // combines with the separate `launcherSubtitle` field ONLY needed for\n // `data-relay-*` attributes (an HTML attribute can't hold a nested object).\n const launcherMessage = s.launcherMessage && typeof s.launcherMessage === 'object'\n ? s.launcherMessage\n : s.launcherMessage\n ? (s.launcherSubtitle ? { title: s.launcherMessage, subtitle: s.launcherSubtitle } : s.launcherMessage)\n : undefined\n\n return {\n el,\n url: s.url ?? DEFAULT_URL,\n profileId,\n ...(s.apiUrl ? { apiUrl: s.apiUrl } : {}),\n ...(subjectId ? { subjectId } : {}),\n ...(s.token ? { token: s.token } : {}),\n ...(s.refreshToken ? { refreshToken: s.refreshToken } : {}),\n ...(s.userId ? { userId: s.userId } : {}),\n ...(subject ? { subject } : {}),\n ...(user ? { user } : {}),\n ...(s.quickReplies ? { quickReplies: s.quickReplies } : {}),\n ...(s.i18n ? { i18n: s.i18n } : {}),\n ...(s.features ? { features: s.features } : {}),\n ...(s.accent ? { accent: s.accent } : {}),\n ...(s.accent2 ? { accent2: s.accent2 } : {}),\n ...(s.theme ? { theme: s.theme } : {}),\n ...(s.webfont === false ? { webfont: false } : {}),\n ...(s.translateLang ? { translateLang: s.translateLang } : {}),\n ...(launcherMessage ? { launcherMessage } : {}),\n // Inbox (inline only — matches React exactly, including its one limit:\n // launcher mode has no `inbox`, that's a separate component there too).\n ...(inboxEnabled(s) && !launcher ? { onBack: () => { showInboxList = true; listIsRoot = false; remount(current) } } : {}),\n launcher,\n position: s.position ?? 'bottom-right',\n }\n}\n\nlet handle: WidgetHandle | null = null\nlet hostEl: HTMLElement | null = null\n/** True when `hostEl` is an element the HOST PAGE owns (via `el`/`data-relay-target`)\n * rather than one we created — we never remove or take full ownership of it,\n * only mount into and clear it. */\nlet externalHost = false\nlet current: RelaySettings = {}\n/** Mirrors React's `showInbox` state: true while the inline widget is showing\n * the full conversation list (reached via the single thread's back-chevron)\n * instead of its own single thread. Reset to false on a fresh `boot`;\n * preserved across `update` (so identify/navigation while browsing the inbox\n * doesn't silently kick the visitor out of it — matches how ChatApp reacts\n * to prop changes without unmounting in React). */\nlet showInboxList = false\n/** True when the list is the ROOT view (`inboxStart`) rather than somewhere we\n * navigated to from a single thread. Drives whether the ✕ (\"back to the\n * original thread\") is offered at all — with no thread behind it, a ✕ would\n * close to nothing. */\nlet listIsRoot = false\n\n/** Inline inbox is enabled by either flag; `inboxStart` implies `inbox`. */\nfunction inboxEnabled(s: RelaySettings): boolean { return !!(s.inbox || s.inboxStart) }\n/** Cleanup for whatever `mountInboxStack` currently has mounted, so switching\n * back to the single-thread view (or shutting down) leaves the host clean. */\nlet inboxTeardown: (() => void) | null = null\n\nfunction ensureHost(s: RelaySettings, launcher: boolean): HTMLElement {\n const wantsExternal = !launcher && !!s.el\n // No longer targeting a page-owned element (launcher mode now, or `el`\n // cleared/unset since the last mount) — release it. We never remove it (we\n // don't own it), just stop treating it as ours so the auto-create path\n // below takes over. Safe to blank its contents here: by the time\n // ensureHost() runs, remount() has already closed whatever was live\n // (handle / inbox stack), so nothing is orphaned mid-connection.\n if (externalHost && !wantsExternal) {\n hostEl!.innerHTML = ''\n hostEl = null\n externalHost = false\n }\n // A target only applies inline — a floating launcher panel is a fixed popup\n // mount() owns, not something placed at a point in the page.\n if (wantsExternal) {\n const resolved = typeof s.el === 'string' ? document.querySelector(s.el) : s.el\n if (resolved instanceof HTMLElement) {\n if (hostEl && hostEl !== resolved && !externalHost) hostEl.remove() // drop any previously auto-created host\n hostEl = resolved\n externalHost = true\n } else {\n console.error(`[Relay] \\`el\\` (\"${String(s.el)}\") did not match any element — falling back to an auto-created host.`)\n }\n }\n if (!hostEl || (!externalHost && !hostEl.isConnected)) {\n hostEl = document.createElement('div')\n hostEl.id = 'relay-widget-root'\n document.body.appendChild(hostEl)\n externalHost = false\n }\n if (!launcher && s.height) {\n hostEl.style.height = s.height\n if (!hostEl.style.width) hostEl.style.width = '100%'\n }\n return hostEl\n}\n\nfunction remount(s: RelaySettings): void {\n try {\n const launcher = s.launcher ?? true\n // Always tear down whatever's currently mounted FIRST, before host\n // resolution — otherwise a host-target/launcher-mode switch can leave a\n // live socket (single-thread OR inbox list/thread) attached to DOM that\n // ensureHost() is about to blank or abandon underneath it.\n inboxTeardown?.(); inboxTeardown = null\n handle?.close(); handle = null\n\n const host = ensureHost(s, launcher)\n if (inboxEnabled(s) && !launcher && showInboxList) {\n void mountInboxStack(s, host)\n return\n }\n handle = mount(toMountOptions(s, host))\n } catch (e) {\n // Never throw into the host page — a misconfigured embed logs and no-ops.\n console.error('[Relay]', e instanceof Error ? e.message : e)\n }\n}\n\n/** The inbox stack (inline, `inbox: true`, back-chevron reached): a list pane\n * and a thread pane sharing one host, plus a ✕ that returns to the widget's\n * ORIGINAL single-thread view. This is deliberately the vanilla equivalent\n * of React's `<ChatApp>` used internally by `ChatWidget`'s `inbox` prop — two\n * ALREADY-BUILT, already-shared engines (`mount()` for a thread,\n * `mountChatList()` for the list, both used by the dashboard too) wired\n * together, not a new chat engine. `mountChatList` is imported dynamically\n * for code clarity (keeps this module's structure matching its own\n * `chatlist.ts` boundary) — NOTE this is NOT a bundle-size optimization here:\n * `vite.embed.config.ts` builds `embed.js` as a single IIFE with no chunk\n * splitting, so it gets inlined regardless of whether `inbox` is ever used\n * (confirmed: embed.js grew ~100KB→114KB, ~4KB gzipped, after this change).\n * A real lazy-load would need a different bundle format for embed.js — out\n * of scope here, flagged in the roadmap as a minor follow-up. */\nasync function mountInboxStack(s: RelaySettings, host: HTMLElement): Promise<void> {\n const profileId = s.profileId ?? s.appId\n // A tenant-level inbox needs no chatroom: the list spans all of them and the\n // server reports which one \"new conversation\" should open against. Matches\n // React's <ChatApp tenantId=… /> exactly.\n if (!profileId && !s.tenantId) {\n console.error('[Relay] `inbox` requires `profileId` or `tenantId`.')\n return\n }\n\n host.innerHTML = ''\n const wrap = document.createElement('div')\n wrap.style.cssText = 'position:relative;width:100%;height:100%;overflow:hidden;background:#fff'\n const listPane = document.createElement('div')\n listPane.style.cssText = 'position:absolute;inset:0'\n const threadPane = document.createElement('div')\n threadPane.style.cssText = 'position:absolute;inset:0;display:none'\n const closeBtn = document.createElement('button')\n closeBtn.type = 'button'\n closeBtn.setAttribute('aria-label', 'Close')\n closeBtn.textContent = '✕'\n closeBtn.style.cssText = 'position:absolute;top:8px;right:8px;z-index:20;width:32px;height:32px;border-radius:50%;'\n + 'display:flex;align-items:center;justify-content:center;background:rgba(0,0,0,.05);border:none;'\n + 'color:#1c1b1a;font-size:16px;line-height:1;cursor:pointer'\n // ✕ = leave the inbox stack entirely, back to the ORIGINAL single-thread\n // view (mirrors ChatApp's onClose, wired by ChatWidget to setShowInbox(false)).\n closeBtn.onclick = () => { showInboxList = false; remount(current) }\n wrap.append(listPane, threadPane)\n // ...but only when there IS a thread behind the list to go back to. With\n // `inboxStart` the list is the root view, so a ✕ would close to nothing —\n // and with a tenant-only config there is no single thread to construct at\n // all (`toMountOptions` would throw on the missing profileId).\n const canCloseToThread = !listIsRoot && !!profileId\n if (canCloseToThread) wrap.append(closeBtn)\n host.appendChild(wrap)\n\n let listHandle: import('./chatlist.js').ChatListHandle | null = null\n let threadHandle: WidgetHandle | null = null\n // Set BEFORE the await below: if shutdown() (or a superseding remount())\n // runs while the dynamic import is still in flight, there must already be\n // a way to clean up the synchronously-created `wrap` — otherwise, for an\n // EXTERNAL host (never `.remove()`d), it would sit there orphaned forever.\n // The closure reads `threadHandle`/`listHandle` at CALL time, so it's still\n // correct once they're actually assigned below.\n inboxTeardown = () => { threadHandle?.close(); listHandle?.close(); host.innerHTML = '' }\n\n // A failed dynamic import used to reject into nothing: the promise had no\n // catch, so the host page got a silent blank box and only an unhandled\n // rejection in the console. Say what happened, in the box the visitor is\n // looking at.\n let mountChatList: typeof import('./chatlist.js').mountChatList\n try {\n ({ mountChatList } = await import('./chatlist.js'))\n } catch (e) {\n console.error('[Relay] could not load the conversation list module.', e)\n if (listPane.isConnected) {\n listPane.style.cssText += ';display:flex;align-items:center;justify-content:center;'\n + 'padding:16px;font:13px system-ui;color:#b91c1c;text-align:center'\n listPane.textContent = 'Could not load conversations.'\n }\n return\n }\n type Entry = import('./chatlist.js').ChatListEntry\n // The dynamic import is async: if the stack was torn down (shutdown, or a\n // subsequent remount already cleared `host`) before it resolved, bail —\n // same guard React's own async effect uses (a `cancelled` flag there).\n if (!listPane.isConnected) return\n\n const openThread = (entry: Entry): void => {\n // Rows always carry their own chatroom and compose always sets one, so a\n // missing chatroom here means a malformed row rather than a normal state —\n // and with a tenant-only config there is no fallback to reach for. Refuse\n // loudly instead of mounting a thread against nothing.\n const roomId = entry.profileId ?? profileId\n if (!roomId) { console.error('[Relay] conversation row has no chatroom; cannot open it.', entry); return }\n closeBtn.style.display = 'none' // hidden while a thread is shown — matches React (`onClose && !selected`)\n threadHandle?.close()\n threadHandle = mount({\n el: threadPane,\n url: s.url ?? DEFAULT_URL,\n ...(s.apiUrl ? { apiUrl: s.apiUrl } : {}),\n profileId: roomId,\n // DM rows only open correctly via kind+peerId (their subjectId only\n // resolves for the participant that owns the thread key) — same\n // handling ChatApp itself uses.\n ...(entry.kind === 'direct' && entry.peerId\n ? { kind: 'direct' as const, peerId: entry.peerId }\n : entry.subjectId ? { subjectId: entry.subjectId } : {}),\n ...(s.token ? { token: s.token } : {}),\n ...(s.refreshToken ? { refreshToken: s.refreshToken } : {}),\n ...(s.userId ? { userId: s.userId } : {}),\n ...(s.userId || s.userName || s.userEmail || s.userAvatar ? {\n user: {\n ...(s.userName ? { name: s.userName } : {}),\n ...(s.userEmail ? { email: s.userEmail } : {}),\n ...(s.userAvatar ? { avatar: s.userAvatar } : {}),\n },\n } : {}),\n ...(entry.subjectTitle ? {\n subject: { title: entry.subjectTitle, ...(entry.subjectMeta ? { subtitle: entry.subjectMeta } : {}) },\n } : {}),\n ...(s.accent ? { accent: s.accent } : {}),\n launcher: false,\n // Row's own back-chevron: return to the LIST (not the original single\n // thread — that needs the ✕ above), matching ChatApp's setSelected(null).\n onBack: () => {\n threadHandle?.close(); threadHandle = null\n threadPane.style.display = 'none'\n listPane.style.display = ''\n closeBtn.style.display = '' // visible again now that the list is showing\n listHandle?.refresh() // reflects what just happened (read state, preview)\n },\n })\n listPane.style.display = 'none'\n threadPane.style.display = ''\n }\n\n listHandle = mountChatList({\n el: listPane,\n url: s.url ?? DEFAULT_URL,\n ...(s.apiUrl ? { apiUrl: s.apiUrl } : {}),\n ...(profileId ? { profileId } : {}),\n ...(s.tenantId ? { tenantId: s.tenantId } : {}),\n scope: s.inboxScope ?? 'tenant',\n // Only when the ✕ is actually drawn (see canCloseToThread) — otherwise the\n // reserved gap would be empty space for no reason.\n ...(canCloseToThread ? { reserveCloseSpace: true } : {}),\n onSelect: openThread,\n // ✎ compose: open a fresh thread against this widget's own chatroom when\n // one is configured; with a tenant-only config, against the server-reported\n // default (the tenant's oldest chatroom), exactly like <ChatApp/>. That\n // default only exists after the first successful fetch, so bail quietly\n // until then rather than opening a thread with no chatroom.\n onNewChat: () => {\n const target = profileId ?? listHandle?.defaultProfileId()\n if (!target) return\n openThread({ id: '__new__', profileId: target, state: 'open', updatedAt: Date.now() })\n },\n ...(s.token ? { token: s.token } : {}),\n ...(s.userId ? { userId: s.userId } : {}),\n ...(s.accent ? { accent: s.accent } : {}),\n })\n}\n\n/** Mount (or re-mount) with a fresh set of settings. */\nfunction boot(s: RelaySettings): void {\n // `inboxStart` lands ON the list. `inbox` alone still lands on the single\n // thread (the list is behind its back-chevron) — unchanged, because that is\n // what every currently-deployed embed expects.\n listIsRoot = !!(s.inboxStart && !(s.launcher ?? true))\n showInboxList = listIsRoot\n current = { ...s }\n remount(current)\n}\n\n/** Merge new settings over the current ones and re-mount. Used for identify\n * (add a userId after login) and navigation (switch listingId). Preserves\n * `showInboxList` — identify/navigation shouldn't silently kick a visitor\n * out of the inbox they're currently browsing. */\nfunction update(s: RelaySettings): void {\n current = { ...current, ...s }\n remount(current)\n}\n\n/** Tear the widget down completely (e.g. on logout). */\nfunction shutdown(): void {\n inboxTeardown?.(); inboxTeardown = null\n handle?.close(); handle = null\n if (hostEl && !externalHost) hostEl.remove()\n hostEl = null; externalHost = false\n showInboxList = false\n listIsRoot = false\n current = {}\n}\n\nexport type RelayCommand = 'boot' | 'update' | 'identify' | 'shutdown'\n\n/** The public command dispatcher exposed as `window.Relay`. */\nexport function Relay(command: RelayCommand | string, arg?: unknown): void {\n switch (command) {\n case 'boot': boot((arg ?? {}) as RelaySettings); break\n case 'update':\n case 'identify': update((arg ?? {}) as RelaySettings); break // identify == update with a userId\n case 'shutdown': shutdown(); break\n default: console.warn('[Relay] unknown command:', command)\n }\n}\n\n/** Read settings from a `<script data-relay-app=\"p_x\">` (or\n * `data-relay-profile-id=\"p_x\"`, same thing) tag — the zero-JavaScript\n * install: every field here is a plain string/number, so it's exactly what a\n * server template (WordPress/Shopify/Liquid/PHP/ERB) can drop straight into\n * an attribute without writing any script. Fields that need a nested object,\n * an array, or a function (`user`, `subject`, `quickReplies`, `i18n`,\n * `refreshToken`) have NO attribute form — those need the JS-object install\n * (`window.relaySettings` / `Relay('boot', ...)`) instead. */\nfunction readDataAttrs(): RelaySettings | null {\n if (typeof document === 'undefined') return null\n const s = (document.querySelector('script[data-relay-app]')\n ?? document.querySelector('script[data-relay-profile-id]')\n // An inbox page names a business, not a chatroom — that tag has neither of\n // the two attributes above, so it needs its own lookup or it is invisible\n // to the zero-JS install path.\n ?? document.querySelector('script[data-relay-tenant-id]')) as HTMLElement | null\n const d = s?.dataset\n const app = d?.['relayApp'] ?? d?.['relayProfileId']\n const tenant = d?.['relayTenantId']\n // A tenant-only tag is valid for an inbox page (no chatroom to name).\n if (!app && !tenant) return null\n const out: RelaySettings = app ? { profileId: app } : {}\n if (tenant) out.tenantId = tenant\n if (d!['relayUser']) out.userId = d!['relayUser']\n if (d!['relayToken']) out.token = d!['relayToken']\n if (d!['relayListing']) out.listingId = d!['relayListing']\n if (d!['relayAccent']) out.accent = d!['relayAccent']\n if (d!['relayAccent2']) out.accent2 = d!['relayAccent2']\n if (d!['relayTheme']) out.theme = d!['relayTheme'] as 'auto'|'light'|'dark'\n if (d!['relayWebfont'] === 'false') out.webfont = false\n if (d!['relayUrl']) out.url = d!['relayUrl']\n const pos = d!['relayPosition']\n if (pos === 'bottom-left' || pos === 'bottom-right') out.position = pos\n if (d!['relayLauncherMessage']) out.launcherMessage = d!['relayLauncherMessage']\n if (d!['relayLauncherSubtitle']) out.launcherSubtitle = d!['relayLauncherSubtitle']\n if (d!['relayLauncher'] === 'false') out.launcher = false\n // Display info — matches userName/userEmail/userAvatar in the JS-object form.\n if (d!['relayUserName']) out.userName = d!['relayUserName']\n if (d!['relayUserEmail']) out.userEmail = d!['relayUserEmail']\n if (d!['relayUserAvatar']) out.userAvatar = d!['relayUserAvatar']\n // Context/listing card — either vocabulary, matching the JS-object form.\n if (d!['relayContextTitle']) out.contextTitle = d!['relayContextTitle']\n if (d!['relayContextSubtitle']) out.contextSubtitle = d!['relayContextSubtitle']\n if (d!['relayContextStatus']) out.contextStatus = d!['relayContextStatus']\n if (d!['relayListingTitle']) out.listingTitle = d!['relayListingTitle']\n if (d!['relayListingMeta']) out.listingMeta = d!['relayListingMeta']\n if (d!['relayListingPrice']) out.listingPrice = Number(d!['relayListingPrice'])\n if (d!['relayListingStatus']) out.listingStatus = d!['relayListingStatus']\n // Inline placement/sizing/inbox — all plain strings, so all attribute-safe.\n if (d!['relayTarget']) out.el = d!['relayTarget']\n if (d!['relayHeight']) out.height = d!['relayHeight']\n if (d!['relayInbox'] === 'true') out.inbox = true\n if (d!['relayInbox'] === 'false') out.inbox = false\n if (d!['relayInboxStart'] === 'true') out.inboxStart = true\n if (d!['relayInboxStart'] === 'false') out.inboxStart = false\n const scope = d!['relayInboxScope']\n if (scope === 'tenant' || scope === 'profile') out.inboxScope = scope\n\n // Translation: ISO code of the language to auto-translate INCOMING messages\n // into (shows a 🌐 button per message). The interface and mount path already\n // supported translateLang for React and JS config; the zero-JS script-tag\n // path could not set it at all until this line — a field-parity gap.\n if (d!['relayTranslateLang']) out.translateLang = d!['relayTranslateLang']\n return out\n}\n\n// ── Install: take over the loader stub's queue, then replay it ───────────────\n// The paste-in loader defines `window.Relay` as a queue so calls made before\n// this script finishes loading aren't lost. We swap in the real dispatcher and\n// flush anything queued, then auto-boot from `window.relaySettings` OR a\n// `data-relay-app` script attribute if the embedder never called boot() — the\n// two zero-JS install paths.\ntype Queue = { q?: IArguments[] }\ntype Win = typeof window & { Relay?: ((...a: unknown[]) => void) & Queue; relaySettings?: RelaySettings }\n\nif (typeof window !== 'undefined') {\n const w = window as Win\n const queued: IArguments[] = (w.Relay && w.Relay.q) ? w.Relay.q : []\n w.Relay = Relay as ((...a: unknown[]) => void) & Queue\n\n let explicitBoot = false\n for (const call of queued) {\n const [cmd, arg] = call as unknown as [string, unknown]\n if (cmd === 'boot') explicitBoot = true\n Relay(cmd, arg)\n }\n if (!explicitBoot) {\n const auto = w.relaySettings ?? readDataAttrs()\n if (auto) boot(auto)\n }\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","/**\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":["KEY","readCookie","name","m","writeCookie","value","secure","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","data","__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","i","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","e","MORE_DATA","sharedCachedKeyDecoder","Decoder","remainingData","newData","posToShow","stream","decoded","headByte","totalPos","isArray","isArrayHeaderRequired","arrayItemsLeft","DECODE","stack","headerOffset","_a","headOffset","extType","CLIENT_FRAME_TYPES","isClientFrame","frame","encodeFrame","mpEncode","decodeFrame","mpDecode","ChatStore","me","a","b","ap","bp","clientMsgId","content","msg","confirmed","reactions","users","u","uptoSeq","status","targetRank","rank","changed","k","s","ConnectionManager","opts","_b","sock","defaultFactory","ev","FATAL_ERRORS","_d","_c","fresh","friendlyError","conversationId","pending","f","cap","base","max","delay","code","url","MAX_ITEMS","MAX_AGE_MS","PersistentOutbox","token","raw","items","cutoff","subtle","b64encode","buf","b64decode","bin","out","generateKeyPair","kp","exportPublicKey","importPeerPublicKey","b64","deriveSharedKey","privateKey","peerPublicKeyB64","peer","encrypt","plaintext","iv","ct","decrypt","plain","loadOrCreateKeyPair","storageKey","pub","priv","publicKey","signPrekey","signingPrivateKey","spkPublicKey","spkRaw","sig","generateIdentityKeyPair","ecdhKP","ecdsaKP","loadOrCreateIdentityKeyPair","d","ecdhPub","ecdhPriv","ecdsaPub","ecdsaPriv","ikp","x3dhSend","senderIK","recipientBundle","ek","epkB64","ik_r","spk_r","opk_r","dh1","rawDH","dh2","dh3","dh4","ikm","concatBuffers","hkdfDeriveKey","x3dhReceive","recipientIK","recipientSPK","senderIKb64","ephemeralKeyB64","recipientOPK","ik_s","ek_s","bufs","total","n","ikmKey","OTP_BATCH_SIZE","E2ESession","peerKeyB64","signedPrekeyPub","signature","oneTimePrekeys","bundle","sharedKey","ephemeralPublicKey","spkId","usedOTP","otp","ephemeralKey","text","x3dhInit","extractX3DHInit","c","LIGHT","DARK","FB","vars","prefix","t","v","lightTokens","darkTokens","CSS","STYLE_ID","REACTION_EMOJIS","COMPACT_BREAKPOINT","SEND_ICON_SVG","injectStyles","FONT_ID","injectFonts","l","el","tag","cls","fmtTime","ts","contentText","Renderer","root","h","cfg","accent2","head","back","brandName","avatarEl","hm","_e","_f","_g","typingBubble","q","_h","sendBtn","sendLabel","_i","attachBtn","fileInput","inputRow","footer","_j","_k","ta","applyCompact","w","entries","fn","sh","preview","store","ownerLabel","actions","prevScrollHeight","prevScrollTop","sentinel","maxOther","prevSender","showLabel","typingNames","bubble","guestHasSpoken","copy","terminalStates","isTerminal","note","fatal","form","inputs","inp","topicSel","ph","o","callbackCb","phoneForCb","row","submit","email","callback","phone","articles","card","stars","btns","bb","idx","title","tags","btn","label","resolve","overlay","cancel","ok","close","panel","sel","opt","sys","mine","isNote","col","who","bubbleWrap","replyCtx","textNode","img","links","gLink","iLink","original","translateBtn","transLine","showLine","hideLine","cached","menu","editBtn","saveBtn","cancelBtn","btnRow","editPanel","restore","newText","ke","delBtn","reactWrap","reactRow","emoji","pill","addBtn","picker","pb","alreadyReacted","opening","meta","tick","PAGE","resolveRelayUrls","input","apiBaseOverride","trimmed","scheme","authorityAndPath","httpBase","httpBaseFromWsUrl","wsUrl","historyUrl","beforeSeq","limit","qs","fetchPage","lastError","sawResponse","res","restoreHistory","renderer","apiBase","page","loading","loadOlder","oldest","page2","scrollEl","armed","onScroll","_registry","_launcherRegistry","launcherSlot","_audioCtx","getAudioContext","mount","anonId","deflectTimer","destroyed","linkFrom","outboxKey","outbox","cid","outboxRestored","_mql","_mqlHandler","_escHandler","_paintTeaser","launcherEl","badgeEl","unread","open","isRight","mql","applyPanelLayout","mobile","mqlHandler","CHAT_SVG","CLOSE_SVG","paintBubble","teaserKey","optMsg","teaserEl","teaserDismissed","CHAT_MINI_SVG","paintTeaser","sub","ic","st","x","openFromTeaser","showPanel","show","addUnread","playSound","ctx","osc","gain","preSendQueue","flushPreSendQueue","conn","e2e","e2eStarted","x3dhPending","x3dhBundleFetched","sendSealed","sendSealedX3DH","flushPending","p","fetchAndX3DH","targetUserId","i18n","rtlLocales","browserLang","preChatKey","file","uploadUrl","mime","actionId","isTyping","first","query","r","seq","messageId","remove","score","translated","userInfo","openFrame","toSend","x3dh","prekeyPayload","liveKey","slot","handle","DEFAULT_URL","toMountOptions","profileId","subjectId","launcher","subtitle","price","builtSubject","subject","uName","uEmail","uAvatar","builtUser","user","launcherMessage","inboxEnabled","showInboxList","listIsRoot","remount","current","hostEl","externalHost","inboxTeardown","ensureHost","wantsExternal","resolved","host","mountInboxStack","wrap","listPane","threadPane","closeBtn","canCloseToThread","listHandle","threadHandle","mountChatList","chatlist","openThread","entry","roomId","target","boot","update","shutdown","Relay","command","arg","readDataAttrs","app","tenant","scope","queued","explicitBoot","call","cmd","auto","statusChip","timeAgo","days","accent","titleText","titleEl","compose","searchWrap","searchIn","body","compactObserver","serverDefaultProfileId","seenKey","seenSeq","saveSeenSeq","allEntries","fetchEntries","headers","renderRows","filtered","rowName","empty","start","isUnread","read","buildRow","initial","lastSeq","unreadCount","av","info","stateMap","right","chip","refresh","errBox","retry","reconnectTimer","refreshTimer","attempt","connectedBefore","debouncedRefresh","connectInbox","scheduleReconnect"],"mappings":"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","x_google_ignoreList":[1,2,3,4,5,6,7,8,9,10,11,12,13]}