{"_id":"@antzsoft/chat-web-sdk","_rev":"22-409f6923c04dd77f96b5ed67abff3867","name":"@antzsoft/chat-web-sdk","dist-tags":{"latest":"1.2.2"},"versions":{"1.0.0":{"name":"@antzsoft/chat-web-sdk","version":"1.0.0","author":{"name":"Antz"},"license":"MIT","_id":"@antzsoft/chat-web-sdk@1.0.0","maintainers":[{"name":"antz.karthik","email":"karthikmitta@lifesciencetrust.com"},{"name":"antzsoft_trellisys","email":"antzsoft@lifesciencetrust.com"}],"dist":{"shasum":"087bbd5fb046a7824bf2b24ac3c1920d802581a0","tarball":"https://registry.npmjs.org/@antzsoft/chat-web-sdk/-/chat-web-sdk-1.0.0.tgz","fileCount":14,"integrity":"sha512-dFxU/n7RzU3Dg0BeHGud1Eyz1azzFc+uz+esaQTO6kIZY/gDxxxP6Jp+GmXmdiHLJouXaTAhZ9WwW3dqaNvc3A==","signatures":[{"sig":"MEQCIDWN85bMWxICLXsjmKpY1v7tKC9Fydpy0hM/XoExujJGAiBfcClTXBSU4bdwtt8vjTB2pq3wCaB1vJgRNwtGV0DArw==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":4614565},"main":"./dist/index.cjs","type":"module","types":"./dist/index.d.ts","module":"./dist/index.js","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","require":"./dist/index.cjs"},"./react":{"types":"./dist/react/index.d.ts","import":"./dist/react/index.js","require":"./dist/react/index.cjs"}},"gitHead":"46e9b5a028bb6a4fa11ab4a09aff3ca41d7821df","scripts":{"lint":"eslint src --ext .ts,.tsx","build":"tsup","typecheck":"tsc --noEmit","build:watch":"tsup --watch"},"_npmUser":{"name":"antz.karthik","email":"karthikmitta@lifesciencetrust.com"},"_npmVersion":"10.9.2","description":"Pluggable web chat UI SDK — React, Next.js, Vue, any JS framework","directories":{},"_nodeVersion":"22.14.0","_hasShrinkwrap":false,"devDependencies":{"tsup":"^8.0.0","react":"^18.2.0","react-dom":"^18.2.0","typescript":"^5.3.0","@types/react":"^18.2.0","lucide-react":"^0.344.0","@types/react-dom":"^18.2.0","@antzsoft/chat-core":"^1.2.1","@tanstack/react-query":"^5.17.19"},"peerDependencies":{"react":">=18.0.0","react-dom":">=18.0.0","@antzsoft/chat-core":">=1.2.1"},"optionalDependencies":{"lucide-react":"^0.344.0","@tanstack/react-query":"^5.17.19"},"peerDependenciesMeta":{"react":{"optional":true},"react-dom":{"optional":true},"@antzsoft/chat-core":{"optional":false}},"_npmOperationalInternal":{"tmp":"tmp/chat-web-sdk_1.0.0_1779717054420_0.991574226510368","host":"s3://npm-registry-packages-npm-production"}},"1.0.1":{"name":"@antzsoft/chat-web-sdk","version":"1.0.1","author":{"name":"Antz"},"license":"MIT","_id":"@antzsoft/chat-web-sdk@1.0.1","maintainers":[{"name":"antz.karthik","email":"karthikmitta@lifesciencetrust.com"},{"name":"antzsoft_trellisys","email":"antzsoft@lifesciencetrust.com"}],"dist":{"shasum":"bd58a4902b1ccbe796796ed4ffbcd0306f47a82a","tarball":"https://registry.npmjs.org/@antzsoft/chat-web-sdk/-/chat-web-sdk-1.0.1.tgz","fileCount":14,"integrity":"sha512-HGa3r+XIHwyk8Bz0jKuOX/JDbbqLmjyNVb8YXhE3SILAuJFVDvMonMqHrSbi/RjtRrInAFiC0TNXT2burnfp0A==","signatures":[{"sig":"MEUCIGbMWX2If3toO+gldEFHkn6p1ZdpoiqcQaPBsxOMgL8IAiEA4MFrEKB2Rpqgb58ris09FLpFb5ftfu+znL5SAEtGEmc=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":5151199},"main":"./dist/index.cjs","type":"module","types":"./dist/index.d.ts","module":"./dist/index.js","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","require":"./dist/index.cjs"},"./react":{"types":"./dist/react/index.d.ts","import":"./dist/react/index.js","require":"./dist/react/index.cjs"}},"gitHead":"a34557f2e7703b5b61a4e3d826ba78d459b76e7f","scripts":{"lint":"eslint src --ext .ts,.tsx","build":"tsup","typecheck":"tsc --noEmit","build:watch":"tsup --watch"},"_npmUser":{"name":"antz.karthik","email":"karthikmitta@lifesciencetrust.com"},"_npmVersion":"10.9.2","description":"Pluggable web chat UI SDK — React, Next.js, Vue, any JS framework","directories":{},"_nodeVersion":"22.14.0","_hasShrinkwrap":false,"devDependencies":{"tsup":"^8.0.0","react":"^18.2.0","react-dom":"^18.2.0","typescript":"^5.3.0","@types/react":"^18.2.0","lucide-react":"^0.344.0","@types/react-dom":"^18.2.0","@antzsoft/chat-core":"^1.2.4","@tanstack/react-query":"^5.17.19"},"peerDependencies":{"react":">=18.0.0","react-dom":">=18.0.0","@antzsoft/chat-core":">=1.2.4"},"optionalDependencies":{"lucide-react":"^0.344.0","@tanstack/react-query":"^5.17.19"},"peerDependenciesMeta":{"react":{"optional":true},"react-dom":{"optional":true},"@antzsoft/chat-core":{"optional":false}},"_npmOperationalInternal":{"tmp":"tmp/chat-web-sdk_1.0.1_1779872293157_0.9608830909848891","host":"s3://npm-registry-packages-npm-production"}},"1.0.2":{"name":"@antzsoft/chat-web-sdk","version":"1.0.2","author":{"name":"Antz"},"license":"MIT","_id":"@antzsoft/chat-web-sdk@1.0.2","maintainers":[{"name":"antz.karthik","email":"karthikmitta@lifesciencetrust.com"},{"name":"antzsoft_trellisys","email":"antzsoft@lifesciencetrust.com"}],"dist":{"shasum":"0b960d505ed7fd381f59ff1f2bd8dda857a13ff2","tarball":"https://registry.npmjs.org/@antzsoft/chat-web-sdk/-/chat-web-sdk-1.0.2.tgz","fileCount":14,"integrity":"sha512-mzAOZlT5DVr83NJUKWxSGfuNU9wEwF3SVRISirBs7tgDLtwjebB0qXyzMyh/oYN0qSo3VtB2xVn80jHaorsVlw==","signatures":[{"sig":"MEUCIQCnGWpBuzjzeq3J6gMzUHhkqSKQLevtyly+h06gT1AdXQIgAe7A6ho2IRmODgzND+QaaHMHz7T3y4s1i4CIMQazTyc=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":5293919},"main":"./dist/index.cjs","type":"module","types":"./dist/index.d.ts","module":"./dist/index.js","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","require":"./dist/index.cjs"},"./react":{"types":"./dist/react/index.d.ts","import":"./dist/react/index.js","require":"./dist/react/index.cjs"}},"gitHead":"f08d219e802afc3a8e757fc7afbcc40c957aa70a","scripts":{"lint":"eslint src --ext .ts,.tsx","build":"tsup","typecheck":"tsc --noEmit","build:watch":"tsup --watch"},"_npmUser":{"name":"antz.karthik","email":"karthikmitta@lifesciencetrust.com"},"_npmVersion":"10.9.2","description":"Pluggable web chat UI SDK — React, Next.js, Vue, any JS framework","directories":{},"_nodeVersion":"22.14.0","dependencies":{"webm-muxer":"^5.1.4"},"_hasShrinkwrap":false,"devDependencies":{"tsup":"^8.0.0","react":"^18.2.0","react-dom":"^18.2.0","typescript":"^5.3.0","@types/react":"^18.2.0","lucide-react":"^0.344.0","@types/react-dom":"^18.2.0","@antzsoft/chat-core":"^1.2.4","@tanstack/react-query":"^5.17.19"},"peerDependencies":{"react":">=18.0.0","react-dom":">=18.0.0","@antzsoft/chat-core":">=1.2.4"},"optionalDependencies":{"lucide-react":"^0.344.0","@tanstack/react-query":"^5.17.19"},"peerDependenciesMeta":{"react":{"optional":true},"react-dom":{"optional":true},"@antzsoft/chat-core":{"optional":false}},"_npmOperationalInternal":{"tmp":"tmp/chat-web-sdk_1.0.2_1780033401593_0.4440151866208142","host":"s3://npm-registry-packages-npm-production"}},"1.0.3":{"name":"@antzsoft/chat-web-sdk","version":"1.0.3","author":{"name":"Antz"},"license":"MIT","_id":"@antzsoft/chat-web-sdk@1.0.3","maintainers":[{"name":"antz.karthik","email":"karthikmitta@lifesciencetrust.com"},{"name":"antzsoft_trellisys","email":"antzsoft@lifesciencetrust.com"}],"dist":{"shasum":"7f02870800e7580070baa5c6f64ab79d078685e5","tarball":"https://registry.npmjs.org/@antzsoft/chat-web-sdk/-/chat-web-sdk-1.0.3.tgz","fileCount":14,"integrity":"sha512-mlGOgg+8cEE0oPN0Hqlhcae/8DGHc2ScoOtcOZF5HKhVXAGC+zds29lcWrh5kIhBSzZ63JbzDts2p1+iRMI1oQ==","signatures":[{"sig":"MEYCIQC3F7LfPkfNd8QCNZP+vy8DumBTpNGVgowx0ssNvBrR5AIhAJ/LC6vNHWYm7VWj4YvMH2pocyrjPvWKG3O8IVgEMfPs","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":5293919},"main":"./dist/index.cjs","type":"module","types":"./dist/index.d.ts","module":"./dist/index.js","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","require":"./dist/index.cjs"},"./react":{"types":"./dist/react/index.d.ts","import":"./dist/react/index.js","require":"./dist/react/index.cjs"}},"gitHead":"1ae78a374fc7448a79230ff75df865883065b0de","scripts":{"lint":"eslint src --ext .ts,.tsx","build":"tsup","typecheck":"tsc --noEmit","build:watch":"tsup --watch"},"_npmUser":{"name":"antz.karthik","email":"karthikmitta@lifesciencetrust.com"},"_npmVersion":"10.9.2","description":"Pluggable web chat UI SDK — React, Next.js, Vue, any JS framework","directories":{},"_nodeVersion":"22.14.0","dependencies":{"webm-muxer":"^5.1.4"},"_hasShrinkwrap":false,"devDependencies":{"tsup":"^8.0.0","react":"^18.2.0","react-dom":"^18.2.0","typescript":"^5.3.0","@types/react":"^18.2.0","lucide-react":"^0.344.0","@types/react-dom":"^18.2.0","@antzsoft/chat-core":"^1.2.4","@tanstack/react-query":"^5.17.19"},"peerDependencies":{"react":">=18.0.0","react-dom":">=18.0.0","@antzsoft/chat-core":">=1.2.4"},"optionalDependencies":{"lucide-react":"^0.344.0","@tanstack/react-query":"^5.17.19"},"peerDependenciesMeta":{"react":{"optional":true},"react-dom":{"optional":true},"@antzsoft/chat-core":{"optional":false}},"_npmOperationalInternal":{"tmp":"tmp/chat-web-sdk_1.0.3_1780290712141_0.8671642031771196","host":"s3://npm-registry-packages-npm-production"}},"1.0.4":{"name":"@antzsoft/chat-web-sdk","version":"1.0.4","author":{"name":"Antz"},"license":"MIT","_id":"@antzsoft/chat-web-sdk@1.0.4","maintainers":[{"name":"antz.karthik","email":"karthikmitta@lifesciencetrust.com"},{"name":"antzsoft_trellisys","email":"antzsoft@lifesciencetrust.com"}],"dist":{"shasum":"4f5dc68eb15a30f2bae90a7dae03db9bde282e93","tarball":"https://registry.npmjs.org/@antzsoft/chat-web-sdk/-/chat-web-sdk-1.0.4.tgz","fileCount":14,"integrity":"sha512-+QRWXpYq5hK40P8zftwPEIJYfEgKjAemhl2Ndbl+J95/z/2d1KejXgCP0+Um9dAq+4izq5+rmDwQNFQ2hMCL5g==","signatures":[{"sig":"MEUCIQCCHgdJbQVuV4YPoQ5RoAmCvBcbMADxHRIkG+OO2SEMTwIgTa+rpm8MUt8H8B3vB9qAnstu0eZDeRZYj1qLsIVbGx8=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":5383463},"main":"./dist/index.cjs","type":"module","types":"./dist/index.d.ts","module":"./dist/index.js","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","require":"./dist/index.cjs"},"./react":{"types":"./dist/react/index.d.ts","import":"./dist/react/index.js","require":"./dist/react/index.cjs"}},"gitHead":"0cf50a8931848c5222ad728a7e5e82d3f0b6a975","scripts":{"lint":"eslint src --ext .ts,.tsx","build":"tsup","typecheck":"tsc --noEmit","build:watch":"tsup --watch"},"_npmUser":{"name":"antz.karthik","email":"karthikmitta@lifesciencetrust.com"},"_npmVersion":"10.9.2","description":"Pluggable web chat UI SDK — React, Next.js, Vue, any JS framework","directories":{},"_nodeVersion":"22.14.0","dependencies":{"webm-muxer":"^5.1.4"},"_hasShrinkwrap":false,"devDependencies":{"tsup":"^8.0.0","react":"^18.2.0","react-dom":"^18.2.0","typescript":"^5.3.0","@types/react":"^18.2.0","lucide-react":"^0.344.0","@types/react-dom":"^18.2.0","@antzsoft/chat-core":"^1.2.5","@tanstack/react-query":"^5.17.19"},"peerDependencies":{"react":">=18.0.0","react-dom":">=18.0.0","@antzsoft/chat-core":">=1.2.5"},"optionalDependencies":{"lucide-react":"^0.344.0","@tanstack/react-query":"^5.17.19"},"peerDependenciesMeta":{"react":{"optional":true},"react-dom":{"optional":true},"@antzsoft/chat-core":{"optional":false}},"_npmOperationalInternal":{"tmp":"tmp/chat-web-sdk_1.0.4_1780402674478_0.7902566756593781","host":"s3://npm-registry-packages-npm-production"}},"1.0.5":{"name":"@antzsoft/chat-web-sdk","version":"1.0.5","author":{"name":"Antz"},"license":"MIT","_id":"@antzsoft/chat-web-sdk@1.0.5","maintainers":[{"name":"antz.karthik","email":"karthikmitta@lifesciencetrust.com"},{"name":"antzsoft_trellisys","email":"antzsoft@lifesciencetrust.com"}],"dist":{"shasum":"e559ba2627b069a7b5b3b4ae7dbe6ab888aa1c5a","tarball":"https://registry.npmjs.org/@antzsoft/chat-web-sdk/-/chat-web-sdk-1.0.5.tgz","fileCount":14,"integrity":"sha512-MCIW4Hm6YHD++Il3MUWElUKIeKEIpU30Az102xpA2i34GzizhgbmS4PqB6qAEtIV8cSURNKVwUqWyycvv5EPTg==","signatures":[{"sig":"MEYCIQD6jBw17qSOe/0LeQ7y2eItdiLKnYwP85hlUHZ9/w+ZhwIhANkf6PbwJAQQxC9CUvY/EU8iETcmBEt4cQWzMk3nbGeY","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":5464869},"main":"./dist/index.cjs","type":"module","types":"./dist/index.d.ts","module":"./dist/index.js","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","require":"./dist/index.cjs"},"./react":{"types":"./dist/react/index.d.ts","import":"./dist/react/index.js","require":"./dist/react/index.cjs"}},"gitHead":"78ac489937430e4088f2a946edc05859a5eeacd8","scripts":{"lint":"eslint src --ext .ts,.tsx","build":"tsup","typecheck":"tsc --noEmit","build:watch":"tsup --watch"},"_npmUser":{"name":"antz.karthik","email":"karthikmitta@lifesciencetrust.com"},"_npmVersion":"10.9.2","description":"Pluggable web chat UI SDK — React, Next.js, Vue, any JS framework","directories":{},"_nodeVersion":"22.14.0","dependencies":{"webm-muxer":"^5.1.4"},"_hasShrinkwrap":false,"devDependencies":{"tsup":"^8.0.0","react":"^18.2.0","react-dom":"^18.2.0","typescript":"^5.3.0","@types/react":"^18.2.0","lucide-react":"^0.344.0","@types/react-dom":"^18.2.0","@antzsoft/chat-core":"^1.2.6","@tanstack/react-query":"^5.17.19"},"peerDependencies":{"react":">=18.0.0","react-dom":">=18.0.0","@antzsoft/chat-core":">=1.2.6"},"optionalDependencies":{"lucide-react":"^0.344.0","@tanstack/react-query":"^5.17.19"},"peerDependenciesMeta":{"react":{"optional":true},"react-dom":{"optional":true},"@antzsoft/chat-core":{"optional":false}},"_npmOperationalInternal":{"tmp":"tmp/chat-web-sdk_1.0.5_1780486309897_0.9654421998673262","host":"s3://npm-registry-packages-npm-production"}},"1.0.6":{"name":"@antzsoft/chat-web-sdk","version":"1.0.6","author":{"name":"Antz"},"license":"MIT","_id":"@antzsoft/chat-web-sdk@1.0.6","maintainers":[{"name":"antz.karthik","email":"karthikmitta@lifesciencetrust.com"},{"name":"antzsoft_trellisys","email":"antzsoft@lifesciencetrust.com"}],"dist":{"shasum":"831b603863a059f024599c5be0dbb0a9ef3768ad","tarball":"https://registry.npmjs.org/@antzsoft/chat-web-sdk/-/chat-web-sdk-1.0.6.tgz","fileCount":14,"integrity":"sha512-xH7VydN28BfpV6Nkf7pLwyAKq2GPsTKS6FXJ0+af6gRa5FdQzNURdCdSmt3++Ji1owy1bdw2dX18VRgMTVKbwg==","signatures":[{"sig":"MEUCIHXr18ehP7ic3oHmb+6ctivVsdvFlr/84nvuasr1d6ISAiEAo1uBQfFYqKD2/FvBKck50T3hEygeuhohlMGJZ7agvcg=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":5474978},"main":"./dist/index.cjs","type":"module","types":"./dist/index.d.ts","module":"./dist/index.js","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","require":"./dist/index.cjs"},"./react":{"types":"./dist/react/index.d.ts","import":"./dist/react/index.js","require":"./dist/react/index.cjs"}},"gitHead":"a6f2b35ba18cf7e8732df11502e1cb147b706db1","scripts":{"lint":"eslint src --ext .ts,.tsx","build":"tsup","typecheck":"tsc --noEmit","build:watch":"tsup --watch"},"_npmUser":{"name":"antz.karthik","email":"karthikmitta@lifesciencetrust.com"},"_npmVersion":"10.9.2","description":"Pluggable web chat UI SDK — React, Next.js, Vue, any JS framework","directories":{},"_nodeVersion":"22.14.0","dependencies":{"webm-muxer":"^5.1.4"},"_hasShrinkwrap":false,"devDependencies":{"tsup":"^8.0.0","react":"^18.2.0","react-dom":"^18.2.0","typescript":"^5.3.0","@types/react":"^18.2.0","lucide-react":"^0.344.0","@types/react-dom":"^18.2.0","@antzsoft/chat-core":"^1.2.7","@tanstack/react-query":"^5.17.19"},"peerDependencies":{"react":">=18.0.0","react-dom":">=18.0.0","@antzsoft/chat-core":">=1.2.7"},"optionalDependencies":{"lucide-react":"^0.344.0","@tanstack/react-query":"^5.17.19"},"peerDependenciesMeta":{"react":{"optional":true},"react-dom":{"optional":true},"@antzsoft/chat-core":{"optional":false}},"_npmOperationalInternal":{"tmp":"tmp/chat-web-sdk_1.0.6_1781608894122_0.1804539736038422","host":"s3://npm-registry-packages-npm-production"}},"1.0.8":{"name":"@antzsoft/chat-web-sdk","version":"1.0.8","author":{"name":"Antz"},"license":"MIT","_id":"@antzsoft/chat-web-sdk@1.0.8","maintainers":[{"name":"antz.karthik","email":"karthikmitta@lifesciencetrust.com"},{"name":"antzsoft_trellisys","email":"antzsoft@lifesciencetrust.com"}],"dist":{"shasum":"090a3cc355090e9bde3936b730e309f55425b9e9","tarball":"https://registry.npmjs.org/@antzsoft/chat-web-sdk/-/chat-web-sdk-1.0.8.tgz","fileCount":14,"integrity":"sha512-+ekP/VKYjdkFeTvxzSQWpbCM3IJ7Ci46/8tGEg8B0ahRkIk6CE92Y5PpXydirisTyv5z8UyKrLW4nMLFjAoapg==","signatures":[{"sig":"MEQCIGvATvDDywlt8sbxGPiK8vEngSfkpUw7ueoEQtjv4DPcAiAa/Kunbtb8zYSTC//azi3A/6YYxBzgRuntIUFNKb1ydQ==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":5484462},"main":"./dist/index.cjs","type":"module","types":"./dist/index.d.ts","module":"./dist/index.js","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","require":"./dist/index.cjs"},"./react":{"types":"./dist/react/index.d.ts","import":"./dist/react/index.js","require":"./dist/react/index.cjs"}},"gitHead":"7d7ceef41a5aca6569e612667f6490ca90e4f1cd","scripts":{"lint":"eslint src --ext .ts,.tsx","build":"tsup","typecheck":"tsc --noEmit","build:watch":"tsup --watch"},"_npmUser":{"name":"antz.karthik","email":"karthikmitta@lifesciencetrust.com"},"_npmVersion":"10.9.2","description":"Pluggable web chat UI SDK — React, Next.js, Vue, any JS framework","directories":{},"_nodeVersion":"22.14.0","dependencies":{"webm-muxer":"^5.1.4"},"_hasShrinkwrap":false,"devDependencies":{"tsup":"^8.0.0","react":"^18.2.0","react-dom":"^18.2.0","typescript":"^5.3.0","@types/react":"^18.2.0","lucide-react":"^0.344.0","@types/react-dom":"^18.2.0","@antzsoft/chat-core":"^1.2.9","@tanstack/react-query":"^5.17.19"},"peerDependencies":{"react":">=18.0.0","react-dom":">=18.0.0","@antzsoft/chat-core":">=1.2.9"},"optionalDependencies":{"lucide-react":"^0.344.0","@tanstack/react-query":"^5.17.19"},"peerDependenciesMeta":{"react":{"optional":true},"react-dom":{"optional":true},"@antzsoft/chat-core":{"optional":false}},"_npmOperationalInternal":{"tmp":"tmp/chat-web-sdk_1.0.8_1782733782280_0.10258590086532093","host":"s3://npm-registry-packages-npm-production"}},"1.0.9":{"name":"@antzsoft/chat-web-sdk","version":"1.0.9","author":{"name":"Antz"},"license":"MIT","_id":"@antzsoft/chat-web-sdk@1.0.9","maintainers":[{"name":"antz.karthik","email":"karthikmitta@lifesciencetrust.com"},{"name":"antzsoft_trellisys","email":"antzsoft@lifesciencetrust.com"}],"dist":{"shasum":"ea5b42995a71bb250e6840c6734b1eafcce5726c","tarball":"https://registry.npmjs.org/@antzsoft/chat-web-sdk/-/chat-web-sdk-1.0.9.tgz","fileCount":14,"integrity":"sha512-Ypa2AR9IKHeoVdjKpoAbNE+POGBrMBV+UYIsDpqnsWTv6K503Y3JQNK+XbelgDXx72QBPlyFZEE8/NMMBiXBjQ==","signatures":[{"sig":"MEUCIAGjZmTWbzCz0ydU8/ndUgxeX59v8RKiH7D/qFT1z2NRAiEA4+GYED9kWl94UaZMHXprrOJBnW6pofFCQ4t72MSuc8c=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":5484462},"main":"./dist/index.cjs","type":"module","types":"./dist/index.d.ts","module":"./dist/index.js","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","require":"./dist/index.cjs"},"./react":{"types":"./dist/react/index.d.ts","import":"./dist/react/index.js","require":"./dist/react/index.cjs"}},"gitHead":"14b30e5c769fd77347f8703b1b3216cc1986694c","scripts":{"lint":"eslint src --ext .ts,.tsx","build":"tsup","typecheck":"tsc --noEmit","build:watch":"tsup --watch"},"_npmUser":{"name":"antz.karthik","email":"karthikmitta@lifesciencetrust.com"},"_npmVersion":"10.9.2","description":"Pluggable web chat UI SDK — React, Next.js, Vue, any JS framework","directories":{},"_nodeVersion":"22.14.0","dependencies":{"webm-muxer":"^5.1.4"},"_hasShrinkwrap":false,"devDependencies":{"tsup":"^8.0.0","react":"^18.2.0","react-dom":"^18.2.0","typescript":"^5.3.0","@types/react":"^18.2.0","lucide-react":"^0.344.0","@types/react-dom":"^18.2.0","@antzsoft/chat-core":"^1.3.0","@tanstack/react-query":"^5.17.19"},"peerDependencies":{"react":">=18.0.0","react-dom":">=18.0.0","@antzsoft/chat-core":">=1.3.0"},"optionalDependencies":{"lucide-react":"^0.344.0","@tanstack/react-query":"^5.17.19"},"peerDependenciesMeta":{"react":{"optional":true},"react-dom":{"optional":true},"@antzsoft/chat-core":{"optional":false}},"_npmOperationalInternal":{"tmp":"tmp/chat-web-sdk_1.0.9_1782740432418_0.5611236407360949","host":"s3://npm-registry-packages-npm-production"}},"1.1.0":{"name":"@antzsoft/chat-web-sdk","version":"1.1.0","author":{"name":"Antz"},"license":"MIT","_id":"@antzsoft/chat-web-sdk@1.1.0","maintainers":[{"name":"antz.karthik","email":"karthikmitta@lifesciencetrust.com"},{"name":"antzsoft_trellisys","email":"antzsoft@lifesciencetrust.com"}],"dist":{"shasum":"5cc491ae653e1b6404bf70886a5cebbb7e1bc011","tarball":"https://registry.npmjs.org/@antzsoft/chat-web-sdk/-/chat-web-sdk-1.1.0.tgz","fileCount":14,"integrity":"sha512-MOmrDs3UeDxsQj2v0OgNFXSPnsretKIjHKHl9F0CGwTT3rmF7U2zXOjLX+UtZWWP/iD9TVMQPvRQucAqMXSyCg==","signatures":[{"sig":"MEYCIQD0LWO9oMmmCDOwtqlMj82y6qk+w8wXDaAB3KSbYc1YrAIhAJMC4B8Nw3Tdpk9k5ujZLD6EWPCkJKFxeFD0e9G81jAF","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":5484462},"main":"./dist/index.cjs","type":"module","types":"./dist/index.d.ts","module":"./dist/index.js","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","require":"./dist/index.cjs"},"./react":{"types":"./dist/react/index.d.ts","import":"./dist/react/index.js","require":"./dist/react/index.cjs"}},"gitHead":"8955a198e2c67658f06c8988c5cba64c5c9ff6f5","scripts":{"lint":"eslint src --ext .ts,.tsx","build":"tsup","typecheck":"tsc --noEmit","build:watch":"tsup --watch"},"_npmUser":{"name":"antz.karthik","email":"karthikmitta@lifesciencetrust.com"},"_npmVersion":"10.9.2","description":"Pluggable web chat UI SDK — React, Next.js, Vue, any JS framework","directories":{},"_nodeVersion":"22.14.0","dependencies":{"webm-muxer":"^5.1.4"},"_hasShrinkwrap":false,"devDependencies":{"tsup":"^8.0.0","react":"^18.2.0","react-dom":"^18.2.0","typescript":"^5.3.0","@types/react":"^18.2.0","lucide-react":"^0.344.0","@types/react-dom":"^18.2.0","@antzsoft/chat-core":"^1.3.1","@tanstack/react-query":"^5.17.19"},"peerDependencies":{"react":">=18.0.0","react-dom":">=18.0.0","@antzsoft/chat-core":">=1.3.1"},"optionalDependencies":{"lucide-react":"^0.344.0","@tanstack/react-query":"^5.17.19"},"peerDependenciesMeta":{"react":{"optional":true},"react-dom":{"optional":true},"@antzsoft/chat-core":{"optional":false}},"_npmOperationalInternal":{"tmp":"tmp/chat-web-sdk_1.1.0_1782760898536_0.4739398080238595","host":"s3://npm-registry-packages-npm-production"}},"1.1.1":{"name":"@antzsoft/chat-web-sdk","version":"1.1.1","author":{"name":"Antz"},"license":"MIT","_id":"@antzsoft/chat-web-sdk@1.1.1","maintainers":[{"name":"antz.karthik","email":"karthikmitta@lifesciencetrust.com"},{"name":"antzsoft_trellisys","email":"antzsoft@lifesciencetrust.com"}],"dist":{"shasum":"15e3883974f9546632315fc3578e845e8d702572","tarball":"https://registry.npmjs.org/@antzsoft/chat-web-sdk/-/chat-web-sdk-1.1.1.tgz","fileCount":14,"integrity":"sha512-iNWZ4FDmlTYtKtH9ytVH8Dtr3PiszgjC+KwNbL6wP5IiIE/AbVkGZ7NjpyxmRapSFzbgIMG22VD++DlVl/IO/Q==","signatures":[{"sig":"MEUCICFSBU2HxVS99g4r5ZL0MvE6oVR7y0hbtg2G26R+WwSuAiEAuHgIk38jtIOwdCvOHWCdxI+wEASr1RYx6/VCkr7XxCY=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":5484462},"main":"./dist/index.cjs","type":"module","types":"./dist/index.d.ts","module":"./dist/index.js","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","require":"./dist/index.cjs"},"./react":{"types":"./dist/react/index.d.ts","import":"./dist/react/index.js","require":"./dist/react/index.cjs"}},"gitHead":"46857716204b144f891f829b73dde53fb92cffd6","scripts":{"lint":"eslint src --ext .ts,.tsx","build":"tsup","typecheck":"tsc --noEmit","build:watch":"tsup --watch"},"_npmUser":{"name":"antz.karthik","email":"karthikmitta@lifesciencetrust.com"},"_npmVersion":"10.9.2","description":"Pluggable web chat UI SDK — React, Next.js, Vue, any JS framework","directories":{},"_nodeVersion":"22.14.0","dependencies":{"webm-muxer":"^5.1.4"},"_hasShrinkwrap":false,"devDependencies":{"tsup":"^8.0.0","react":"^18.2.0","react-dom":"^18.2.0","typescript":"^5.3.0","@types/react":"^18.2.0","lucide-react":"^0.344.0","@types/react-dom":"^18.2.0","@antzsoft/chat-core":"^1.3.2","@tanstack/react-query":"^5.17.19"},"peerDependencies":{"react":">=18.0.0","react-dom":">=18.0.0","@antzsoft/chat-core":">=1.3.2"},"optionalDependencies":{"lucide-react":"^0.344.0","@tanstack/react-query":"^5.17.19"},"peerDependenciesMeta":{"react":{"optional":true},"react-dom":{"optional":true},"@antzsoft/chat-core":{"optional":false}},"_npmOperationalInternal":{"tmp":"tmp/chat-web-sdk_1.1.1_1782809183226_0.6538401322590812","host":"s3://npm-registry-packages-npm-production"}},"1.1.2":{"name":"@antzsoft/chat-web-sdk","version":"1.1.2","author":{"name":"Antz"},"license":"MIT","_id":"@antzsoft/chat-web-sdk@1.1.2","maintainers":[{"name":"antz.karthik","email":"karthikmitta@lifesciencetrust.com"},{"name":"antzsoft_trellisys","email":"antzsoft@lifesciencetrust.com"}],"dist":{"shasum":"1e88261684376961e156e462b19999c9de6cbc3e","tarball":"https://registry.npmjs.org/@antzsoft/chat-web-sdk/-/chat-web-sdk-1.1.2.tgz","fileCount":14,"integrity":"sha512-dB8biwicVRWCFQUYvB4iBR85KrSLtKi9QuQjox2hylE1SOH96G3bhU5mbcvQdVLh9WlRpTmx1uxN+SjQSFvGpQ==","signatures":[{"sig":"MEYCIQCFTQrZ04/VJcjqcWc2AF/F+HxStmQxHZMJUIxGiFfhjwIhAKAaQYq6Nu75QKNlCGnTHkV8jt2seWQ6Nvhrl/UzBEF4","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":5484462},"main":"./dist/index.cjs","type":"module","types":"./dist/index.d.ts","module":"./dist/index.js","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","require":"./dist/index.cjs"},"./react":{"types":"./dist/react/index.d.ts","import":"./dist/react/index.js","require":"./dist/react/index.cjs"}},"gitHead":"b812d8d8573e11ab98f780a9d0642fa12c944902","scripts":{"lint":"eslint src --ext .ts,.tsx","build":"tsup","typecheck":"tsc --noEmit","build:watch":"tsup --watch"},"_npmUser":{"name":"antz.karthik","email":"karthikmitta@lifesciencetrust.com"},"_npmVersion":"10.9.2","description":"Pluggable web chat UI SDK — React, Next.js, Vue, any JS framework","directories":{},"_nodeVersion":"22.14.0","dependencies":{"webm-muxer":"^5.1.4"},"_hasShrinkwrap":false,"devDependencies":{"tsup":"^8.0.0","react":"^18.2.0","react-dom":"^18.2.0","typescript":"^5.3.0","@types/react":"^18.2.0","lucide-react":"^0.344.0","@types/react-dom":"^18.2.0","@antzsoft/chat-core":"^1.3.3","@tanstack/react-query":"^5.17.19"},"peerDependencies":{"react":">=18.0.0","react-dom":">=18.0.0","@antzsoft/chat-core":">=1.3.3"},"optionalDependencies":{"lucide-react":"^0.344.0","@tanstack/react-query":"^5.17.19"},"peerDependenciesMeta":{"react":{"optional":true},"react-dom":{"optional":true},"@antzsoft/chat-core":{"optional":false}},"_npmOperationalInternal":{"tmp":"tmp/chat-web-sdk_1.1.2_1782828298964_0.017273514786317223","host":"s3://npm-registry-packages-npm-production"}},"1.1.3":{"name":"@antzsoft/chat-web-sdk","version":"1.1.3","author":{"name":"Antz"},"license":"MIT","_id":"@antzsoft/chat-web-sdk@1.1.3","maintainers":[{"name":"antz.karthik","email":"karthikmitta@lifesciencetrust.com"},{"name":"antzsoft_trellisys","email":"antzsoft@lifesciencetrust.com"}],"dist":{"shasum":"380b94b24db08b5f9337b45c8aebbfb1a47721ca","tarball":"https://registry.npmjs.org/@antzsoft/chat-web-sdk/-/chat-web-sdk-1.1.3.tgz","fileCount":14,"integrity":"sha512-cNw1gk1Ouy0gxLbhwXjw0mWcM73+8Ucv5HlA3wb7rGpqoa7kgUpy4S+Z4QEd5lFUNeRaMur+bdIkipip4UqHSg==","signatures":[{"sig":"MEYCIQDQBzh8hLjcWe5f6GbRw29rgwuhqLHGNuSSa3zC3eObDAIhAL27AHNdnQ5Vb/T+1N+fh2t1ZI2p/kmzRXxQUnfeO3HG","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":5484462},"main":"./dist/index.cjs","type":"module","types":"./dist/index.d.ts","module":"./dist/index.js","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","require":"./dist/index.cjs"},"./react":{"types":"./dist/react/index.d.ts","import":"./dist/react/index.js","require":"./dist/react/index.cjs"}},"gitHead":"28364fb2a37f38ac408c5fba87aed00f119e3268","scripts":{"lint":"eslint src --ext .ts,.tsx","build":"tsup","typecheck":"tsc --noEmit","build:watch":"tsup --watch"},"_npmUser":{"name":"antz.karthik","email":"karthikmitta@lifesciencetrust.com"},"_npmVersion":"10.9.2","description":"Pluggable web chat UI SDK — React, Next.js, Vue, any JS framework","directories":{},"_nodeVersion":"22.14.0","dependencies":{"webm-muxer":"^5.1.4"},"_hasShrinkwrap":false,"devDependencies":{"tsup":"^8.0.0","react":"^18.2.0","react-dom":"^18.2.0","typescript":"^5.3.0","@types/react":"^18.2.0","lucide-react":"^0.344.0","@types/react-dom":"^18.2.0","@antzsoft/chat-core":"^1.3.4","@tanstack/react-query":"^5.17.19"},"peerDependencies":{"react":">=18.0.0","react-dom":">=18.0.0","@antzsoft/chat-core":">=1.3.4"},"optionalDependencies":{"lucide-react":"^0.344.0","@tanstack/react-query":"^5.17.19"},"peerDependenciesMeta":{"react":{"optional":true},"react-dom":{"optional":true},"@antzsoft/chat-core":{"optional":false}},"_npmOperationalInternal":{"tmp":"tmp/chat-web-sdk_1.1.3_1782890372850_0.5528532143249052","host":"s3://npm-registry-packages-npm-production"}},"1.1.4":{"name":"@antzsoft/chat-web-sdk","version":"1.1.4","author":{"name":"Antz"},"license":"MIT","_id":"@antzsoft/chat-web-sdk@1.1.4","maintainers":[{"name":"antz.karthik","email":"karthikmitta@lifesciencetrust.com"},{"name":"antzsoft_trellisys","email":"antzsoft@lifesciencetrust.com"}],"dist":{"shasum":"c6cc1d22bc1d37fe275f73869337f5f46e3367a4","tarball":"https://registry.npmjs.org/@antzsoft/chat-web-sdk/-/chat-web-sdk-1.1.4.tgz","fileCount":14,"integrity":"sha512-pWYIpBBuIdp9GpfpItDxtQksEoFTjcO8Byx7+Fz3ebR+7BEOdaOlNoqWLHN2R4zjA433YW+zeQeD83/D61QZ7g==","signatures":[{"sig":"MEYCIQCA1cjHgA5/4fOshaFRda3IsdFSmQWahMG8gW20qsbh1wIhAPg+z9O/pL75XNqzbSl6amh4QArFKh90wOpaxPTXnPZf","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":5485746},"main":"./dist/index.cjs","type":"module","types":"./dist/index.d.ts","module":"./dist/index.js","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","require":"./dist/index.cjs"},"./react":{"types":"./dist/react/index.d.ts","import":"./dist/react/index.js","require":"./dist/react/index.cjs"}},"gitHead":"807ea032c387b5f246c2384d37a0b0e0d627d629","scripts":{"lint":"eslint src --ext .ts,.tsx","build":"tsup","typecheck":"tsc --noEmit","build:watch":"tsup --watch"},"_npmUser":{"name":"antz.karthik","email":"karthikmitta@lifesciencetrust.com"},"_npmVersion":"10.9.2","description":"Pluggable web chat UI SDK — React, Next.js, Vue, any JS framework","directories":{},"_nodeVersion":"22.14.0","dependencies":{"webm-muxer":"^5.1.4"},"_hasShrinkwrap":false,"devDependencies":{"tsup":"^8.0.0","react":"^18.2.0","react-dom":"^18.2.0","typescript":"^5.3.0","@types/react":"^18.2.0","lucide-react":"^0.344.0","@types/react-dom":"^18.2.0","@antzsoft/chat-core":"^1.3.7","@tanstack/react-query":"^5.17.19"},"peerDependencies":{"react":">=18.0.0","react-dom":">=18.0.0","@antzsoft/chat-core":">=1.3.7"},"optionalDependencies":{"lucide-react":"^0.344.0","@tanstack/react-query":"^5.17.19"},"peerDependenciesMeta":{"react":{"optional":true},"react-dom":{"optional":true},"@antzsoft/chat-core":{"optional":false}},"_npmOperationalInternal":{"tmp":"tmp/chat-web-sdk_1.1.4_1784138146922_0.9994511657937339","host":"s3://npm-registry-packages-npm-production"}},"1.1.5":{"name":"@antzsoft/chat-web-sdk","version":"1.1.5","author":{"name":"Antz"},"license":"MIT","_id":"@antzsoft/chat-web-sdk@1.1.5","maintainers":[{"name":"antz.karthik","email":"karthikmitta@lifesciencetrust.com"},{"name":"antzsoft_trellisys","email":"antzsoft@lifesciencetrust.com"}],"dist":{"shasum":"964ff6a0904b0f5e0f00dcd09e71b3bac23c828a","tarball":"https://registry.npmjs.org/@antzsoft/chat-web-sdk/-/chat-web-sdk-1.1.5.tgz","fileCount":14,"integrity":"sha512-tiZo9RJzrmFHxGZ5GAZ99zYAafmTRu62x2/SyzKT2jCg4geN23CvC3gdKwtert4Mkj3O0TGXEKExbASHjabu2Q==","signatures":[{"sig":"MEQCIFNGPsEWZm1Rz8sTXxnOi6af7J/NybPADIohlKXCHxOTAiBXwuOs+D8QbwtSG5n1o3iJWHT71rqzExKi9T6D3xNBmA==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":5743890},"main":"./dist/index.cjs","type":"module","types":"./dist/index.d.ts","module":"./dist/index.js","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","require":"./dist/index.cjs"},"./react":{"types":"./dist/react/index.d.ts","import":"./dist/react/index.js","require":"./dist/react/index.cjs"}},"gitHead":"8b5943368f4fa3b518e4bf61ce8f72f7c6828586","scripts":{"lint":"eslint src --ext .ts,.tsx","build":"tsup","typecheck":"tsc --noEmit","build:watch":"tsup --watch"},"_npmUser":{"name":"antz.karthik","email":"karthikmitta@lifesciencetrust.com"},"_npmVersion":"10.9.2","description":"Pluggable web chat UI SDK — React, Next.js, Vue, any JS framework","directories":{},"_nodeVersion":"22.14.0","dependencies":{"webm-muxer":"^5.1.4"},"_hasShrinkwrap":false,"devDependencies":{"tsup":"^8.0.0","react":"^18.2.0","react-dom":"^18.2.0","typescript":"^5.3.0","@types/react":"^18.2.0","lucide-react":"^0.344.0","@types/react-dom":"^18.2.0","@antzsoft/chat-core":"^1.3.9","@tanstack/react-query":"^5.17.19"},"peerDependencies":{"react":">=18.0.0","react-dom":">=18.0.0","@antzsoft/chat-core":">=1.3.9"},"optionalDependencies":{"lucide-react":"^0.344.0","@tanstack/react-query":"^5.17.19"},"peerDependenciesMeta":{"react":{"optional":true},"react-dom":{"optional":true},"@antzsoft/chat-core":{"optional":false}},"_npmOperationalInternal":{"tmp":"tmp/chat-web-sdk_1.1.5_1784635230457_0.14162333617296485","host":"s3://npm-registry-packages-npm-production"}},"1.1.6":{"name":"@antzsoft/chat-web-sdk","version":"1.1.6","author":{"name":"Antz"},"license":"MIT","_id":"@antzsoft/chat-web-sdk@1.1.6","maintainers":[{"name":"antz.karthik","email":"karthikmitta@lifesciencetrust.com"},{"name":"antzsoft_trellisys","email":"antzsoft@lifesciencetrust.com"}],"dist":{"shasum":"cd8ca37ba6108bcbec8d8882eb44f017c8397c99","tarball":"https://registry.npmjs.org/@antzsoft/chat-web-sdk/-/chat-web-sdk-1.1.6.tgz","fileCount":14,"integrity":"sha512-k3Fpdiyhecs/+1MTbXKH5oguKmctKQMlgtXbur/V1pgEEmXH1jHWQwn/ybo8uJOIGGORSBW5r75DbvDp1wN0Pw==","signatures":[{"sig":"MEUCIQDzEdGs0EiPRtq1WtbZay52F8c3HhiamT4HgO1CqFjl2gIgTgqlhHenfbd/sU8mCwAWagTEoS8TvcaWgJmhQDo5r3k=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":6795039},"main":"./dist/index.cjs","type":"module","types":"./dist/index.d.ts","module":"./dist/index.js","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","require":"./dist/index.cjs"},"./react":{"types":"./dist/react/index.d.ts","import":"./dist/react/index.js","require":"./dist/react/index.cjs"}},"gitHead":"ce7bfe6b0b0b51d0b9b1764aca241f5bd5114e9f","scripts":{"lint":"eslint src --ext .ts,.tsx","build":"tsup","typecheck":"tsc --noEmit","build:watch":"tsup --watch"},"_npmUser":{"name":"antz.karthik","email":"karthikmitta@lifesciencetrust.com"},"_npmVersion":"11.17.0","description":"Pluggable web chat UI SDK — React, Next.js, Vue, any JS framework","directories":{},"_nodeVersion":"24.19.0","dependencies":{"zustand":"^4.5.0","webm-muxer":"^5.1.4"},"_hasShrinkwrap":false,"devDependencies":{"tsup":"^8.0.0","react":"^18.2.0","react-dom":"^18.2.0","typescript":"^5.3.0","@types/react":"^18.2.0","lucide-react":"^0.344.0","@types/react-dom":"^18.2.0","@antzsoft/chat-core":"^1.4.5","@tanstack/react-query":"^5.17.19"},"peerDependencies":{"react":">=18.0.0","react-dom":">=18.0.0","@antzsoft/chat-core":">=1.4.5"},"optionalDependencies":{"lucide-react":"^0.344.0","@tanstack/react-query":"^5.17.19"},"peerDependenciesMeta":{"react":{"optional":true},"react-dom":{"optional":true},"@antzsoft/chat-core":{"optional":false}},"_npmOperationalInternal":{"tmp":"tmp/chat-web-sdk_1.1.6_1788265949913_0.36823479296203154","host":"s3://npm-registry-packages-npm-production"}},"1.1.7":{"name":"@antzsoft/chat-web-sdk","version":"1.1.7","author":{"name":"Antz"},"license":"MIT","_id":"@antzsoft/chat-web-sdk@1.1.7","maintainers":[{"name":"antz.karthik","email":"karthikmitta@lifesciencetrust.com"},{"name":"antzsoft_trellisys","email":"antzsoft@lifesciencetrust.com"}],"dist":{"shasum":"70231915ca8c902f37712aa3a978cff5982c0abd","tarball":"https://registry.npmjs.org/@antzsoft/chat-web-sdk/-/chat-web-sdk-1.1.7.tgz","fileCount":14,"integrity":"sha512-8qzntx2MoFi6BGSBdHPRY4rmLETVLQxf6oO43CfUpK53pVKKlFXYqW8lgU5/4ln+iM+Q6mdznUISS7bUIJ8FpQ==","signatures":[{"sig":"MEYCIQDwqxbOL4oglv2L9zqJ5JS8MZhMOo4BU1uBxCdsi2WjcwIhAKanJTYZxJekexaP/OJPNG+NPF9cDkyWd5a4wByoITXE","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":7530713},"main":"./dist/index.cjs","type":"module","types":"./dist/index.d.ts","module":"./dist/index.js","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","require":"./dist/index.cjs"},"./react":{"types":"./dist/react/index.d.ts","import":"./dist/react/index.js","require":"./dist/react/index.cjs"}},"gitHead":"dd5b4ce2d85ca7f83cfeb7e1e524b46cb79ccd62","scripts":{"lint":"eslint src --ext .ts,.tsx","build":"tsup","typecheck":"tsc --noEmit","build:watch":"tsup --watch"},"_npmUser":{"name":"antz.karthik","email":"karthikmitta@lifesciencetrust.com"},"_npmVersion":"11.17.0","description":"Pluggable web chat UI SDK — React, Next.js, Vue, any JS framework","directories":{},"_nodeVersion":"24.19.0","dependencies":{"zustand":"^4.5.0","webm-muxer":"^5.1.4"},"_hasShrinkwrap":false,"devDependencies":{"tsup":"^8.0.0","react":"^18.2.0","react-dom":"^18.2.0","typescript":"^5.3.0","@types/react":"^18.2.0","lucide-react":"^0.344.0","@types/react-dom":"^18.2.0","@antzsoft/chat-core":"^1.4.6","@tanstack/react-query":"^5.17.19"},"peerDependencies":{"react":">=18.0.0","react-dom":">=18.0.0","@antzsoft/chat-core":">=1.4.6"},"optionalDependencies":{"lucide-react":"^0.344.0","@tanstack/react-query":"^5.17.19"},"peerDependenciesMeta":{"react":{"optional":true},"react-dom":{"optional":true},"@antzsoft/chat-core":{"optional":false}},"_npmOperationalInternal":{"tmp":"tmp/chat-web-sdk_1.1.7_1788361742213_0.9895830279041908","host":"s3://npm-registry-packages-npm-production"}},"1.1.8":{"name":"@antzsoft/chat-web-sdk","version":"1.1.8","author":{"name":"Antz"},"license":"MIT","_id":"@antzsoft/chat-web-sdk@1.1.8","maintainers":[{"name":"antz.karthik","email":"karthikmitta@lifesciencetrust.com"},{"name":"antzsoft_trellisys","email":"antzsoft@lifesciencetrust.com"}],"dist":{"shasum":"04d303001c97d54764b8e20c8e7d6f7e5f2b91a6","tarball":"https://registry.npmjs.org/@antzsoft/chat-web-sdk/-/chat-web-sdk-1.1.8.tgz","fileCount":14,"integrity":"sha512-3rQoJ7rsTu6pSJ/dVzxKvWMW7w1Ymp+/S3jLPZ/vo74jhpmpW4d18gnJ52F1xVr0/LH4fcvQx2vkM4oyblnBbA==","signatures":[{"sig":"MEUCIQDKIsii3ehO2jBV7nwNnyG1tB7CtRbVIvBFhfXgK4V+WAIgUtu4huVwp0K8Df/882Dhw81KjiaYjlC27T15IR3ie00=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":8133555},"main":"./dist/index.cjs","type":"module","types":"./dist/index.d.ts","module":"./dist/index.js","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","require":"./dist/index.cjs"},"./react":{"types":"./dist/react/index.d.ts","import":"./dist/react/index.js","require":"./dist/react/index.cjs"}},"gitHead":"2220ba8bd9428117cd9961775c1dc61dd35a8510","scripts":{"lint":"eslint src --ext .ts,.tsx","build":"tsup","typecheck":"tsc --noEmit","build:watch":"tsup --watch"},"_npmUser":{"name":"antz.karthik","email":"karthikmitta@lifesciencetrust.com"},"_npmVersion":"11.17.0","description":"Pluggable web chat UI SDK — React, Next.js, Vue, any JS framework","directories":{},"_nodeVersion":"24.19.0","dependencies":{"zustand":"^4.5.0","webm-muxer":"^5.1.4"},"_hasShrinkwrap":false,"devDependencies":{"tsup":"^8.0.0","react":"^18.2.0","react-dom":"^18.2.0","typescript":"^5.3.0","@types/react":"^18.2.0","lucide-react":"^0.344.0","@types/react-dom":"^18.2.0","@antzsoft/chat-core":"^1.4.6","@tanstack/react-query":"^5.17.19"},"peerDependencies":{"react":">=18.0.0","react-dom":">=18.0.0","@antzsoft/chat-core":">=1.4.6"},"optionalDependencies":{"lucide-react":"^0.344.0","@tanstack/react-query":"^5.17.19"},"peerDependenciesMeta":{"react":{"optional":true},"react-dom":{"optional":true},"@antzsoft/chat-core":{"optional":false}},"_npmOperationalInternal":{"tmp":"tmp/chat-web-sdk_1.1.8_1788840858232_0.029712347252672133","host":"s3://npm-registry-packages-npm-production"}},"1.1.9":{"name":"@antzsoft/chat-web-sdk","version":"1.1.9","author":{"name":"Antz"},"license":"MIT","_id":"@antzsoft/chat-web-sdk@1.1.9","maintainers":[{"name":"antz.karthik","email":"karthikmitta@lifesciencetrust.com"},{"name":"antzsoft_trellisys","email":"antzsoft@lifesciencetrust.com"}],"dist":{"shasum":"65071e8e606fe4eda275f8e00259cd2f258819d8","tarball":"https://registry.npmjs.org/@antzsoft/chat-web-sdk/-/chat-web-sdk-1.1.9.tgz","fileCount":14,"integrity":"sha512-z1QQhat4wO3fpscksuJHT3o8aMp9psN5CENC4PvSMYw/+ilnyHjlDVc4f1xGI+hnHRkjQV7Z28pX+kCgwOv5Hg==","signatures":[{"sig":"MEUCICFphhblHT1+O9br2QwCA2RKqZ2P07gLN9NYNFQ8+1EXAiEAm3vPV6hX3PnhtCq290oPPdswbzIeuCA/6kfoa/sJjMw=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":8156540},"main":"./dist/index.cjs","type":"module","types":"./dist/index.d.ts","module":"./dist/index.js","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","require":"./dist/index.cjs"},"./react":{"types":"./dist/react/index.d.ts","import":"./dist/react/index.js","require":"./dist/react/index.cjs"}},"gitHead":"9fef252ab6d988faa1277bfcadc52341d7df3355","scripts":{"lint":"eslint src --ext .ts,.tsx","build":"tsup","typecheck":"tsc --noEmit","build:watch":"tsup --watch"},"_npmUser":{"name":"antz.karthik","email":"karthikmitta@lifesciencetrust.com"},"_npmVersion":"11.17.0","description":"Pluggable web chat UI SDK — React, Next.js, Vue, any JS framework","directories":{},"_nodeVersion":"24.19.0","dependencies":{"zustand":"^4.5.0","webm-muxer":"^5.1.4"},"_hasShrinkwrap":false,"devDependencies":{"tsup":"^8.0.0","react":"^18.2.0","react-dom":"^18.2.0","typescript":"^5.3.0","@types/react":"^18.2.0","lucide-react":"^0.344.0","@types/react-dom":"^18.2.0","@antzsoft/chat-core":"^1.4.7","@tanstack/react-query":"^5.17.19"},"peerDependencies":{"react":">=18.0.0","react-dom":">=18.0.0","@antzsoft/chat-core":">=1.4.7"},"optionalDependencies":{"lucide-react":"^0.344.0","@tanstack/react-query":"^5.17.19"},"peerDependenciesMeta":{"react":{"optional":true},"react-dom":{"optional":true},"@antzsoft/chat-core":{"optional":false}},"_npmOperationalInternal":{"tmp":"tmp/chat-web-sdk_1.1.9_1788847882817_0.7368189824256239","host":"s3://npm-registry-packages-npm-production"}},"1.2.0":{"name":"@antzsoft/chat-web-sdk","version":"1.2.0","author":{"name":"Antz"},"license":"MIT","_id":"@antzsoft/chat-web-sdk@1.2.0","maintainers":[{"name":"antz.karthik","email":"karthikmitta@lifesciencetrust.com"},{"name":"antzsoft_trellisys","email":"antzsoft@lifesciencetrust.com"}],"dist":{"shasum":"de3da656761bc919458150bf808f4b282da03d17","tarball":"https://registry.npmjs.org/@antzsoft/chat-web-sdk/-/chat-web-sdk-1.2.0.tgz","fileCount":14,"integrity":"sha512-qKuCrcTpcToiAPDkDxjSQdbG1pYlYJxr7wIUAZjeIg45Xlj0GGLd5bTrhyaebgzETwm9qSQfGN9FifVK9Sh09A==","signatures":[{"sig":"MEUCIQCaAEumvvmeTmkXuQoyV/tenQO8R8qWoLxY8EETmhDE+AIgLSTUJWDzc3XiwuEiXqbL6jRdWpBNbJ+W0i1xtFui/WU=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":9192222},"main":"./dist/index.cjs","type":"module","types":"./dist/index.d.ts","module":"./dist/index.js","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","require":"./dist/index.cjs"},"./react":{"types":"./dist/react/index.d.ts","import":"./dist/react/index.js","require":"./dist/react/index.cjs"}},"gitHead":"82a308373c0fd9aca87e8f2bd516f354e1be506e","scripts":{"lint":"eslint src --ext .ts,.tsx","build":"tsup","typecheck":"tsc --noEmit","build:watch":"tsup --watch"},"_npmUser":{"name":"antz.karthik","email":"karthikmitta@lifesciencetrust.com"},"_npmVersion":"11.17.0","description":"Pluggable web chat UI SDK — React, Next.js, Vue, any JS framework","directories":{},"_nodeVersion":"24.19.0","dependencies":{"zustand":"^4.5.0","webm-muxer":"^5.1.4"},"_hasShrinkwrap":false,"devDependencies":{"tsup":"^8.0.0","react":"^18.2.0","react-dom":"^18.2.0","typescript":"^5.3.0","@types/react":"^18.2.0","lucide-react":"^0.344.0","@types/react-dom":"^18.2.0","@antzsoft/chat-core":"^1.4.8","@tanstack/react-query":"^5.17.19"},"peerDependencies":{"react":">=18.0.0","react-dom":">=18.0.0","@antzsoft/chat-core":">=1.4.8"},"optionalDependencies":{"lucide-react":"^0.344.0","@tanstack/react-query":"^5.17.19"},"peerDependenciesMeta":{"react":{"optional":true},"react-dom":{"optional":true},"@antzsoft/chat-core":{"optional":false}},"_npmOperationalInternal":{"tmp":"tmp/chat-web-sdk_1.2.0_1789010520674_0.20849057910179813","host":"s3://npm-registry-packages-npm-production"}},"1.2.1":{"name":"@antzsoft/chat-web-sdk","version":"1.2.1","author":{"name":"Antz"},"license":"MIT","_id":"@antzsoft/chat-web-sdk@1.2.1","maintainers":[{"name":"antz.karthik","email":"karthikmitta@lifesciencetrust.com"},{"name":"antzsoft_trellisys","email":"antzsoft@lifesciencetrust.com"}],"dist":{"shasum":"4b1d0da5a2e9b335cfbdf7f056e13b985b9f750a","tarball":"https://registry.npmjs.org/@antzsoft/chat-web-sdk/-/chat-web-sdk-1.2.1.tgz","fileCount":14,"integrity":"sha512-gM9RltYT9oCGrmFYfgViUKV7wL/0tOp4daYTVvceq+M2cQCHvgQRK8/gQf7xAmuuL62AqQWZjDk2xph2V1AfbQ==","signatures":[{"sig":"MEUCIHYVPtQfk/29YO6XkfO/sJ17Fm8aurFpO4fPfY7bGdb/AiEAg93cBq29B8mVJTzTSv5pNwR21b55+i8R1htnIz/rD0E=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":9198370},"main":"./dist/index.cjs","type":"module","types":"./dist/index.d.ts","module":"./dist/index.js","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","require":"./dist/index.cjs"},"./react":{"types":"./dist/react/index.d.ts","import":"./dist/react/index.js","require":"./dist/react/index.cjs"}},"gitHead":"b405897741d573b9a66a18ef502b32d834251529","scripts":{"lint":"eslint src --ext .ts,.tsx","build":"tsup","typecheck":"tsc --noEmit","build:watch":"tsup --watch"},"_npmUser":{"name":"antz.karthik","email":"karthikmitta@lifesciencetrust.com"},"_npmVersion":"11.17.0","description":"Pluggable web chat UI SDK — React, Next.js, Vue, any JS framework","directories":{},"_nodeVersion":"24.19.0","dependencies":{"zustand":"^4.5.0","webm-muxer":"^5.1.4"},"_hasShrinkwrap":false,"devDependencies":{"tsup":"^8.0.0","react":"^18.2.0","react-dom":"^18.2.0","typescript":"^5.3.0","@types/react":"^18.2.0","lucide-react":"^0.344.0","@types/react-dom":"^18.2.0","@antzsoft/chat-core":"^1.4.8","@tanstack/react-query":"^5.17.19"},"peerDependencies":{"react":">=18.0.0","react-dom":">=18.0.0","@antzsoft/chat-core":">=1.4.8"},"optionalDependencies":{"lucide-react":"^0.344.0","@tanstack/react-query":"^5.17.19"},"peerDependenciesMeta":{"react":{"optional":true},"react-dom":{"optional":true},"@antzsoft/chat-core":{"optional":false}},"_npmOperationalInternal":{"tmp":"tmp/chat-web-sdk_1.2.1_1789040095404_0.14779563183992006","host":"s3://npm-registry-packages-npm-production"}},"1.2.2":{"_id":"@antzsoft/chat-web-sdk@1.2.2","dist":{"shasum":"a44fd03878b65651aeacb0326ad224665f0a79db","tarball":"https://registry.npmjs.org/@antzsoft/chat-web-sdk/-/chat-web-sdk-1.2.2.tgz","fileCount":14,"integrity":"sha512-WHOZZpqE6GXEfxcDL2XgFKZipsGMZ7PXI0iEUdnzXb/cdJVPK7JBIwHW+riB5WNOqxlJCm9DRD+dbwr9sTH6yA==","signatures":[{"sig":"MEUCIGH4jJ8THOMhEBmwyOh85DvjPBkNzrQlIFzrHHc9k9GCAiEAoGfdLQ+eThG++GX+pVLfbjCcLsejE1BCW9S3vgqK4c4=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIQCZ1cnLnrgs9KFNdrnCGtjmh2fq4AvRM+WlSwXEsa4niAIgX9o5PbHNYs/ccEOmnCmT5Ey+yeeUy2muTTKKJ2tNnAM="}],"unpackedSize":9880280},"main":"./dist/index.cjs","name":"@antzsoft/chat-web-sdk","type":"module","types":"./dist/index.d.ts","author":{"name":"Antz"},"module":"./dist/index.js","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","require":"./dist/index.cjs"},"./react":{"types":"./dist/react/index.d.ts","import":"./dist/react/index.js","require":"./dist/react/index.cjs"}},"gitHead":"04145417ba68f3711ff065ead62e3460a6a92897","license":"MIT","scripts":{"lint":"eslint src --ext .ts,.tsx","build":"tsup","typecheck":"tsc --noEmit","build:watch":"tsup --watch"},"version":"1.2.2","_npmUser":{"name":"antz.karthik","email":"karthikmitta@lifesciencetrust.com"},"_npmVersion":"11.17.0","description":"Pluggable web chat UI SDK — React, Next.js, Vue, any JS framework","directories":{},"maintainers":[{"name":"antz.karthik","email":"karthikmitta@lifesciencetrust.com"},{"name":"antzsoft_trellisys","email":"antzsoft@lifesciencetrust.com"}],"_nodeVersion":"24.19.0","dependencies":{"zustand":"^4.5.0","webm-muxer":"^5.1.4"},"_hasShrinkwrap":false,"devDependencies":{"tsup":"^8.0.0","react":"^18.2.0","react-dom":"^18.2.0","typescript":"^5.3.0","@types/react":"^18.2.0","lucide-react":"^0.344.0","@types/react-dom":"^18.2.0","@antzsoft/chat-core":"^1.4.9","@tanstack/react-query":"^5.17.19"},"peerDependencies":{"react":">=18.0.0","react-dom":">=18.0.0","@antzsoft/chat-core":">=1.4.9"},"optionalDependencies":{"lucide-react":"^0.344.0","@tanstack/react-query":"^5.17.19"},"peerDependenciesMeta":{"react":{"optional":true},"react-dom":{"optional":true},"@antzsoft/chat-core":{"optional":false}},"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/chat-web-sdk_1.2.2_1789132288595_0.7676623341615416"}}},"time":{"created":"2026-05-25T13:50:53.913Z","modified":"2026-09-11T13:11:28.924Z","1.0.0":"2026-05-25T13:50:54.678Z","1.0.1":"2026-05-27T08:58:13.345Z","1.0.2":"2026-05-29T05:43:21.775Z","1.0.3":"2026-06-01T05:11:52.326Z","1.0.4":"2026-06-02T12:17:54.665Z","1.0.5":"2026-06-03T11:31:50.060Z","1.0.6":"2026-06-16T11:21:34.309Z","1.0.8":"2026-06-29T11:49:42.451Z","1.0.9":"2026-06-29T13:40:32.617Z","1.1.0":"2026-06-29T19:21:38.752Z","1.1.1":"2026-06-30T08:46:23.393Z","1.1.2":"2026-06-30T14:04:59.173Z","1.1.3":"2026-07-01T07:19:33.031Z","1.1.4":"2026-07-15T17:55:47.133Z","1.1.5":"2026-07-21T12:00:30.626Z","1.1.6":"2026-09-01T12:32:30.226Z","1.1.7":"2026-09-02T15:09:02.378Z","1.1.8":"2026-09-08T04:14:18.518Z","1.1.9":"2026-09-08T06:11:23.032Z","1.2.0":"2026-09-10T03:22:00.892Z","1.2.1":"2026-09-10T11:34:55.591Z","1.2.2":"2026-09-11T13:11:28.750Z"},"author":{"name":"Antz"},"license":"MIT","description":"Pluggable web chat UI SDK — React, Next.js, Vue, any JS framework","maintainers":[{"name":"antz.karthik","email":"karthikmitta@lifesciencetrust.com"},{"name":"antzsoft_trellisys","email":"antzsoft@lifesciencetrust.com"}],"readme":"# @antzsoft/chat-web-sdk\n\nDrop-in chat UI for React and Next.js — real-time messaging with 5 layout modes, built-in auth, theming, file uploads, voice messages, and push notifications, all in a single component.\n\n[![npm version](https://img.shields.io/npm/v/@antzsoft/chat-web-sdk.svg)](https://www.npmjs.com/package/@antzsoft/chat-web-sdk)\n[![license](https://img.shields.io/npm/l/@antzsoft/chat-web-sdk.svg)](./LICENSE)\n\n---\n\n## Overview\n\n`@antzsoft/chat-web-sdk` gives you a fully-featured chat UI that you can drop into any React or Next.js app with a single component. It re-exports everything from `@antzsoft/chat-core` and layers on top of it:\n\n- **React components** — `<AntzChat />`, `<AntzChatProvider />`, individual layout shells, and lower-level chat UI components\n- **Hooks** — conversations, messages, send/edit/delete, typing, uploads, socket status, responsive breakpoints\n- **5 layout modes** — floating bubble, embedded panel, sidebar drawer, fullscreen overlay, mobile webview\n- **Built-in auth UI** — optional login/register screens with token-based and provider-based flows\n- **Theming** — light/dark/system modes with full color, font, and border-radius customization\n- **File uploads** — images, video, audio, and documents with per-type size limits and progress tracking\n- **Voice messages** — in-browser recording and playback\n- **Reactions** — emoji reactions on messages\n- **Mentions** — `@`-mention members in group chats (with admin-gated `@all`); mentions notify even a muted user\n- **Read receipts** — per-message delivery and read status\n- **Typing indicators** — real-time \"is typing\" display\n- **Starred messages** — bookmark important messages\n- **Message search** — search within a conversation\n- **Groups** — create and manage group conversations\n- **Push notifications** — Web Push (VAPID) integration via tokenProvider\n- **Responsive** — container-query-aware layout that adapts from 220 px to full-width\n\n---\n\n## Installation\n\n```bash\nnpm install @antzsoft/chat-web-sdk\n```\n\n### Peer dependencies\n\n```bash\nnpm install react react-dom\n```\n\nReact 18 or higher is required.\n\n### Optional dependencies\n\n```bash\n# Required if you use the hook-based query API (useConversations, useMessages, etc.)\nnpm install @tanstack/react-query\n\n# Required for icon rendering inside the built-in UI components\nnpm install lucide-react\n```\n\nBoth packages are listed as `optionalDependencies` in the SDK. They are bundled into the SDK's own React components, so if you only use `<AntzChat />` you do not need to install them separately — they will be resolved from the SDK's own node_modules. You only need to install them yourself if your application code imports from them directly.\n\n---\n\n## Quick Start\n\n```tsx\n// app/chat/page.tsx  (Next.js App Router)\n'use client';\n\nimport { AntzChat } from '@antzsoft/chat-web-sdk';\n\nexport default function ChatPage() {\n  return (\n    <AntzChat\n      config={{\n        apiUrl: 'https://api.yourapp.com/api/v1',\n        authToken: 'your-jwt-token',\n      }}\n      layout={{ mode: 'floating' }}\n    />\n  );\n}\n```\n\nThat is the entire integration. The component:\n1. Connects to the WebSocket server\n2. Loads conversations and messages\n3. Shows a floating chat bubble that expands into a full chat panel\n4. Manages auth state (restores session from localStorage between page reloads)\n\n---\n\n## The AntzChat Component\n\n`<AntzChat />` is the main entry point. It composes `AntzChatProvider` (config, theme, socket), the selected layout shell, an optional auth gate, and the chat UI.\n\n```tsx\nimport { AntzChat } from '@antzsoft/chat-web-sdk';\n\n<AntzChat\n  config={webChatConfig}\n  theme={themeConfig}\n  layout={layoutConfig}\n  features={featureConfig}\n/>\n```\n\n### Props (AntzChatProps)\n\n| Prop | Type | Required | Description |\n|------|------|----------|-------------|\n| `config` | `WebChatConfig` | Yes | Server URLs, auth, upload settings |\n| `theme` | `ThemeConfig` | No | Colors, fonts, border radius, pattern |\n| `layout` | `LayoutConfig` | No | Layout mode and mode-specific options |\n| `features` | `FeatureConfig` | No | Feature flags and view mode |\n| `conversationListFilters` | `ConversationListFilters` | No | Server-side filters applied to the conversation list — changing these refetches from the server with correct pagination |\n\n---\n\n## WebChatConfig\n\n`WebChatConfig` extends the platform-agnostic `AntzChatConfig` from `@antzsoft/chat-core`. The web SDK pre-fills `platformUploadFn` (XHR-based upload with progress) and `persistStorage` (localStorage), so you do not need to supply them.\n\n```typescript\ninterface WebChatConfig {\n  /** REST API base URL — e.g. \"https://api.yourapp.com/api/v1\" */\n  apiUrl: string;\n\n  /**\n   * WebSocket server URL.\n   * Defaults to apiUrl with the /api/vN path stripped.\n   * The SDK connects to {socketUrl}/chat\n   */\n  socketUrl?: string;\n\n  /**\n   * Static JWT — use this when you already have a token at render time\n   * (e.g. SSO / your own auth flow).\n   * Use either authToken OR authProvider, not both.\n   */\n  authToken?: string;\n\n  /**\n   * Async function that returns a token string.\n   * Called before REST requests and on socket reconnect.\n   * Preferred when the host app manages its own token refresh lifecycle.\n   */\n  authProvider?: () => Promise<string>;\n\n  /** Required for multi-tenant backends. Sent as X-Tenant-ID header. */\n  tenantId?: string;\n\n  /**\n   * Enable payload-level transit encryption for all HTTP and socket traffic.\n   * Uses ECDH key exchange (X25519/P-256) + AES-256-GCM to encrypt every\n   * request, response, and socket event on the wire — independent of TLS.\n   * Server must have TRANSIT_ENCRYPTION_ENABLED=true (default).\n   * Default: true. Set false only for local development or debugging.\n   * Safe to toggle anytime — no data migration needed (wire-only, never stored).\n   */\n  transitEncryption?: boolean;\n\n  /** File upload constraints and callbacks. */\n  upload?: {\n    /**\n     * Per-type size limits in MB, or a single number applied to all types.\n     * Defaults: image 5 MB, video 25 MB, audio 10 MB, document 10 MB.\n     */\n    maxFileSizeMB?: number | {\n      image?: number;\n      video?: number;\n      audio?: number;\n      document?: number;\n      default?: number;\n    };\n\n    /** Max number of files per message. Default: 10 */\n    maxFilesPerMessage?: number;\n\n    /** Which file categories users can attach. Default: all four types. */\n    allowedTypes?: Array<'image' | 'video' | 'audio' | 'document'>;\n\n    /** Called when a file fails validation or upload. */\n    onUploadError?: (file: UploadableFile, error: Error) => void;\n\n    /** Called with aggregate progress (0–100) during a batch upload. */\n    onProgress?: (progress: number) => void;\n  };\n\n  /**\n   * The user's ID in the external auth system.\n   * Required for non-builtin authentication modes (antz, external, wso2).\n   * Sent as the \"x-user-id\" request header when provided.\n   */\n  userId?: string;\n\n  /**\n   * Optional profile picture for non-builtin authentication modes.\n   * Supply a publicly accessible URL or a base64-encoded data URI.\n   * The server fetches/decodes the image, stores it in its own storage,\n   * and serves back a 15-minute signed URL.\n   */\n  avatar?: {\n    url?: string;\n    base64?: string;\n  };\n\n  /**\n   * Pre-filled by the web SDK — XHR-based upload with progress events.\n   * Override only if you need a custom upload transport.\n   */\n  platformUploadFn?: PlatformUploadFn;\n\n  /**\n   * Pre-filled by the web SDK — canvas + CompressionStream compressor.\n   * Override to use a custom compression implementation.\n   * Set compression: { enabled: false } to disable without overriding.\n   */\n  platformCompressFn?: PlatformCompressFn;\n\n  /**\n   * Pre-filled by the web SDK — localStorage adapter for auth token persistence.\n   * Override to use sessionStorage or an in-memory store.\n   */\n  persistStorage?: PersistStorage;\n\n  /**\n   * Optional compression settings. Compression is enabled by default on web.\n   * Pass { enabled: false } to disable.\n   */\n  compression?: {\n    /** Master switch. Default: true */\n    enabled?: boolean;\n    /** WebP encode quality, 0–1. Default: 0.85 */\n    imageQuality?: number;\n    /** Longest side cap in px. Default: 1920 */\n    imageMaxDimension?: number;\n    /** gzip text/JSON/CSV/XML/YAML/SVG. Default: true */\n    compressDocuments?: boolean;\n  };\n}\n```\n\n---\n\n## Layout Modes\n\nPass a `LayoutConfig` to the `layout` prop to control how the chat UI is presented in your app.\n\n```typescript\ninterface LayoutConfig {\n  mode?: 'floating' | 'embedded' | 'sidebar' | 'fullscreen' | 'mobile-webview';\n  position?: 'bottom-right' | 'bottom-left' | 'top-right' | 'top-left'; // floating only\n  width?: string;       // CSS width value, e.g. '400px'\n  height?: string;      // CSS height value, e.g. '600px'\n  zIndex?: number;      // default: 9999\n  initialOpen?: boolean;\n  hideLauncher?: boolean;   // floating only — suppress the built-in FAB\n  open?: boolean;           // floating only — controlled open state\n  onOpenChange?: (open: boolean) => void;\n  fullscreen?: boolean;     // floating only — controlled fullscreen state\n  onFullscreenChange?: (fullscreen: boolean) => void;\n  drawerSide?: 'left' | 'right'; // sidebar only, default: 'right'\n  showBackdrop?: boolean;\n  collapsibleList?: {          // two-column modes — see \"Collapsible conversation list\"\n    enabled?: boolean;         // default: true\n    minWidth?: number;         // default: 640\n    maxWidth?: number;         // default: 1100\n    defaultCollapsed?: boolean;// default: false\n  };\n}\n```\n\n---\n\n### Collapsible conversation list\n\nIn the two-column modes (`fullscreen`, `embedded`, `sidebar`) the user can collapse the\nconversation column away — the open chat then fills the container, and a burger button in\nthe chat header brings the list back. The same `«` / burger pair the floating drawer\nalready uses, applied to the side-by-side layout.\n\nIt is offered only inside a container-width band, because outside it the control is either\npointless or harmful:\n\n| Container width | Behaviour |\n| --- | --- |\n| `< minWidth` (640 px) | Already single-column — list and chat are separate screens with a `‹` back button, so there is nothing to collapse. |\n| `minWidth … maxWidth` | Two columns **plus** the `«` collapse button. This is the tablet / split-window band where both columns fit but neither has room to breathe. |\n| `≥ maxWidth` (1100 px) | Two columns, list permanently visible. Both fit comfortably, and hiding the list would only leave dead space beside the chat. |\n\nWidths are measured on the SDK's **own container**, not the window, so an embedded panel\nnarrower than the viewport is judged as it actually renders.\n\n```tsx\n<AntzChat\n  config={config}\n  layout={{\n    mode: 'fullscreen',\n    collapsibleList: {\n      minWidth: 640,       // from here up, offer the collapse button\n      maxWidth: 1280,      // from here up, pin the list open\n      defaultCollapsed: false,\n    },\n  }}\n/>\n```\n\n`minWidth` is clamped up to 640 — the SDK's own single-column breakpoint — since below it\nthere is no second column to collapse. Pass `maxWidth: Infinity` to keep the toggle at\nevery width above `minWidth`, or `enabled: false` to pin the list open everywhere.\n\nThe collapsed/expanded choice lives in component state for the session: it survives\nresizing out of the band and back (a user who collapsed at tablet width finds it collapsed\nagain after a trip through desktop width), and resets on reload.\n\n---\n\n### 1. floating (default)\n\nA fixed chat bubble anchored to a corner of the viewport. Clicking the bubble opens a panel above it. On mobile, the panel expands to full-screen with a semi-transparent backdrop.\n\n**Use case:** Customer support widgets, contextual help, any situation where chat should not disrupt the main page layout.\n\n```tsx\n<AntzChat\n  config={config}\n  layout={{\n    mode: 'floating',\n    position: 'bottom-right',   // 'bottom-right' | 'bottom-left' | 'top-right' | 'top-left'\n    width: '400px',             // panel width on desktop\n    height: '600px',            // panel height on desktop\n    initialOpen: false,         // start with panel closed\n    showBackdrop: false,        // show backdrop behind panel on desktop (always shown on mobile)\n    zIndex: 9999,\n  }}\n/>\n```\n\nThe FAB (floating action button) is 56 px and uses `var(--antz-primary)` as its background color. On mobile the margin auto-reduces from 24 px to 16 px.\n\n**Driving open/close from your own UI.** Set `hideLauncher: true` to omit the built-in FAB, then drive the panel from `open`/`onOpenChange` — e.g. a tab in your own nav bar:\n\n```tsx\nconst [chatOpen, setChatOpen] = useState(false);\n\n<AntzChat\n  config={config}\n  layout={{\n    mode: 'floating',\n    hideLauncher: true,\n    open: chatOpen,\n    onOpenChange: setChatOpen,\n  }}\n/>\n```\n\n**Controlled fullscreen.** By default the only way into fullscreen is the user tapping the expand button in the panel header — its own `isFullscreen` state is private to the SDK. Set `fullscreen`/`onFullscreenChange` (mirroring `open`/`onOpenChange`) to drive it yourself instead — for example, to always open chat fullscreen from your own nav tab regardless of viewport width:\n\n```tsx\n<AntzChat\n  config={config}\n  layout={{\n    mode: 'floating',\n    hideLauncher: true,\n    open: chatOpen,\n    onOpenChange: setChatOpen,\n    fullscreen: true,\n    onFullscreenChange: () => {}, // called if the header's collapse button is used\n  }}\n/>\n```\n\nOnce `fullscreen` is set, expanding and collapsing are driven entirely by the prop — the header's expand/collapse button calls `onFullscreenChange` instead of managing its own state, so keep it in sync if you want the button's clicks reflected back into your state.\n\nBelow the 640 px mobile breakpoint the panel is already full-bleed (`inset: 0`) regardless of `fullscreen`, so a controlled `true` there changes nothing about layout — it's honoured anyway (no special-casing for mobile), which just means it additionally suppresses the backdrop and the built-in FAB, same as it does on desktop. That makes a constant `fullscreen: true` safe to pass unconditionally for a host that wants one fullscreen chat experience at any viewport width.\n\n---\n\n### 2. embedded\n\nRenders inline inside whatever container you give it. The chat panel fills 100% of the container's width and height. No fixed positioning — behaves like any other block element.\n\n**Use case:** A dedicated `/chat` page, a chat section inside a dashboard layout, a split-pane view you control yourself.\n\n```tsx\n// Give the container explicit dimensions\n<div style={{ width: '100%', height: '600px' }}>\n  <AntzChat\n    config={config}\n    layout={{\n      mode: 'embedded',\n      // width/height default to '100%' and fill the container\n    }}\n  />\n</div>\n```\n\n---\n\n### 3. sidebar\n\nA slide-in drawer that covers the right (or left) edge of the viewport. Opens via `initialOpen: true` or by calling `setOpen` on the `SidebarLayout` component. A semi-transparent backdrop overlays the main content.\n\n**Use case:** Help/support panels that slide in over existing content without a full navigation change, CRM sidebars.\n\n```tsx\n<AntzChat\n  config={config}\n  layout={{\n    mode: 'sidebar',\n    drawerSide: 'right',     // 'left' | 'right'\n    width: '420px',          // drawer width on desktop; auto-fills on mobile/tablet\n    initialOpen: false,\n    showBackdrop: true,      // default: true\n    zIndex: 9999,\n  }}\n/>\n```\n\nWidth behavior:\n- Mobile (< 640 px): `100vw`\n- Tablet (640–1023 px): `min(width, 100vw)`\n- Desktop (≥ 1024 px): the configured `width`\n\n---\n\n### 4. fullscreen\n\nA fixed overlay that covers the entire viewport (`position: fixed; inset: 0`). Unlike `embedded`, this uses fixed positioning and sits on top of all other content.\n\n**Use case:** A full-screen chat experience triggered from a nav item, modals, or apps where chat is the primary UI.\n\n```tsx\n<AntzChat\n  config={config}\n  layout={{\n    mode: 'fullscreen',\n    zIndex: 9999,\n  }}\n/>\n```\n\n---\n\n### 5. mobile-webview\n\nFills `100dvw × 100dvh` and is specifically optimized for rendering inside a React Native `<WebView>`. It applies CSS `env(safe-area-inset-*)` for iPhone notch and home-indicator clearance, disables iOS rubber-band scroll, injects a `viewport-fit=cover` meta tag if one is not already present, and forces a single-column layout regardless of container width.\n\n**Use case:** Hybrid mobile apps that serve the chat UI inside a React Native WebView.\n\n```tsx\n// In your Next.js or standalone web page served to the WebView:\n<AntzChat\n  config={config}\n  layout={{ mode: 'mobile-webview' }}\n/>\n```\n\n```tsx\n// In your React Native app:\nimport { WebView } from 'react-native-webview';\n\n<WebView\n  source={{ uri: 'https://yourapp.com/chat' }}\n  style={{ flex: 1 }}\n  contentInsetAdjustmentBehavior=\"never\"\n  bounces={false}\n/>\n```\n\n---\n\n## Theming\n\n### ThemeConfig\n\n```typescript\ninterface ThemeConfig {\n  /**\n   * Color scheme mode.\n   * 'system' reads the user's OS preference via prefers-color-scheme.\n   * Default: 'light'\n   */\n  mode?: 'light' | 'dark' | 'system';\n\n  colors?: {\n    primary?: string;          // FAB, send button, active states (default: #25D366)\n    primaryDark?: string;      // Hover/active variant of primary (default: #128C7E)\n    chatBackground?: string;   // Message list background (default: #ECE5DD light / #0B141A dark)\n    bubbleOutgoing?: string;   // Sent message bubble background (default: #DCF8C6 light / #005C4B dark)\n    bubbleIncoming?: string;   // Received message bubble background (default: #FFFFFF light / #202C33 dark)\n    sidebar?: string;          // Conversation list panel background\n    header?: string;           // Conversation list header background\n    inputBackground?: string;  // Message input bar background\n    textPrimary?: string;      // Primary text color\n    textSecondary?: string;    // Secondary / muted text color\n  };\n\n  fonts?: {\n    family?: string;     // CSS font-family string\n    sizeBase?: string;   // CSS font-size, e.g. '14px'\n  };\n\n  /** CSS border-radius applied to message bubbles and other rounded elements */\n  borderRadius?: string;\n\n  /**\n   * Background pattern for the message area.\n   * 'default' — subtle radial dot grid\n   * 'none'    — flat background color\n   * Any other string is treated as a raw CSS `background-image` value\n   */\n  backgroundPattern?: 'default' | 'none' | string;\n}\n```\n\nColors are injected as CSS custom properties on the root chat element, so your own CSS can reference them:\n\n```css\n/* Available CSS variables (scoped to .antz-chat-root) */\n--antz-primary\n--antz-primary-dark\n--antz-chat-bg\n--antz-bubble-outgoing\n--antz-bubble-incoming\n--antz-sidebar\n--antz-header\n--antz-input-bg\n--antz-text-primary\n--antz-text-secondary\n--antz-font-family\n--antz-font-size-base\n--antz-border-radius\n```\n\n### Light theme example\n\n```tsx\n<AntzChat\n  config={config}\n  theme={{\n    mode: 'light',\n    colors: {\n      primary: '#25D366',\n      primaryDark: '#128C7E',\n      chatBackground: '#ECE5DD',\n      bubbleOutgoing: '#DCF8C6',\n      bubbleIncoming: '#FFFFFF',\n      sidebar: '#FFFFFF',\n      header: '#008069',\n      inputBackground: '#F0F2F5',\n      textPrimary: '#111B21',\n      textSecondary: '#667781',\n    },\n  }}\n/>\n```\n\n### Dark theme example\n\n```tsx\n<AntzChat\n  config={config}\n  theme={{\n    mode: 'dark',\n    colors: {\n      primary: '#25D366',\n      primaryDark: '#128C7E',\n      chatBackground: '#0B141A',\n      bubbleOutgoing: '#005C4B',\n      bubbleIncoming: '#202C33',\n      sidebar: '#111B21',\n      header: '#202C33',\n      inputBackground: '#2A3942',\n      textPrimary: '#E9EDEF',\n      textSecondary: '#8696A0',\n    },\n  }}\n/>\n```\n\n### Matching your app's brand colors\n\n```tsx\n<AntzChat\n  config={config}\n  theme={{\n    mode: 'system',   // automatically follows OS preference\n    colors: {\n      primary: '#6366F1',       // Indigo — your brand primary\n      primaryDark: '#4F46E5',   // Darker shade for hover states\n      header: '#4F46E5',        // Sidebar header matches brand\n    },\n    fonts: {\n      family: '\"Inter\", sans-serif',\n      sizeBase: '14px',\n    },\n    borderRadius: '12px',\n    backgroundPattern: 'none',  // clean flat background\n  }}\n/>\n```\n\n---\n\n## Feature Flags (FeatureConfig)\n\nAll features default to `true` (enabled). Set a flag to `false` to hide the corresponding UI.\n\n```typescript\ninterface FeatureConfig {\n  /** Emoji reactions on messages. Default: true */\n  reactions?: boolean;\n\n  /** Voice message recording and playback. Default: true */\n  voiceMessages?: boolean;\n\n  /** Per-message read receipts (sent / delivered / read ticks). Default: true */\n  readReceipts?: boolean;\n\n  /** \"is typing...\" indicator. Default: true */\n  typingIndicators?: boolean;\n\n  /** Star / bookmark messages. Default: true */\n  starredMessages?: boolean;\n\n  /** In-conversation message search. Default: true */\n  messageSearch?: boolean;\n\n  /** Group conversation creation and management. Default: true */\n  groups?: boolean;\n\n  /**\n   * Show the built-in login and register UI when the user is not authenticated.\n   * Set to false when you handle auth externally (authToken / authProvider).\n   * Default: true\n   */\n  builtInAuth?: boolean;\n\n  /**\n   * 'full'                — shows conversation list + chat panel (default)\n   * 'single-conversation' — skips the conversation list and opens directly\n   *                         into the conversation specified by defaultConversationId\n   */\n  viewMode?: 'full' | 'single-conversation';\n\n  /**\n   * Used with viewMode: 'single-conversation'.\n   * The SDK opens this conversation immediately on mount.\n   */\n  defaultConversationId?: string;\n\n  /** Push notification integration. See Push Notifications section. */\n  pushNotifications?: PushNotificationConfig;\n}\n```\n\n### Example: customer support widget (minimal feature set)\n\n```tsx\n<AntzChat\n  config={config}\n  features={{\n    reactions: false,\n    voiceMessages: false,\n    starredMessages: false,\n    messageSearch: false,\n    groups: false,\n    builtInAuth: false,     // auth handled externally via authToken\n    viewMode: 'single-conversation',\n    defaultConversationId: 'support-conv-id',\n  }}\n/>\n```\n\n---\n\n## Zoo (Tenant) Selector\n\nBy default, the host app resolves a single `tenantId` and passes it to `config.tenantId` for the\nlife of the mount — the SDK never changes it. Set `features.zooSelector` to let the SDK own\nselection instead, for users who belong to more than one zoo (tenant):\n\n- **1 zoo** → auto-selected, no UI shown.\n- **N zoos** → a default is selected, with a header dropdown to switch.\n- The zoo list is still supplied by the host — the SDK adds no new API call, and does not fall\n  back to `config.tenantId` when the selector is enabled.\n\nNot supported under `builtInAuth` (one account maps to exactly one tenant there) — enabling it\nin that mode is a no-op with a console warning.\n\n```typescript\ninterface ZooSelectorConfig {\n  /** Master switch. Default: false — existing integrations are untouched. */\n  enabled?: boolean;\n\n  /**\n   * The host-supplied zoo list.\n   *\n   *   undefined | null — not loaded yet. Holds the current selection and shows\n   *                       a skeleton on first boot. Never treated as \"no zoos\".\n   *   []               — this user genuinely has zero zoos. Renders a\n   *                       locked-out empty state, with no fallback to\n   *                       config.tenantId.\n   *\n   * This distinction matters: a host whose fetch fails must pass null/undefined,\n   * never []. Passing [] tells the SDK the user has no memberships at all.\n   */\n  zoos?: Array<{\n    /** Coerced to string internally. */\n    id: string | number;\n    name: string;\n    avatarUrl?: string;\n    /** Secondary line in the dropdown, e.g. city or region. */\n    description?: string;\n    /** Visible but greyed and unselectable. Treated as removal if active. */\n    disabled?: boolean;\n  }> | null;\n\n  /** Preferred zoo when nothing is remembered, and the fallback on eviction. */\n  defaultZooId?: string;\n\n  /** Persist the last pick per user in localStorage. Default: true */\n  remember?: boolean;\n\n  /** Render the built-in picker. Default: true. Set false and use useZooSelection(). */\n  ui?: boolean;\n\n  /** Noun shown in the UI: \"Zoo\" | \"Organization\" | \"Site\". Default: \"Zoo\" */\n  label?: string;\n\n  /**\n   * What to do when access to the ACTIVE zoo is lost and more than one zoo is\n   * left.\n   *   'ask'  (default) — stop and let the user choose. Never picks for them.\n   *   'auto' — pick a fallback silently and show a dismissible banner. For\n   *            kiosk / embedded hosts where a blocking modal isn't viable.\n   * With exactly one zoo left, both behave the same: auto-select and warn.\n   */\n  evictionBehaviour?: 'ask' | 'auto';\n\n  onZooChange?: (zoo: ZooOption, previous: ZooOption | null) => void;\n  /**\n   * `fallback` is the auto-selected zoo when there was no choice to make, and\n   * null when there was. Read `status` to tell the two null cases apart:\n   * 'awaiting-choice' (user is picking) vs 'locked-out' (nothing left).\n   */\n  onZooRemoved?: (removed: ZooOption, fallback: ZooOption | null) => void;\n\n  /** Confirm before switching. Default: only when an upload is in flight. */\n  confirmOnSwitch?: boolean;\n}\n```\n\n### Example\n\n```tsx\n<AntzChat\n  config={{ apiUrl, authProvider, userId: '58' }}   // note: no tenantId needed\n  features={{\n    zooSelector: {\n      enabled: true,\n      zoos: myZoos,               // null while your fetch is in flight, [] if the user has none\n      defaultZooId: '11',\n    },\n  }}\n/>\n```\n\nSwitching zoo is a full identity switch, not a filter over one inbox — different chat user id,\ndifferent conversations, different unread counts. The SDK handles the socket reconnect, cache\nresets, and (best-effort) device-token cleanup for the zoo the user is leaving.\n\n### Headless hook\n\nFor hosts that set `ui: false` and render their own picker:\n\n```ts\nconst {\n  zoos,            // NormalisedZoo[]\n  selectedZoo,     // NormalisedZoo | null\n  selectZoo,       // (id: string) => void\n  isSwitching,     // boolean\n  status,          // 'loading' | 'ready' | 'awaiting-choice' | 'locked-out'\n  evictedZoo,      // NormalisedZoo | null — the zoo access was lost to\n  suggestedZooId,  // string | null — pre-highlight in your own chooser, never auto-applied\n  dismissEviction, // () => void — clears the eviction warning banner only\n} = useZooSelection();\n```\n\n`'awaiting-choice'` means access to the active zoo was lost and the user has more than one option\nleft. Call `selectZoo()` with their answer; until then the SDK holds no tenant and makes no\nrequests. Use `status` to hide your own chat launcher while `'locked-out'` — there is nothing\nuseful for it to open.\n\n---\n\n## Authentication\n\nThe SDK supports three authentication modes. Use exactly one at a time.\n\n### Mode 1: authToken (static JWT)\n\nPass a token you have already fetched — from your SSO provider, a login API call, a cookie, etc. The SDK injects it into all REST requests and the WebSocket handshake.\n\n```tsx\n// Fetch your token from your auth server, then pass it in\nconst token = await fetchMyAuthToken();\n\n<AntzChat\n  config={{\n    apiUrl: 'https://api.yourapp.com/api/v1',\n    authToken: token,\n  }}\n  features={{ builtInAuth: false }}\n/>\n```\n\nThe token is stored in `localStorage` via the built-in `persistStorage` adapter so it survives page reloads. If you need finer control over persistence, override `persistStorage` in the config.\n\n### Mode 2: authProvider (dynamic token getter)\n\nPass an async function that returns a fresh token. The SDK calls this before REST requests and on WebSocket reconnect, making it ideal for short-lived tokens or OAuth flows with refresh logic.\n\n```tsx\n<AntzChat\n  config={{\n    apiUrl: 'https://api.yourapp.com/api/v1',\n    authProvider: async () => {\n      // Your token refresh logic here\n      const { accessToken } = await refreshMyToken();\n      return accessToken;\n    },\n  }}\n  features={{ builtInAuth: false }}\n/>\n```\n\n### Mode 3: builtInAuth (built-in login/register UI)\n\nLeave `authToken` and `authProvider` unset and enable `builtInAuth` (the default). The SDK renders a login form inside the chat panel. Users log in with email/password or register a new account.\n\n```tsx\n<AntzChat\n  config={{\n    apiUrl: 'https://api.yourapp.com/api/v1',\n    tenantId: 'your-tenant-id',   // required when using built-in auth on multi-tenant servers\n  }}\n  features={{\n    builtInAuth: true,   // this is the default — shown here for clarity\n  }}\n/>\n```\n\nAfter a successful login the SDK stores the tokens in `localStorage` and immediately shows the chat UI. A \"Register\" link lets new users sign up within the same panel.\n\n### Logging out — `onLogout()`\n\nCall `onLogout()` from your own logout flow. It is the single supported teardown entry point for all three auth modes — you do not need to clear any SDK storage key yourself.\n\n```tsx\nimport { onLogout } from '@antzsoft/chat-web-sdk';\n\nasync function handleLogout() {\n  // Call BEFORE clearing your own session / navigating away — the chat token\n  // must still be valid for the server-side steps below.\n  await onLogout();\n\n  yourAuth.clearSession();\n  router.push('/login');\n}\n```\n\nWhat it does, in order:\n\n1. Revokes the chat session's refresh token server-side (`POST /auth/logout`). Built-in auth only — in `authToken` / `authProvider` mode the SDK holds no refresh token and your app owns the session.\n2. Unsubscribes this browser's `PushSubscription` and unregisters the matching device token server-side, so the signed-out user stops receiving push on this device.\n3. Disconnects the socket, which also drops the transit/E2E session.\n4. Cancels in-flight queries, then clears the entire react-query cache.\n5. Resets every in-memory store — chat state, unsettled send payloads, message-cache LRU, file preview, in-app toasts, OS notifications, notification/push settings, the zoo selector, and the provider's identity-bootstrap state.\n6. Removes every per-identity `localStorage` key the SDK writes.\n7. Clears the persisted auth store.\n\nEvery step is best-effort — failures are logged, never thrown, so a host that never enabled push (or the zoo selector) still gets a clean teardown from one call. The network steps are time-boxed (3s each, 5s for service-worker readiness), so an unreachable server cannot wedge your logout.\n\nTwo keys deliberately **survive** logout: `antz-chat:floating-size:*` (a per-device panel-size preference, not user data) and `antz-chat:device-id` (identifies the browser, not the user — it must stay stable so the next person signing in on this device keeps a working push registration; what logout changes is *which user that id is registered to* on the server).\n\n```typescript\ninterface OnLogoutOptions {\n  /** This device's push id, if you manage one explicitly (same value you pass\n   *  as `PushNotificationConfig.deviceId` / `NotificationSettingsConfig.deviceId`).\n   *  Omit to use the SDK's own auto-generated id. */\n  deviceId?: string;\n  /** How to reach the service worker holding the `PushSubscription`, for apps\n   *  that register their own. Defaults to `navigator.serviceWorker.ready`. */\n  getServiceWorkerRegistration?: () => Promise<ServiceWorkerRegistration>;\n  /** Skip step 1 when your backend already revokes the chat session itself. */\n  skipServerLogout?: boolean;\n}\n```\n\n---\n\n## Push Notifications\n\nThe SDK never requests push permission on its own — that is always the parent app's responsibility. You supply a `tokenProvider` function that the SDK calls automatically after the user authenticates, or use the `useDeviceToken` hook for manual control from a settings screen.\n\nThe server stores one token document per physical device in `chat_device_tokens`. Every call to `register()` is an **upsert** keyed on `deviceId` — re-registering the same device updates the existing record, never creates a duplicate.\n\n### The `deviceId` rule\n\n`deviceId` must be a **stable UUID stored in `localStorage`** — generated once on first visit, never regenerated. Losing it causes orphan token records in the server DB; the user may receive duplicate notifications until the stale token expires.\n\n```typescript\n// Generate once, reuse forever\nfunction getStableDeviceId(): string {\n  let id = localStorage.getItem('chat-device-id');\n  if (!id) { id = crypto.randomUUID(); localStorage.setItem('chat-device-id', id); }\n  return id;\n}\n```\n\n### When to register and remove\n\n- **On app init after login** — if a push subscription already exists, re-register it. This refreshes `lastUsedAt` and catches any silent endpoint rotation the browser may have done. The SDK handles this automatically when you pass `tokenProvider`.\n- **When the user enables notifications** — request permission, subscribe, register. Only call `pushManager.subscribe()` at this point (not on every page load — that would prompt the user repeatedly).\n- **On logout** — call [`onLogout()`](#logging-out--onlogout). It does both halves for you (`sub.unsubscribe()` + `remove(deviceId)`) as part of the full teardown; there is no need to unregister the device separately.\n- **On \"Disable notifications\"** — call `remove(deviceId)`. This deactivates the token on the server immediately. Also call `sub.unsubscribe()` to tell the browser to drop the subscription. (`useNotificationSettings().setPushEnabled(false)` already does both.)\n\n```typescript\ninterface PushNotificationConfig {\n  /**\n   * Stable UUID for this device. Store in localStorage, never regenerate.\n   * Used as the upsert key — omitting it causes a new record on every page load.\n   */\n  deviceId?: string;\n\n  /**\n   * Called once after login. Return the push payload, or null if permission\n   * is not granted. The SDK registers it with the server automatically.\n   * On subsequent page loads with an existing subscription, return the\n   * existing subscription rather than calling requestPermission() again.\n   */\n  tokenProvider?: () => Promise<RegisterDeviceTokenPayload | null>;\n\n  /** Called after successful registration. Use to persist the deviceId. */\n  onRegistered?: (deviceId: string) => void;\n\n  /** Called if registration fails. Defaults to console.warn. */\n  onError?: (error: Error) => void;\n}\n```\n\n### Web Push (VAPID) — auto-registration via `tokenProvider`\n\n```tsx\nconst VAPID_PUBLIC_KEY = 'your-vapid-public-key';\n\nfunction base64url(buffer: ArrayBuffer | null): string {\n  return buffer ? btoa(String.fromCharCode(...new Uint8Array(buffer))) : '';\n}\n\n<AntzChat\n  config={config}\n  features={{\n    pushNotifications: {\n      deviceId: localStorage.getItem('chat-device-id') ?? undefined,\n\n      tokenProvider: async () => {\n        if (!('serviceWorker' in navigator)) return null;\n\n        // If permission already granted, re-register the existing subscription\n        // (upsert — no duplicate created). Don't re-prompt the user.\n        if (Notification.permission === 'granted') {\n          const reg = await navigator.serviceWorker.ready;\n          const existing = await reg.pushManager.getSubscription();\n          if (existing) {\n            return {\n              deviceId: getStableDeviceId(),\n              platform: 'web', provider: 'web-push',\n              endpoint: existing.endpoint,\n              p256dh: base64url(existing.getKey('p256dh')),\n              auth: base64url(existing.getKey('auth')),\n            };\n          }\n        }\n\n        // No existing subscription — request permission and subscribe\n        const permission = await Notification.requestPermission();\n        if (permission !== 'granted') return null;\n\n        const reg = await navigator.serviceWorker.ready;\n        const sub = await reg.pushManager.subscribe({\n          userVisibleOnly: true,\n          applicationServerKey: VAPID_PUBLIC_KEY,\n        });\n\n        return {\n          deviceId: getStableDeviceId(),\n          platform: 'web', provider: 'web-push',\n          endpoint: sub.endpoint,\n          p256dh: base64url(sub.getKey('p256dh')),\n          auth: base64url(sub.getKey('auth')),\n        };\n      },\n\n      onRegistered: (deviceId) => {\n        localStorage.setItem('chat-device-id', deviceId);\n      },\n\n      onError: (err) => {\n        console.warn('Push registration failed:', err.message);\n      },\n    },\n  }}\n/>\n```\n\n### Manual registration with `useDeviceToken`\n\nFor full control (e.g. a settings screen where the user explicitly opts in):\n\n```tsx\nimport { useDeviceToken } from '@antzsoft/chat-web-sdk';\n\nfunction NotificationSettings() {\n  const { register, remove } = useDeviceToken();\n\n  async function enablePush() {\n    const permission = await Notification.requestPermission();\n    if (permission !== 'granted') return;\n\n    const reg = await navigator.serviceWorker.ready;\n    const sub = await reg.pushManager.subscribe({\n      userVisibleOnly: true,\n      applicationServerKey: VAPID_PUBLIC_KEY,\n    });\n\n    await register({\n      deviceId: getStableDeviceId(),\n      platform: 'web',\n      provider: 'web-push',\n      endpoint: sub.endpoint,\n      p256dh: base64url(sub.getKey('p256dh')),\n      auth: base64url(sub.getKey('auth')),\n    });\n  }\n\n  async function disablePush() {\n    const reg = await navigator.serviceWorker.ready;\n    const sub = await reg.pushManager.getSubscription();\n    if (sub) await sub.unsubscribe(); // tells browser to drop the subscription\n    await remove(getStableDeviceId()); // tells server to stop pushing\n  }\n\n  return (\n    <div>\n      <button onClick={enablePush}>Enable notifications</button>\n      <button onClick={disablePush}>Disable notifications</button>\n    </div>\n  );\n}\n```\n\n---\n\n## Notification Preferences\n\nUser notification preferences are stored server-side in `chat_user_prefs`. A record with all defaults is created automatically when a push token is first registered — so this API is always available after push setup. Call it via `usersApi` from `@antzsoft/chat-core`.\n\nAll fields are optional — only send what changed. Future preference fields are added to the same collection and same API; no new endpoints.\n\n```tsx\nimport { usersApi } from '@antzsoft/chat-core';\nimport type { UserPreferences } from '@antzsoft/chat-core';\n\n// Read current preferences\nconst prefs = await usersApi.getPreferences();\n\n// Partial updates — only send changed fields\nawait usersApi.updatePreferences({ notifyOnReaction: false });\nawait usersApi.updatePreferences({ messagePreview: false }); // privacy mode\nawait usersApi.updatePreferences({ notificationsEnabled: false }); // master off\nawait usersApi.updatePreferences({\n  quietHours: { enabled: true, start: '23:00', end: '07:00', timezone: 'Europe/London' },\n});\n```\n\n### Preferences reference\n\n| Field | Default | Description |\n|---|---|---|\n| `notificationsEnabled` | `true` | Master switch — `false` disables all push |\n| `soundEnabled` | `true` | Play sound with notifications |\n| `messagePreview` | `true` | Show message text in body. `false` = show \"New message\" only |\n| `notifyOnMention` | `true` | Notify when @mentioned in a group |\n| `notifyOnReaction` | `true` | Notify when someone reacts to your message |\n| `notifyOnGroupInvite` | `true` | Notify when added to a group |\n| `quietHours.enabled` | `false` | Enable quiet hours window |\n| `quietHours.start` | `\"22:00\"` | Start of quiet window (HH:MM) |\n| `quietHours.end` | `\"08:00\"` | End of quiet window (HH:MM) |\n| `quietHours.timezone` | `\"UTC\"` | IANA timezone for the quiet window |\n\n### Settings UI example\n\n```tsx\nimport { useState, useEffect } from 'react';\nimport { usersApi } from '@antzsoft/chat-core';\nimport type { UserPreferences } from '@antzsoft/chat-core';\n\nfunction NotificationSettings() {\n  const [prefs, setPrefs] = useState<UserPreferences | null>(null);\n\n  useEffect(() => {\n    usersApi.getPreferences().then(setPrefs);\n  }, []);\n\n  async function toggle(field: keyof UserPreferences, value: boolean) {\n    await usersApi.updatePreferences({ [field]: value });\n    setPrefs(prev => ({ ...prev, [field]: value }));\n  }\n\n  if (!prefs) return null;\n\n  return (\n    <div>\n      <label>\n        <input type=\"checkbox\" checked={prefs.notificationsEnabled ?? true}\n          onChange={e => toggle('notificationsEnabled', e.target.checked)} />\n        Enable notifications\n      </label>\n      <label>\n        <input type=\"checkbox\" checked={prefs.messagePreview ?? true}\n          onChange={e => toggle('messagePreview', e.target.checked)} />\n        Show message preview\n      </label>\n      <label>\n        <input type=\"checkbox\" checked={prefs.notifyOnMention ?? true}\n          onChange={e => toggle('notifyOnMention', e.target.checked)} />\n        Mentions\n      </label>\n      <label>\n        <input type=\"checkbox\" checked={prefs.notifyOnReaction ?? true}\n          onChange={e => toggle('notifyOnReaction', e.target.checked)} />\n        Reactions\n      </label>\n      <label>\n        <input type=\"checkbox\" checked={prefs.notifyOnGroupInvite ?? true}\n          onChange={e => toggle('notifyOnGroupInvite', e.target.checked)} />\n        Group invites\n      </label>\n    </div>\n  );\n}\n```\n\n---\n\n## Notification Settings UI (built-in)\n\nThe SDK ships a ready-made settings surface so you don't have to build the screen\nabove. It lives in the **conversation-list header ⋮ menu → \"🔔 Notifications\"**\n(shown in every layout mode's `full` view) and lets the user toggle:\n\n- **In-app notifications** — master switch + toast / sound / desktop / tab-badge\n  sub-toggles. Stored per-browser in `localStorage`\n  (`antz-chat:notification-settings`); overlays your `features.inAppNotifications`\n  config.\n- **Push notifications** — per-device toggle: requests OS permission, subscribes\n  via VAPID, registers with `devicesApi`, and ensures the account master\n  `notificationsEnabled` is on. Turning it off tears down this device's\n  subscription only, leaving other devices untouched. Requires\n  `features.notificationSettings.vapidPublicKey` and a host service worker with a\n  `push` handler.\n- **Shared preferences** — message preview, per-kind toggles, quiet hours\n  (`usersApi` `UserPreferences`, synced across all devices).\n\n```tsx\n<AntzChat\n  config={{ /* … */ }}\n  features={{\n    inAppNotifications: { enabled: true },\n    notificationSettings: {\n      ui: true,                              // default — set false to hide the built-in panel\n      vapidPublicKey: process.env.NEXT_PUBLIC_VAPID_PUBLIC_KEY,\n      // getServiceWorkerRegistration: () => navigator.serviceWorker.ready,  // default\n    },\n  }}\n/>\n```\n\n### Build your own UI — `useNotificationSettings()`\n\nSet `notificationSettings.ui = false` and drive everything from the hook (works\nin any layout / view mode, including `single-conversation`):\n\n```tsx\nimport { useNotificationSettings } from '@antzsoft/chat-web-sdk';\n\nfunction MyNotificationSettings() {\n  const {\n    inApp, setInApp, requestBrowserPermission,\n    serverPrefs, setServerPrefs,\n    push, setPushEnabled,\n  } = useNotificationSettings();\n\n  return (\n    <>\n      <label>\n        <input type=\"checkbox\" checked={inApp.enabled}\n          onChange={e => setInApp({ enabled: e.target.checked })} />\n        In-app notifications\n      </label>\n\n      <label>\n        <input type=\"checkbox\"\n          checked={push.subscribed && (serverPrefs?.notificationsEnabled ?? true)}\n          disabled={push.busy || !push.supported || !push.configured}\n          onChange={e => setPushEnabled(e.target.checked)} />\n        Push notifications {push.error && <span>— {push.error}</span>}\n      </label>\n\n      <label>\n        <input type=\"checkbox\" checked={serverPrefs?.notifyOnMention ?? true}\n          onChange={e => setServerPrefs({ notifyOnMention: e.target.checked })} />\n        Notify on mentions\n      </label>\n    </>\n  );\n}\n```\n\nYou can also render just the built-in panel yourself:\n\n```tsx\nimport { NotificationSettingsPanel } from '@antzsoft/chat-web-sdk';\n\n{open && <NotificationSettingsPanel onClose={() => setOpen(false)} />}\n```\n\n---\n\n## Hooks\n\nAll hooks must be called from within a component that is a descendant of `AntzChatProvider` (or `<AntzChat />`, which mounts the provider internally).\n\n### useAntzChat()\n\nAccess the resolved config, theme, layout, and features from anywhere inside the provider tree. Throws if called outside of `AntzChatProvider`.\n\n```tsx\nimport { useAntzChat } from '@antzsoft/chat-web-sdk';\n\nfunction MyComponent() {\n  const { config, theme, layout, features, resolvedMode } = useAntzChat();\n\n  return (\n    <div>\n      <p>Connected to: {config.apiUrl}</p>\n      <p>Theme: {resolvedMode}</p>\n      <p>Reactions enabled: {String(features.reactions)}</p>\n    </div>\n  );\n}\n```\n\n**Returns:**\n\n| Field | Type | Description |\n|-------|------|-------------|\n| `config` | `ResolvedConfig` | Resolved config with all defaults filled |\n| `theme` | `ThemeConfig` | Raw theme prop as passed |\n| `layout` | `LayoutConfig` | Raw layout prop as passed |\n| `features` | `Required<FeatureConfig>` | Merged feature flags (user overrides + defaults) |\n| `resolvedMode` | `'light' \\| 'dark'` | Actual color mode after resolving `'system'` |\n\n---\n\n### useConversations(filters?)\n\nFetches and manages the conversation list. Initial load is via REST; all subsequent updates arrive through the WebSocket (no polling). Pass an optional `filters` object to narrow the list using server-side filtering — changing any filter triggers a new fetch with correct pagination.\n\n```tsx\nimport { useConversations } from '@antzsoft/chat-web-sdk';\n\nfunction ConversationSidebar() {\n  // No filters — full list\n  const { conversations, isLoading } = useConversations();\n\n  // With server-side filters — each unique filter set is a separate query cache entry\n  const { conversations: groups }  = useConversations({ type: 'group' });\n  const { conversations: pinned }  = useConversations({ isPinned: true });\n  const { conversations: unread }  = useConversations({ hasUnread: true });\n  const { conversations: results } = useConversations({ search: 'design' });\n}\n\nfunction ConversationSidebar() {\n  const {\n    conversations,\n    isLoading,\n    error,\n    refetch,\n    createDirect,\n    createGroup,\n    mute,\n    unmute,\n    pin,\n    unpin,\n    markUnread,\n    markRead,\n    leaveGroup,\n    leaveAndDeleteGroup,\n    deleteGroup,\n  } = useConversations({ type: 'group', hasUnread: true });\n\n  async function startChat(userId: string) {\n    await createDirect.mutateAsync(userId);\n  }\n\n  async function newGroup() {\n    await createGroup.mutateAsync({\n      name: 'Project Alpha',\n      memberIds: ['user-1', 'user-2'],\n    });\n  }\n\n  return (\n    <ul>\n      {conversations.map((conv) => (\n        <li key={conv.id}>\n          {conv.name}\n          <button onClick={() => pin.mutate(conv.id)}>Pin</button>\n          <button onClick={() => mute.mutate({ id: conv.id })}>Mute</button>\n          <button onClick={() => leaveGroup.mutate(conv.id)}>Exit Group</button>\n          <button onClick={() => leaveAndDeleteGroup.mutate(conv.id)}>Exit &amp; Delete</button>\n        </li>\n      ))}\n    </ul>\n  );\n}\n```\n\n**Returns:**\n\n| Field | Type | Description |\n|-------|------|-------------|\n| `conversations` | `Conversation[]` | Sorted list (pinned first, then by last message time) |\n| `isLoading` | `boolean` | True during the initial fetch |\n| `error` | `Error \\| null` | Fetch error |\n| `refetch` | `() => void` | Manually re-fetch the conversation list |\n| `createDirect` | `UseMutationResult` | Create a direct message conversation with a userId |\n| `createGroup` | `UseMutationResult` | Create a group conversation |\n| `mute` | `UseMutationResult` | Mute a conversation (optionally until a date) |\n| `unmute` | `UseMutationResult` | Unmute a conversation |\n| `pin` | `UseMutationResult` | Pin a conversation to the top |\n| `unpin` | `UseMutationResult` | Unpin a conversation |\n| `markUnread` | `UseMutationResult<void, Error, string>` | Flag a conversation unread, independent of `unreadCount` |\n| `markRead` | `UseMutationResult<void, Error, string>` | Clear the manual unread flag |\n| `leaveGroup` | `UseMutationResult<void, Error, string>` | Exit a group — stays in list as read-only. Auto-promotes if last admin. |\n| `leaveAndDeleteGroup` | `UseMutationResult<void, Error, string>` | Exit a group and remove it from the list in one call (\"Exit and Delete\"). |\n| `deleteGroup` | `UseMutationResult<void, Error, string>` | Hide a conversation from the list. For DMs this is \"Delete Chat\"; for groups already exited this is \"Delete Group\". Any participant can call this — no admin role required. |\n\n**Accepted filters (`ConversationListFilters`):**\n\n| Filter | Type | Description |\n|--------|------|-------------|\n| `type` | `'direct' \\| 'group'` | Show only DMs or only group conversations |\n| `isPinned` | `boolean` | `true` = only pinned, `false` = only unpinned |\n| `isMuted` | `boolean` | `true` = only muted, `false` = only unmuted |\n| `hasUnread` | `boolean` | Only conversations with at least 1 unread message |\n| `search` | `string` | Server-side text search on group name / description |\n| `role` | `'admin' \\| 'member'` | Filter by the current user's role in conversations |\n| `hasAttachments` | `boolean` | Filter by whether the last message has attachments |\n| `attachmentType` | `'image' \\| 'video' \\| 'document' \\| 'audio'` | Filter by last message attachment type |\n| `notificationsEnabled` | `boolean` | Filter by notification setting |\n\nAll filters are applied server-side. Omit `page` and `limit` to receive all matching conversations in one response. Pass both to opt into paginated results.\n\n### Passing filters to `<AntzChat />`\n\nPass `conversationListFilters` directly on the component. The conversation list refetches from the server whenever the filter object changes — pagination is always correct.\n\n```tsx\n// Show only group conversations\n<AntzChat\n  config={config}\n  conversationListFilters={{ type: 'group' }}\n/>\n\n// Show only unread conversations\n<AntzChat\n  config={config}\n  conversationListFilters={{ hasUnread: true }}\n/>\n\n// Combine filters\n<AntzChat\n  config={config}\n  conversationListFilters={{ type: 'group', isPinned: true }}\n/>\n```\n\n---\n\n### Unread counts\n\nEach `Conversation` object in `useConversations()` already has `unreadCount` populated from the initial REST fetch. The socket then keeps it live — you don't need to poll.\n\n#### Chat icon badge — the complete pattern\n\n`useConversations()` is already subscribed to every `conversation_updated` and `unread_count_changed` socket event internally. Summing `unreadCount` from the hook is all you need — no extra socket listener, no polling:\n\n```tsx\nimport { useConversations } from '@antzsoft/chat-web-sdk';\n\nfunction ChatIconButton({ onClick }: { onClick: () => void }) {\n  const { conversations } = useConversations();\n\n  // Recalculates automatically every time any conversation's unreadCount changes\n  const totalUnread = conversations.reduce(\n    (sum, c) => sum + (c.unreadCount ?? 0), 0\n  );\n\n  return (\n    <button onClick={onClick} style={{ position: 'relative' }}>\n      💬\n      {totalUnread > 0 && (\n        <span style={{\n          position: 'absolute',\n          top: -6, right: -6,\n          backgroundColor: '#e53935',\n          color: '#fff',\n          borderRadius: '50%',\n          minWidth: 18, height: 18,\n          fontSize: 11, fontWeight: 700,\n          display: 'flex', alignItems: 'center', justifyContent: 'center',\n          padding: '0 4px',\n        }}>\n          {totalUnread > 99 ? '99+' : totalUnread}\n        </span>\n      )}\n    </button>\n  );\n}\n```\n\nThe update chain is fully automatic:\n```\nNew message sent\n  → server emits conversation_updated with DB-accurate unreadCount\n  → SocketProvider updates useConversations() cache\n  → totalUnread recalculates\n  → badge re-renders\n```\n\nReading a conversation clears it the same way via `unread_count_changed`, including on other tabs/devices of the same user.\n\n#### When to call the REST APIs\n\nThe socket may have been down (tab was backgrounded, network drop, etc.). Refresh from the server on:\n\n```tsx\nimport { conversationsApi } from '@antzsoft/chat-core';\nimport type { UnreadSummary } from '@antzsoft/chat-core';\n\n// On app focus / visibility change — catch up after tab was hidden\nuseEffect(() => {\n  function onVisible() {\n    if (document.visibilityState === 'visible') {\n      // Option A — refetch the full conversation list (also updates unreadCount)\n      refetch();\n\n      // Option B — lightweight, just the counts (no full list fetch)\n      conversationsApi.getUnreadSummary().then((summary: UnreadSummary) => {\n        console.log('Total unread:', summary.totalUnread);\n        // summary.byConversation = [{ conversationId, unreadCount }, ...]\n        // Update your own state / badge here\n      });\n    }\n  }\n  document.addEventListener('visibilitychange', onVisible);\n  return () => document.removeEventListener('visibilitychange', onVisible);\n}, [refetch]);\n\n// Refresh a single conversation after a push notification opens it\nconst { unreadCount } = await conversationsApi.getUnreadCount(conversationId);\n```\n\n#### How the socket events work\n\nThe server emits to the user's **private room** — all browser tabs and devices of the same user receive these simultaneously:\n\n```tsx\n// conversation_updated — fires when a new message arrives\n// unreadCount is server-calculated (always accurate, not optimistic)\nsocket?.on('conversation_updated', ({ conversationId, unreadCount, lastMessage }) => {\n  // The web SDK's SocketProvider handles this automatically —\n  // useConversations() updates in real-time with no extra code needed\n});\n\n// unread_count_changed — fires when the user reads a conversation\n// Also fires on your OTHER devices so they clear the badge too\nsocket?.on('unread_count_changed', ({ conversationId, unreadCount }) => {\n  // unreadCount is 0 here — the SDK handles this automatically as well\n});\n```\n\nBoth events are handled internally by the SDK's `SocketProvider`. You only need to listen manually if you're building a **custom badge** (e.g. browser tab title or favicon).\n\n#### `conversation_deleted`\n\nEmitted **only to the acting user's own sockets** when they self-delete a conversation (`delete()`), exit+delete a group (`leave(id, true)`), or hide an already-exited group (`delete()`). Other participants never receive this event. The web SDK's `SocketProvider` handles it automatically — the conversation is removed from the `useConversations()` cache across all tabs. Only listen manually if you need a side effect such as navigation:\n\n```tsx\nimport { tryGetSocket } from '@antzsoft/chat-core';\n\nuseEffect(() => {\n  const socket = tryGetSocket();\n  if (!socket) return;\n\n  const onDeleted = ({ conversationId }: { conversationId: string }) => {\n    if (activeConversationId === conversationId) {\n      router.push('/conversations');\n    }\n  };\n\n  socket.on('conversation_deleted', onDeleted);\n  return () => { socket.off('conversation_deleted', onDeleted); };\n}, [activeConversationId]);\n```\n\n```tsx\n// Custom tab title badge\nimport { tryGetSocket } from '@antzsoft/chat-core';\n\nuseEffect(() => {\n  const socket = tryGetSocket();\n  if (!socket) return;\n\n  const update = () => {\n    const total = conversations.reduce((s, c) => s + (c.unreadCount ?? 0), 0);\n    document.title = total > 0 ? `(${total}) Antz Chat` : 'Antz Chat';\n  };\n\n  socket.on('conversation_updated', update);\n  socket.on('unread_count_changed', update);\n  return () => { socket.off('conversation_updated', update); socket.off('unread_count_changed', update); };\n}, [conversations]);\n```\n\n---\n\n### useMessages(conversationId)\n\nInfinite-scroll message list for a conversation. Messages are loaded oldest-to-newest in pages of 40. After the initial load, new messages arrive via the WebSocket.\n\n```tsx\nimport { useMessages } from '@antzsoft/chat-web-sdk';\n\nfunction MessageFeed({ conversationId }: { conversationId: string }) {\n  const {\n    messages,\n    isLoading,\n    isFetchingMore,\n    hasMore,\n    fetchMore,\n    refresh,\n    error,\n  } = useMessages(conversationId);\n\n  return (\n    <div onScroll={(e) => {\n      const el = e.currentTarget;\n      // Load older messages when scrolled near the top\n      if (el.scrollTop < 100 && hasMore && !isFetchingMore) {\n        fetchMore();\n      }\n    }}>\n      {messages.map((msg) => (\n        <div key={msg.id}>{msg.content.text}</div>\n      ))}\n    </div>\n  );\n}\n```\n\n**Returns:**\n\n| Field | Type | Description |\n|-------|------|-------------|\n| `messages` | `Message[]` | Flat array of all loaded messages, newest first |\n| `isLoading` | `boolean` | True during the initial page fetch |\n| `isFetchingMore` | `boolean` | True while loading an older page |\n| `hasMore` | `boolean` | True if there are older messages to load |\n| `fetchMore` | `() => void` | Load the next (older) page |\n| `refresh` | `() => void` | Invalidate and re-fetch all pages |\n| `error` | `Error \\| null` | Fetch error |\n\n---\n\n### useChat(conversationId)\n\nThe primary hook for all message-level interactions: send, edit, delete, typing, mark read, and reply/edit state.\n\n```tsx\nimport { useChat } from '@antzsoft/chat-web-sdk';\n\nfunction ChatInput({ conversationId }: { conversationId: string }) {\n  const {\n    sendMessage,\n    editMessage,\n    deleteMessage,\n    startTyping,\n    stopTyping,\n    markRead,\n    replyingTo,\n    setReplyingTo,\n    editingMessage,\n    setEditingMessage,\n  } = useChat(conversationId);\n\n  const [text, setText] = useState('');\n  const [files, setFiles] = useState<File[]>([]);\n\n  return (\n    <form onSubmit={async (e) => {\n      e.preventDefault();\n      if (editingMessage) {\n        await editMessage(editingMessage.id, text);\n      } else {\n        await sendMessage(text, files);\n      }\n      setText('');\n      setFiles([]);\n    }}>\n      {replyingTo && (\n        <div>Replying to: {replyingTo.content?.text}\n          <button type=\"button\" onClick={() => setReplyingTo(null)}>Cancel</button>\n        </div>\n      )}\n      <input\n        value={text}\n        onChange={(e) => { setText(e.target.value); startTyping(); }}\n        onBlur={stopTyping}\n      />\n      <input type=\"file\" multiple onChange={(e) => setFiles(Array.from(e.target.files ?? []))} />\n      <button type=\"submit\">Send</button>\n    </form>\n  );\n}\n```\n\n`sendMessage` optimistically inserts the message into the cache before the server confirms, so the UI feels instant. If the socket emit fails, the message is marked with `deliveryStatus: 'failed'`. Call `retrySendMessage(messageId)` on a failed message to resend it safely — it reuses the exact original `tempId` and already-uploaded attachment `fileId`s (no re-upload), so the server can recognize a retry and avoid creating a duplicate if the original send actually landed before the failure was reported. The built-in `MessageItem` already wires this to a tappable \"Retry\" on the failed indicator and a \"Retry\" menu entry — no extra code needed with the prebuilt UI.\n\n**Returns:**\n\n| Field | Type | Description |\n|-------|------|-------------|\n| `sendMessage` | `(text: string, files?: File[]) => Promise<void>` | Send text and/or file attachments |\n| `retrySendMessage` | `(failedMessageId: string) => Promise<void>` | Resend a message whose `deliveryStatus` is `'failed'`, reusing its original `tempId` for retry-safety (v1.4.4+). No-op if this hook instance never sent that message (e.g. a page reload). |\n| `editMessage` | `(messageId: string, newText: string) => Promise<void>` | Edit a sent message |\n| `deleteMessage` | `(messageId: string) => Promise<void>` | Delete a message for everyone. Own messages are subject to the conversation's delete window (default 30 min); group admins can delete any message with no time restriction. |\n| `startTyping` | `() => void` | Broadcast typing started. Safe to call on every keystroke — core leading-throttles it to one emit per 3s per conversation (v1.4.7+). Don't add your own throttle on top. |\n| `stopTyping` | `() => void` | Broadcast typing stopped. Never throttled — always reaches the server so peers' indicators clear promptly. |\n| `markRead` | `(messageId?: string) => void` | Mark conversation (or specific message) as read |\n| `forwardMessage` | `(messageId: string, targetConversationIds: string[], attachmentIds?: string[], tempId?: string) => Promise<ForwardResult[]>` | Forward a message into up to 5 other conversations (server reduces this to 1 if the message has already been forwarded many times — see below). Pass `attachmentIds` to forward only a subset of the source message's attachments; omit for the whole message. Pass `tempId` when retrying a previously-failed forward — reuse the SAME value, never a new one — so the server recognizes the retry and skips re-creating messages for targets that already succeeded; the built-in `ForwardPicker` already does this. No limit on how many times a message can be forwarded. REST-driven (not optimistic like `sendMessage`) since the targets aren't the conversation currently open — each target's cache is warmed once the server confirms. |\n| `replyingTo` | `Message \\| null` | The message currently being replied to |\n| `setReplyingTo` | `(msg: Message \\| null) => void` | Set or clear the reply target |\n| `editingMessage` | `Message \\| null` | The message currently being edited |\n| `setEditingMessage` | `(msg: Message \\| null) => void` | Set or clear the edit target |\n| `forwardingMessage` | `Message \\| null` | The message currently staged in the forward picker |\n| `setForwardingMessage` | `(msg: Message \\| null) => void` | Set or clear the forward target — setting it opens the built-in `ForwardPicker` modal in `<MessageList>` |\n\n**Forwarding.** The built-in `MessageItem` component already exposes a \"Forward\" action in its context menu, which opens a conversation picker (`ForwardPicker`) capped at 5 targets to match the server's normal-case limit. If the message being forwarded is highly forwarded already (`forwardDepth >= 5`), the server reduces this to 1 target and returns any extra selections as regular `{ success: false }` entries in the result array — the picker doesn't pre-detect this (it isn't known until the request lands), so handle a partial `results` array in your own \"Forwarded to N/M\" UI if you don't use the built-in picker as-is. There is no limit on the number of times a message can be forwarded — only fan-out width per call is ever reduced. Forwarded messages render a \"Forwarded\" (or \"Forwarded many times\" past 4 hops) label instead of a reply-style quote, since the message's own content already holds what was forwarded. See [`@antzsoft/chat-core`'s \"Forward Message\" docs](../antz-chat-core/README.md#forward-message-v142) for the underlying data shape (`Message.forwardedFrom`, one-hop-back lineage, attachment dedup, full limits table).\n\n---\n\n### useSocket()\n\nReal-time WebSocket connection status.\n\n```tsx\nimport { useSocket } from '@antzsoft/chat-web-sdk';\n\nfunction ConnectionIndicator() {\n  const { status, isConnected, isReconnecting, isError } = useSocket();\n\n  if (isConnected) return <span style={{ color: 'green' }}>Connected</span>;\n  if (isReconnecting) return <span style={{ color: 'orange' }}>Reconnecting…</span>;\n  if (isError) return <span style={{ color: 'red' }}>Connection error</span>;\n  return <span style={{ color: 'grey' }}>Connecting…</span>;\n}\n```\n\n**Returns:**\n\n| Field | Type | Description |\n|-------|------|-------------|\n| `status` | `SocketStatus` | Raw status string: `'connecting' \\| 'connected' \\| 'reconnecting' \\| 'error' \\| 'disconnected'` |\n| `isConnected` | `boolean` | `status === 'connected'` |\n| `isReconnecting` | `boolean` | `status === 'reconnecting'` |\n| `isError` | `boolean` | `status === 'error'` |\n\n---\n\n### useUpload(conversationId?)\n\nLow-level file upload hook with MIME validation, size-limit enforcement, and progress tracking. Prefer using `sendMessage` from `useChat` for message attachments — `useUpload` is for standalone upload flows (e.g. a profile picture uploader).\n\n```tsx\nimport { useUpload } from '@antzsoft/chat-web-sdk';\n\nfunction FileUploader({ conversationId }: { conversationId: string }) {\n  const { upload, validateFiles, progress, isUploading, error } = useUpload(conversationId);\n\n  async function handleFiles(files: File[]) {\n    const { valid, errors } = validateFiles(files);\n    errors.forEach(({ file, reason }) => console.warn(file.name, reason));\n\n    if (valid.length > 0) {\n      const result = await upload(valid);\n      console.log('Uploaded:', result.successful);\n      console.log('Failed:', result.failed);\n    }\n  }\n\n  return (\n    <div>\n      <input\n        type=\"file\"\n        multiple\n        onChange={(e) => handleFiles(Array.from(e.target.files ?? []))}\n      />\n      {isUploading && <progress value={progress} max={100} />}\n      {error && <p style={{ color: 'red' }}>{error}</p>}\n    </div>\n  );\n}\n```\n\n**Returns:**\n\n| Field | Type | Description |\n|-------|------|-------------|\n| `upload` | `(files: File[]) => Promise<BatchUploadResult>` | Validate and upload files. Enforces `maxFilesPerMessage`. |\n| `validateFiles` | `(files: File[]) => { valid: File[]; errors: Array<{ file: File; reason: string }> }` | Validate without uploading (MIME check + size limit) |\n| `progress` | `number` | Aggregate upload progress, 0–100 |\n| `isUploading` | `boolean` | True while a batch upload is in progress |\n| `error` | `string \\| null` | Last upload error message |\n\n---\n\n### useResponsive()\n\nViewport-width-based breakpoints using a `resize` event listener. Useful for conditional rendering in custom components.\n\n```tsx\nimport { useResponsive } from '@antzsoft/chat-web-sdk';\n\nfunction AdaptivePanel() {\n  const { isMobile, isTablet, isDesktop, wid","readmeFilename":"README.md"}