{"mappings":";AAAA;;;;GAIG;AAOH,gDAAgD;AAChD;IACE,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC7B;AAED,mDAAmD;AACnD;IACE,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC;CACzC;AAED,oDAAoD;AACpD;IACE;;;;OAIG;IACH,GAAG,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,+DAA+D;IAC/D,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC1B;AAED,oDAAoD;AACpD;IACE,GAAG,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC7B;AAED,gDAAgD;AAChD;IACE,GAAG,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3B;AAED;;;;;;;;;;;;GAYG;AACH;IACE,GAAG,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3B;AAED;;;;;;;;;;;;GAYG;AACH;IACE,GAAG,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,iEAAiE;IACjE,OAAO,CAAC,EAAE,OAAO,GAAG,IAAI,CAAC;CAC1B;AAED;;;;;;;;;;;;;GAaG;AACH;IACE,GAAG,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,qEAAqE;IACrE,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,uCAAuC;IACvC,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC5B;AAUD;;;;;;;GAOG;AACH,wBACI,SAAS,GACT,WAAW,GACX,WAAW,GACX,QAAQ,GACR,OAAO,CAAC;AAEZ,sDAAsD;AACtD;IACE,IAAI,EAAE,eAAe,CAAC;IACtB,oDAAoD;IACpD,MAAM,EAAE,MAAM,CAAC;IACf,sCAAsC;IACtC,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,uDAAuD;IACvD,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,0EAA0E;IAC1E,WAAW,EAAE,OAAO,CAAC;IACrB,uCAAuC;IACvC,EAAE,EAAE,MAAM,CAAC;CACZ;AAED,sFAAsF;AACtF;IACE,IAAI,EAAE,YAAY,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,4CAA4C;IAC5C,WAAW,EAAE,MAAM,CAAC;IACpB,kDAAkD;IAClD,IAAI,EAAE,OAAO,CAAC;IACd,EAAE,EAAE,MAAM,CAAC;CACZ;AAED,oDAAoD;AACpD;IACE,IAAI,EAAE,eAAe,CAAC;IACtB,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,SAAS,CAAC;IAClB,uCAAuC;IACvC,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,EAAE,EAAE,MAAM,CAAC;CACZ;AAED,+EAA+E;AAC/E;IACE,IAAI,EAAE,iBAAiB,CAAC;IACxB,MAAM,EAAE,MAAM,CAAC;IACf,EAAE,EAAE,MAAM,CAAC;CACZ;AAED,iEAAiE;AACjE,iCACI,yBAAyB,GACzB,mBAAmB,GACnB,sBAAsB,GACtB,2BAA2B,CAAC;AAEhC;;;;;;;;GAQG;AACH,iCAAiC,CAAC,QAAQ,EAAE,kBAAkB,KAAK,IAAI,CAAC;AAExE;;;;;;;;;;;GAWG;AACH;IACE;;;;;OAKG;IACH,GAAG,EAAE,MAAM,CAAC;IACZ,2CAA2C;IAC3C,IAAI,EAAE,MAAM,CAAC;IACb,+CAA+C;IAC/C,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,uEAAuE;IACvE,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;;;;;OAKG;IACH,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;IACjB,0BAA0B;IAC1B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;;;;OAIG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB;;;OAGG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,mBAAmB;IACnB,QAAQ,CAAC,EAAE,QAAQ,EAAE,CAAC;CACvB;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH;IACE;;;;OAIG;IACH,GAAG,EAAE,MAAM,CAAC;IACZ;;;OAGG;IACH,IAAI,EAAE,MAAM,CAAC;IACb;;;OAGG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB;;;OAGG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED;;;;;;;;GAQG;AACH;IACE,2EAA2E;IAC3E,IAAI,EAAE,QAAQ,CAAC;IACf,0EAA0E;IAC1E,WAAW,EAAE,MAAM,CAAC;IACpB;;;;;;OAMG;IACH,SAAS,CAAC,EAAE,aAAa,CAAC;CAC3B;ACrPD;;;;;GAKG;AACH,iCAAiC,GAAG,EAAE,MAAM,GAAG,OAAO,GAAG,IAAI,CAa5D;AAED;;;;;;;;;;;;GAYG;AACH,kCAAkC,EAAE,EAAE,OAAO,GAAG,MAAM,GAAG,IAAI,CAE5D;AAuiBD;;;;;;;;;;;;;GAaG;AACH,sCAAsC,aAAa,GAAG,IAAI,CA4CzD;AAMD;IACE;;;;;;OAMG;IACH,aAAa,CAAC,EAAE,OAAO,CAAC;CACzB;AAED;;;;;;;GAOG;AACH,iCACE,IAAI,CAAC,EAAE,OAAO,EACd,OAAO,GAAE,eAAoB,GAC5B,YAAY,CAuBd;AC9uBD,0CAA0C;AAC1C;IACE;;;;;OAKG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB;;;;;;;OAOG;IACH,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB;;;;;;OAMG;IACH,YAAY,CAAC,EAAE,OAAO,CAAC;CACxB;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,kCAAkC,CAAC,QAAQ,EAAE,YAAY,KAAK,IAAI,CAAC;AAEnE;gBAiBI,YAAY,EAAE,mBAAmB,EACjC,OAAO,GAAE,2BAAgC;IAQ3C;;;OAGG;IACH,KAAK,IAAI,IAAI;IA6Eb,uEAAuE;IACvE,IAAI,IAAI,IAAI;CAiFb;AChQD,6BACI,cAAc,GACd,cAAc,GACd,aAAa,GACb,gBAAgB,GAChB,eAAe,GACf,YAAY,GACZ,WAAW,GACX,OAAO,GACP,eAAe,GACf,OAAO,CAAC;AAEZ;IACE,YAAY,iBAAiB;IAC7B,YAAY,iBAAiB;IAC7B,WAAW,gBAAgB;IAC3B,cAAc,mBAAmB;IACjC,aAAa,kBAAkB;IAC/B,UAAU,eAAe;IACzB,SAAS,cAAc;IACvB,KAAK,UAAU;IACf,aAAa,kBAAkB;IAC/B,KAAK,UAAU;CAChB;AAED,0BAA0B;IACxB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,OAAO,CAAC;CAChB,CAAC;AAEF;;;;;GAKG;AACH;AACE,4DAA4D;AAC1D,eAAe;AACjB,oEAAoE;GAClE,cAAc;AAChB,4CAA4C;GAC1C,SAAS;AACX,4DAA4D;GAC1D,OAAO,CAAC;AAEZ;;;;;GAKG;AACH;AACE,wCAAwC;AACtC,SAAS;AACX,8CAA8C;GAC5C,gBAAgB;AAClB,qCAAqC;GACnC,WAAW;AACb,qDAAqD;GACnD,qBAAqB;AACvB,oEAAoE;GAClE,eAAe;AACjB,gDAAgD;GAC9C,SAAS,CAAC;AAEd;;;;GAIG;AACH,2BACI;IAAE,KAAK,EAAE,eAAe,GAAG,cAAc,GAAG,SAAS,CAAA;CAAE,GACvD;IAAE,KAAK,EAAE,OAAO,CAAC;IAAC,MAAM,EAAE,iBAAiB,CAAC;IAAC,OAAO,CAAC,EAAE,OAAO,CAAA;CAAE,CAAC;AAErE;;;;GAIG;AACH,yBAAyB;IACvB,GAAG,EAAE,YAAY,CAAC;IAClB,GAAG,EAAE,YAAY,CAAC;CACnB,CAAC;ACpFF;;;;GAIG;AAEH,sBAAuB,SAAQ,KAAK;IAClC,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC;gBAExB,OAAO,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS;CAI1D;AAED,mCAAoC,SAAQ,SAAS;gBACvC,OAAO,CAAC,EAAE,MAAM,GAAG,SAAS;CAMzC;AAED,0BAA2B,SAAQ,SAAS;IAC1C,QAAQ,CAAC,KAAK,EAAE,MAAM,CAA2B;gBACrC,OAAO,CAAC,EAAE,MAAM,GAAG,SAAS,EAAE,MAAM,CAAC,EAAE,MAAM;CAM1D;AAED,gCAAiC,SAAQ,SAAS;gBACpC,OAAO,CAAC,EAAE,MAAM,GAAG,SAAS;CAGzC;AAED,wCAAyC,SAAQ,SAAS;gBAC5C,OAAO,CAAC,EAAE,MAAM,GAAG,SAAS;CAGzC;AAED,6BAA8B,SAAQ,SAAS;gBACjC,OAAO,CAAC,EAAE,MAAM,GAAG,SAAS;CAMzC;AAED,mCAAoC,SAAQ,SAAS;gBACvC,OAAO,CAAC,EAAE,MAAM,GAAG,SAAS;CAMzC;AAED,oCAAqC,SAAQ,SAAS;IACpD,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;gBACb,OAAO,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM;CAU/D;AAED,iCAAkC,SAAQ,SAAS;gBACrC,OAAO,CAAC,EAAE,MAAM,GAAG,SAAS;CAKzC;AAED,0BAA0B,KAAK,CAAC,KAAK,GAAG,KAAK,GAAG,SAAS,CAAC,CAAC;AAC3D,8BACI,QAAQ,GACR,aAAa,GACb,wBAAwB,GACxB,WAAW,GACX,aAAa,GACb,SAAS,CAAC;AACd,iCAAiC,MAAM,CACrC,MAAM,EACN,MAAM,GAAG,OAAO,GAAG,MAAM,GAAG,KAAK,CAClC,CAAC;AAEF,wBAAyB,SAAQ,SAAS;IACxC,QAAQ,CAAC,OAAO,EAAE,WAAW,CAAC;IAC9B,QAAQ,CAAC,IAAI,EAAE,eAAe,CAAC;IAC/B,QAAQ,CAAC,OAAO,EAAE,kBAAkB,GAAG,SAAS,CAAC;gBAE/C,OAAO,EAAE,WAAW,EACpB,IAAI,EAAE,eAAe,EACrB,OAAO,CAAC,EAAE,MAAM,EAChB,OAAO,CAAC,EAAE,kBAAkB;CAO/B;ACpGD,OAAO,MAAM,+BAA+B,CAAC;AAC7C,OAAO,MAAM,8BAA8B,CAAC;AAE5C;;;GAGG;AACH;IACE,wBAAwB;IACxB,YAAY,iBAAiB;IAC7B,cAAc,mBAAmB;IAEjC,cAAc,mBAAmB;IACjC,SAAS,cAAc;IAEvB,QAAQ,aAAa;IACrB,WAAW,gBAAgB;IAC3B,mBAAmB,wBAAwB;IAE3C,iBAAiB,sBAAsB;IAEvC;;;;OAIG;IACH,SAAS,cAAc,CAAE,iDAAiD;IAC1E,KAAK,UAAU,CAAE,2BAA2B;IAC5C,OAAO,YAAY,CAAE,wBAAwB;IAC7C,cAAc,mBAAmB,CAAE,kCAAkC;IACrE,eAAe,oBAAoB,CAAE,oCAAoC;IACzE,cAAc,mBAAmB,CAAE,mDAAmD;IACtF,wBAAwB,6BAA6B,CAAE,iCAAiC;IAExF,UAAU,eAAe;IACzB,YAAY,iBAAiB;IAE7B,0CAA0C;IAC1C,qBAAqB,0BAA0B,CAAE,wBAAwB;IACzE,qBAAqB,0BAA0B,CAAE,wBAAwB;IACzE,oBAAoB,yBAAyB,CAAE,uBAAuB;IACtE,oBAAoB,yBAAyB,CAAE,uBAAuB;IAGtE,iBAAiB,sBAAsB,CAAE,0BAA0B;IACnE,iBAAiB,sBAAsB,CAAE,4BAA4B;IAErE,kBAAkB,uBAAuB,CAAE,gEAAgE;IAC3G,UAAU,eAAe,CAAE,sFAAsF;IAEjH,iBAAiB,sBAAsB,CAAE,oDAAoD;IAE7F,mBAAmB;IACnB,aAAa,kBAAkB,CAAE,kDAAkD;IACnF,YAAY,iBAAiB,CAAE,qCAAqC;IACpE,eAAe,oBAAoB,CAAE,2BAA2B;IAChE,eAAe,oBAAoB,CAAE,0BAA0B;IAI/D,iBAAiB,sBAAsB,CAAE,iCAAiC;IAC1E,yBAAyB,8BAA8B,CAAE,gCAAgC;IACzF,6BAA6B,kCAAkC,CAAE,oCAAoC;IACrG,yBAAyB,8BAA8B,CAAE,gCAAgC;IACzF,wBAAwB,6BAA6B,CAAE,mCAAmC;IAE1F,uBAAuB,4BAA4B,CAAE,0BAA0B;IAE/E,mBAAmB;IACnB,YAAY,iBAAiB,CAAE,sDAAsD;IACrF,eAAe,oBAAoB,CAAE,0BAA0B;IAC/D,eAAe,oBAAoB;CACpC;AAID,2BAA2B;IACzB,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB,CAAC;AAEF,4BAA4B,SAAS,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC;AAClE,6BACI,oBAAoB,GACpB,MAAM,CAAC,MAAM,EAAE,oBAAoB,CAAC,CAAC;AAMzC;IACE,OAAO,EAAE,MAAM,CAAC;IAChB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,gBAAgB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,qBAAqB,CAAC,CAAC;CAC1D;AAED,8BAA8B;IAC5B,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,eAAe,CAAC;CACxB,CAAC;AAEF,wBAAwB;IACtB,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,OAAO,CAAC;CAChB,CAAC;AAEF,gCAAgC;IAC9B,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;CACf,CAAC;AAEF,iCAAiC;IAC/B,UAAU,CAAC,EAAE,iBAAiB,EAAE,CAAC;IACjC,IAAI,CAAC,EAAE,iBAAiB,EAAE,CAAC;IAC3B,UAAU,CAAC,EAAE,iBAAiB,EAAE,CAAC;CAClC,CAAC;AAEF,6BAA6B;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,OAAO,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;CACjB,CAAC;AAEF;IACE,IAAI,SAAS;IACb,QAAQ,aAAa;CACtB;AAED,4BAA4B;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,OAAO,CAAC;IAChB,aAAa,CAAC,EAAE,eAAe,GAAG,MAAM,CAAC;CAC1C,CAAC;AAEF,6BAA6B;IAC3B,IAAI,EAAE,MAAM,CAAC;CACd,CAAC;AAEF,6BAA6B;IAC3B,IAAI,EAAE,MAAM,CAAC;CACd,CAAC;AAEF,gCAAgC;IAE9B,IAAI,EAAE,GAAG,CAAC;CACX,CAAC;AAEF,gCAAgC;IAC9B,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,CAAC,EAAE,OAAO,CAAC;CACb,CAAC;AAEF,0BAA0B;IACxB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB,CAAC;AAEF,6BAA6B;IAC3B,IAAI,EAAE,YAAY,CAAC;CACpB,CAAC;AAEF,mCAAmC;IACjC,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB,CAAC;AAEF,4BAA4B;IAC1B,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,OAAO,CAAC;CAClB,CAAC;AAEF,6BAA6B,kBAAkB,CAAC;AAEhD,8BAA8B;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,MAAM,EAAE,CAAC;CACtB,CAAC;AAEF,uCAAuC;IACrC,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,OAAO,EAAE,eAAe,EAAE,CAAC;CAC5B,CAAC;AAEF,8BAA8B;IAC5B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,eAAe,EAAE,CAAC;CAC5B,CAAC;AAEF,yCAAyC;IACvC,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB,CAAC;AAEF,4CAA4C;IAC1C,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACrC,CAAC;AAEF,4DAA4D;AAC5D,kCAAkC;IAChC,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,YAAY,EAAE,MAAM,CAAC;IACrB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAC/B,CAAC;AAEF,oCAAoC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAAC;AAErE,4CAA4C;IAC1C,aAAa,EAAE,MAAM,CAAC;IACtB,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACnC,MAAM,EAAE,qBAAqB,CAAC;CAC/B,CAAC;AAEF,yCAAyC;IACvC,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,OAAO,CAAC;IACnB,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB,CAAC;AAEF,8BAA8B;IAC5B,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,cAAc,CAAC,EAAE,OAAO,CAAC;CAC1B,CAAC;AAEF,iBAAiB;AACjB,gCAAgC;IAC9B,IAAI,EAAE,MAAM,GAAG,WAAW,CAAC;IAC3B,OAAO,EAAE,OAAO,CAAC;IACjB,eAAe,CAAC,EAAE,OAAO,CAAC;CAC3B,CAAC;AAEF,iBAAiB;AACjB,wCAAwC;IACtC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAAC;CAC1C,CAAC;AAKF,+BAA+B,KAAK,EAAE,eAAe,QAWpD;AAED;IACE,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAsB;IACnC,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,OAAO,CAAC;gBAEF,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,EAAE,CAAC,EAAE,MAAM;IAOpD,MAAM,CAAC,WAAW,IAAI,WAAW;IAUjC,MAAM,CAAC,aAAa,IAAI,WAAW;IAInC,MAAM,CAAC,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,UAAQ,GAAG,WAAW;CAG1D;ACtRD;IACE,oCAAoC;IACpC,SAAS,cAAc;IACvB,YAAY,iBAAiB;IAC7B,qBAAqB,0BAA0B;IAE/C,qCAAqC;IACrC,UAAU,eAAe;IACzB,YAAY,iBAAiB;IAC7B,QAAQ,aAAa;IACrB,eAAe,oBAAoB;IACnC,KAAK,UAAU;IAEf,uBAAuB;IACvB,aAAa,kBAAkB;IAC/B,cAAc,mBAAmB;IACjC,YAAY,iBAAiB;IAE7B,yBAAyB;IACzB,SAAS,cAAc;IACvB,UAAU,eAAe;IAEzB,qBAAqB;IACrB,OAAO,YAAY;IAGnB,kBAAkB,uBAAuB;IACzC,kBAAkB,uBAAuB;IACzC,mBAAmB,wBAAwB;IAC3C,mBAAmB,wBAAwB;IAG3C,eAAe,oBAAoB;IACnC,eAAe,oBAAoB;IAGnC,cAAc,mBAAmB;IACjC,SAAS,cAAc;IAEvB,aAAa,kBAAkB;IAG/B,UAAU,eAAe;IACzB,aAAa,kBAAkB;IAC/B,aAAa,kBAAkB;IAG/B,eAAe,oBAAoB;IACnC,sBAAsB,2BAA2B;IACjD,yBAAyB,8BAA8B;IACvD,sBAAsB,2BAA2B;IAEjD,oBAAoB,yBAAyB;IAG7C,UAAU,eAAe;IACzB,aAAa,kBAAkB;IAC/B,aAAa,kBAAkB;IAE/B,yBAAyB;IACzB,oBAAoB,yBAAyB;IAC7C,eAAe,oBAAoB;IAEnC,mBAAmB;IACnB,YAAY,iBAAiB;IAC7B,YAAY,iBAAiB;IAC7B,kBAAkB,uBAAuB;IACzC,kBAAkB,uBAAuB;IACzC,gBAAgB,qBAAqB;IAErC,eAAe,oBAAoB;IACnC,gBAAgB,qBAAqB;IAErC,0BAA0B;IAC1B,oBAAoB,yBAAyB;IAC7C,oBAAoB,yBAAyB;IAC7C,wBAAwB,6BAA6B;IACrD,UAAU,eAAe;IACzB,UAAU,eAAe;IACzB,cAAc,mBAAmB;IACjC,2BAA2B;IAC3B,iBAAiB,sBAAsB;IACvC,kBAAkB,uBAAuB;CAC1C;AAED,yBAAyB,OAAO,CAAC;IAC/B,oCAAoC;IACpC,SAAS,EAAE,MAAM,IAAI,CAAC;IACtB,YAAY,EAAE,MAAM,IAAI,CAAC;IACzB,qBAAqB,EAAE,CAAC,KAAK,EAAE,cAAc,KAAK,IAAI,CAAC;IAEvD,qCAAqC;IACrC,UAAU,EAAE,CAAC,WAAW,EAAE,OAAO,KAAK,IAAI,CAAC;IAC3C,YAAY,EAAE,CAAC,WAAW,EAAE,WAAW,KAAK,IAAI,CAAC;IACjD,QAAQ,EAAE,CAAC,OAAO,EAAE,YAAY,KAAK,IAAI,CAAC;IAC1C,eAAe,EAAE,CAAC,WAAW,EAAE,WAAW,KAAK,IAAI,CAAC;IACpD,KAAK,EAAE,CAAC,OAAO,EAAE,WAAW,KAAK,IAAI,CAAC;IAEtC,uBAAuB;IAEvB,aAAa,EAAE,CAAC,IAAI,EAAE,GAAG,KAAK,IAAI,CAAC;IAEnC,cAAc,EAAE,CAAC,IAAI,EAAE,GAAG,KAAK,IAAI,CAAC;IACpC,YAAY,EAAE,CAAC,OAAO,EAAE,WAAW,KAAK,IAAI,CAAC;IAE7C,yBAAyB;IACzB,SAAS,EAAE,CAAC,IAAI,EAAE,aAAa,KAAK,IAAI,CAAC;IACzC,UAAU,EAAE,CAAC,IAAI,EAAE,cAAc,KAAK,IAAI,CAAC;IAE3C,qBAAqB;IACrB,OAAO,EAAE,CAAC,IAAI,EAAE,kBAAkB,KAAK,IAAI,CAAC;IAG5C,kBAAkB,EAAE,MAAM,IAAI,CAAC;IAC/B,kBAAkB,EAAE,MAAM,IAAI,CAAC;IAC/B,mBAAmB,EAAE,MAAM,IAAI,CAAC;IAChC,mBAAmB,EAAE,MAAM,IAAI,CAAC;IAGhC,eAAe,EAAE,MAAM,IAAI,CAAC;IAC5B,eAAe,EAAE,MAAM,IAAI,CAAC;IAG5B,cAAc,EAAE,CAAC,IAAI,EAAE,cAAc,KAAK,IAAI,CAAC;IAC/C,SAAS,EAAE,CAAC,IAAI,EAAE,aAAa,KAAK,IAAI,CAAC;IACzC,aAAa,EAAE,CAAC,IAAI,EAAE,cAAc,KAAK,IAAI,CAAC;IAG9C,UAAU,EAAE,CAAC,IAAI,EAAE,cAAc,KAAK,IAAI,CAAC;IAC3C,aAAa,EAAE,MAAM,IAAI,CAAC;IAC1B,aAAa,EAAE,MAAM,IAAI,CAAC;IAE1B,wDAAwD;IACxD,eAAe,EAAE,CAAC,IAAI,EAAE,mBAAmB,KAAK,IAAI,CAAC;IACrD,sBAAsB,EAAE,CAAC,IAAI,EAAE,0BAA0B,KAAK,IAAI,CAAC;IACnE,yBAAyB,EAAE,CAAC,IAAI,EAAE,6BAA6B,KAAK,IAAI,CAAC;IACzE,sBAAsB,EAAE,CAAC,IAAI,EAAE,0BAA0B,KAAK,IAAI,CAAC;IAEnE,oBAAoB,EAAE,CAAC,IAAI,EAAE,wBAAwB,KAAK,IAAI,CAAC;IAG/D,UAAU,EAAE,CAAC,IAAI,EAAE,cAAc,KAAK,IAAI,CAAC;IAC3C,aAAa,EAAE,MAAM,IAAI,CAAC;IAC1B,aAAa,EAAE,MAAM,IAAI,CAAC;IAE1B,yBAAyB;IACzB,oBAAoB,EAAE,CAAC,WAAW,EAAE,WAAW,KAAK,IAAI,CAAC;IACzD,eAAe,EAAE,CAAC,WAAW,EAAE,WAAW,KAAK,IAAI,CAAC;IAEpD,mBAAmB;IACnB,YAAY,EAAE,CAAC,KAAK,EAAE,gBAAgB,EAAE,WAAW,CAAC,EAAE,WAAW,KAAK,IAAI,CAAC;IAC3E,YAAY,EAAE,CAAC,KAAK,EAAE,gBAAgB,EAAE,WAAW,CAAC,EAAE,WAAW,KAAK,IAAI,CAAC;IAC3E,kBAAkB,EAAE,CAAC,KAAK,EAAE,gBAAgB,EAAE,CAAC,CAAC,EAAE,WAAW,KAAK,IAAI,CAAC;IACvE,kBAAkB,EAAE,CAAC,KAAK,EAAE,gBAAgB,EAAE,CAAC,CAAC,EAAE,WAAW,KAAK,IAAI,CAAC;IACvE,gBAAgB,EAAE,CAAC,YAAY,EAAE,MAAM,KAAK,IAAI,CAAC;IAEjD,eAAe,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACzC,gBAAgB,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,CAAC,EAAE,WAAW,KAAK,IAAI,CAAC;IAE1D,0BAA0B;IAC1B,oBAAoB,EAAE,CAAC,IAAI,EAAE,eAAe,EAAE,KAAK,IAAI,CAAC;IACxD,oBAAoB,EAAE,CAAC,IAAI,EAAE,eAAe,EAAE,KAAK,IAAI,CAAC;IACxD,wBAAwB,EAAE,CAAC,QAAQ,EAAE,eAAe,EAAE,KAAK,IAAI,CAAC;IAChE,UAAU,EAAE,CAAC,GAAG,EAAE,eAAe,KAAK,IAAI,CAAC;IAC3C,UAAU,EAAE,CAAC,GAAG,EAAE,eAAe,KAAK,IAAI,CAAC;IAC3C,cAAc,EAAE,CAAC,OAAO,EAAE,eAAe,KAAK,IAAI,CAAC;IACnD,WAAW,EAAE,CAAC,KAAK,EAAE,WAAW,KAAK,IAAI,CAAC;IAC1C,iBAAiB,EAAE,CAAC,UAAU,EAAE,UAAU,KAAK,IAAI,CAAC;IACpD,kBAAkB,EAAE,CAAC,KAAK,EAAE,uBAAuB,KAAK,IAAI,CAAC;CAC9D,CAAC,CAAC;AAEH,6BAA6B,CAAC,SAAS,SAAS,IAAI,CAAC,SAAS,MAAM,UAAU,GAC1E,UAAU,CAAC,CAAC,CAAC,GACb,KAAK,CAAC;AGtMV;;;;GAIG;AAEH;IACE,IAAI,IAAI;IACR,KAAK,IAAI;IACT,IAAI,IAAI;IACR,IAAI,IAAI;IACR,KAAK,IAAI;CACV;AAED;IAIE,OAAO;IAEP,MAAM,CAAC,WAAW,IAAI,MAAM;IAO5B,QAAQ,CAAC,KAAK,EAAE,QAAQ;IAIxB,KAAK,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE;IAMxB,IAAI,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE;IAMvB,IAAI,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE;IAMvB,KAAK,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE;CAKzB;AAED,OAAO,MAAM,cAA6B,CAAC;AAE3C,sBAAsB,MAAM,CAAC;ACjD7B;IACE,OAAO,EAAE,WAAW,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,CAAC;IAClC,MAAM,EAAE,CAAC,MAAM,CAAC,EAAE,OAAO,KAAK,IAAI,CAAC;CACpC;AAED;IACE,SAAS,CAAC,WAAW,EAAE,CAAC,OAAO,EAAE,WAAW,KAAK,IAAI,CAAC;IACtD,SAAS,CAAC,MAAM,sBAAkC;IAClD,SAAS,CAAC,WAAW,EAAE,UAAU,CAAC,OAAO,WAAW,CAAC,GAAG,SAAS,CAAa;gBAElE,UAAU,EAAE,CAAC,OAAO,EAAE,WAAW,KAAK,IAAI;IAK/C,UAAU;IAMV,QAAQ,CACb,YAAY,EAAE,OAAO,EACrB,IAAI,kBAAiC,EACrC,OAAO,SAAQ,GACd,OAAO,CAAC,WAAW,CAAC;IAiChB,UAAU;IA4BV,OAAO,CAAC,OAAO,EAAE,WAAW,GAAG,WAAW;IAI1C,MAAM,CAAC,OAAO,EAAE,WAAW,GAAG,WAAW;IAIhD,SAAS,CAAC,GAAG;CAwBd;AChID,oBACI,MAAM,GACN,MAAM,GACN,OAAO,GACP,IAAI,GACJ,YAAY,EAAE,GACd;IAAE,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,YAAY,CAAA;CAAE,CAAC;AAE7C;IACE,QAAQ,EAAE,MAAM,GAAG,GAAG,GAAG,WAAW,OAAO,CAAC;IAC5C,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,WAAW,CAAC,EAAE,YAAY,CAAC;IAC3B,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED;;GAEG;AACH,iCAAiC,UAAU,CAAC;AAE5C,6BAA6B,KAAK,EAAE,OAAO,GAAG,OAAO,CAcpD;AAED,4BACE,OAAO,EAAE,UAAU,EACnB,eAAe,CAAC,EAAE,eAAe,GAChC,OAAO,CAAC,OAAO,CAAC,CAwElB;ACvGD,qBAAqB;IACnB,KAAK,EAAE;QACL,KAAK,CAAC,EAAE,gBAAgB,CAAC;QACzB,KAAK,CAAC,EAAE,gBAAgB,CAAC;QACzB,WAAW,CAAC,EAAE,gBAAgB,CAAC;QAC/B,WAAW,CAAC,EAAE,gBAAgB,CAAC;KAChC,CAAC;IACF,GAAG,CAAC,EAAE;QACJ,KAAK,CAAC,EAAE,gBAAgB,CAAC;QACzB,WAAW,CAAC,EAAE,SAAS,CAAC;QACxB,WAAW,CAAC,EAAE,SAAS,CAAC;QACxB,KAAK,CAAC,EAAE,gBAAgB,CAAC;KAC1B,CAAC;CACH,CAAC;AAEF,wCAAwC,OAAO,CAAC;AAEhD,OAAO,QAAQ;IACb,UAAkB,QAAQ,EAAE,oBAAoB,CAAC;IACjD,UAAkB,UAAU,EAAE,CAAC,EAAE,EAAE,WAAW,KAAK,IAAI,CAAC;IACxD,UAAkB,UAAU,EAAE,kBAAkB,CAAC;IACjD,UAAkB,gBAAgB,EAAE,eAAe,GAAG,SAAS,CAAC;IAChE,SAAS,CAAC,MAAM,EAAE,cAAc,CAAkB;IAClD,SAAS,CAAC,eAAe,EAAE,UAAU,GAAG,SAAS,CAAC;IAClD;;;;;;;;;;;OAWG;IACH,SAAS,CAAC,eAAe,SAAa;;IAItC,iEAAiE;IACjE,QAAQ,CAAC,UAAU,CACjB,OAAO,EAAE,oBAAoB,EAC7B,cAAc,EAAE,CAAC,EAAE,EAAE,WAAW,KAAK,IAAI,GACxC,IAAI;IAEP;;;;OAIG;IACH,QAAQ,CAAC,WAAW,IAAI,OAAO,CAAC,IAAI,CAAC;IAErC;;;;;;OAMG;IACH,OAAO,CAAC,aAAa,CAAC,EAAE,yBAAyB,GAAG,OAAO,CAAC,IAAI,CAAC;IAcjE;;OAEG;IACH,IAAI,cAAc,IAAI,UAAU,GAAG,SAAS,CAE3C;IAED;;;OAGG;IACH,IAAI,cAAc,CAAC,cAAc,EAAE,UAAU,EAc5C;IAED,QAAQ,CAAC,yBAAyB,CAAC,aAAa,CAAC,EAAE,OAAO,GAAG,OAAO;IAEpE,QAAQ,CAAC,QAAQ,CAAC,aAAa,CAAC,EAAE,yBAAyB,GAAG,OAAO,CAAC,IAAI,CAAC;IAC3E;;;OAGG;IACH,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAM3B,QAAQ,CAAC,WAAW,IAAI,OAAO,CAAC,IAAI,CAAC;IACrC,QAAQ,CAAC,gBAAgB,IAAI,IAAI;IAEjC,QAAQ,KAAK,KAAK,IAAI,cAAc,CAAC;IACrC,QAAQ,KAAK,KAAK,CAAC,KAAK,EAAE,cAAc,EAAE;IAE1C,QAAQ,CAAC,UAAU,IAAI,OAAO,CAAC,eAAe,EAAE,CAAC;IACjD,QAAQ,CAAC,UAAU,IAAI,OAAO,CAAC,eAAe,EAAE,CAAC;IACjD,QAAQ,CAAC,cAAc,IAAI,OAAO,CAAC,eAAe,EAAE,CAAC;IAErD,QAAQ,CAAC,SAAS,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IACvC,QAAQ,CAAC,SAAS,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IACvC,QAAQ,CAAC,aAAa,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI;IAE/C,QAAQ,KAAK,WAAW,IAAI,eAAe,GAAG,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;IACpE,QAAQ,KAAK,WAAW,IAAI,eAAe,GAAG,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;IACpE,QAAQ,KAAK,eAAe,IAAI,eAAe,GAAG,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;IAExE,QAAQ,CAAC,SAAS,CAAC,MAAM,EAAE,OAAO,GAAG,IAAI;IACzC,QAAQ,CAAC,SAAS,CAAC,MAAM,EAAE,OAAO,GAAG,IAAI;IACzC,QAAQ,CAAC,iBAAiB,CAAC,MAAM,EAAE,OAAO,GAAG,IAAI;IACjD,QAAQ,KAAK,YAAY,IAAI,OAAO,CAAC;IACrC,QAAQ,KAAK,YAAY,IAAI,OAAO,CAAC;IACrC,QAAQ,KAAK,eAAe,IAAI,OAAO,CAAC;IAExC,QAAQ,CAAC,WAAW,CAAC,OAAO,EAAE,WAAW,GAAG,IAAI;IAChD;;;;OAIG;IACH,IAAI,cAAc,IAAI,MAAM,CAE3B;IAED,QAAQ,CAAC,MAAM,IAAI,MAAM;CAC1B;AAED;gBAIc,SAAS,EAAE,SAAS;IA0ChC,IAAI,KAAK,IAAI,SAAS,CAErB;CACF;AC3MD,2BAA4B,SAAQ,eAAe;IACjD,gBAAgB,EAAE;QAChB,OAAO,CAAC,EAAE,MAAM,CAAC;QACjB,eAAe,CAAC,EAAE,MAAM,CAAC;QACzB,aAAa,CAAC,EAAE,MAAM,CAAC;QACvB,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,aAAa,CAAC,EAAE,MAAM,CAAC;QACvB,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,UAAU,CAAC,EAAE;YACX,aAAa,CAAC,EAAE,MAAM,CAAC;YACvB,QAAQ,CAAC,EAAE,MAAM,CAAC;SACnB,CAAC;KACH,CAAC;CACH;AAED,sDA2CC;AAED,uCACE,OAAO,EAAE,OAAO,EAChB,OAAO,EAAE,MAAM,GACd,OAAO,CAST;ACbD,iCAAiC;IAC/B,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACpC,CAAC;AA2BF,mCAAmC,CACjC,EAAE,EAAE,kBAAkB,KACnB,OAAO,CAAC,qBAAqB,GAAG,IAAI,CAAC,CAAC;AAE3C,iCAAiC,OAAO,CAAC;IACvC,WAAW,EAAE,MAAM,IAAI,CAAC;IACxB,cAAc,EAAE,MAAM,IAAI,CAAC;IAC3B,OAAO,EAAE,CAAC,OAAO,EAAE,WAAW,KAAK,IAAI,CAAC;IACxC,uBAAuB,EAAE,CAAC,KAAK,EAAE,cAAc,KAAK,IAAI,CAAC;IAEzD,YAAY,EAAE,CAAC,WAAW,EAAE,OAAO,KAAK,IAAI,CAAC;IAC7C,cAAc,EAAE,CAAC,WAAW,EAAE,WAAW,KAAK,IAAI,CAAC;IACnD,UAAU,EAAE,CAAC,YAAY,EAAE,YAAY,KAAK,IAAI,CAAC;IACjD,iBAAiB,EAAE,CAAC,WAAW,EAAE,WAAW,KAAK,IAAI,CAAC;IACtD,SAAS,EAAE,CAAC,IAAI,EAAE,kBAAkB,KAAK,IAAI,CAAC;IAG9C,eAAe,EAAE,CAAC,IAAI,EAAE,GAAG,KAAK,IAAI,CAAC;IACrC,cAAc,EAAE,CAAC,OAAO,EAAE,WAAW,KAAK,IAAI,CAAC;IAC/C,WAAW,EAAE,CAAC,IAAI,EAAE,aAAa,KAAK,IAAI,CAAC;IAC3C,YAAY,EAAE,CAAC,IAAI,EAAE,cAAc,KAAK,IAAI,CAAC;IAE7C,mBAAmB,EAAE,CAAC,WAAW,EAAE,WAAW,KAAK,IAAI,CAAC;IACxD,iBAAiB,EAAE,CAAC,WAAW,EAAE,WAAW,KAAK,IAAI,CAAC;IAEtD,sBAAsB,EAAE,CAAC,IAAI,EAAE,eAAe,EAAE,KAAK,IAAI,CAAC;IAC1D,sBAAsB,EAAE,CAAC,IAAI,EAAE,eAAe,EAAE,KAAK,IAAI,CAAC;IAC1D,0BAA0B,EAAE,CAAC,QAAQ,EAAE,eAAe,EAAE,KAAK,IAAI,CAAC;IAClE,YAAY,EAAE,CAAC,GAAG,EAAE,eAAe,KAAK,IAAI,CAAC;IAC7C,YAAY,EAAE,CAAC,GAAG,EAAE,eAAe,KAAK,IAAI,CAAC;IAC7C,gBAAgB,EAAE,CAAC,OAAO,EAAE,eAAe,KAAK,IAAI,CAAC;IACrD,aAAa,EAAE,CAAC,KAAK,EAAE,WAAsB,KAAK,IAAI,CAAC;IACvD,mBAAmB,EAAE,CAAC,UAAU,EAAE,UAAU,KAAK,IAAI,CAAC;IACtD,cAAc,EAAE,CAAC,KAAK,EAAE,gBAAgB,EAAE,WAAW,CAAC,EAAE,WAAW,KAAK,IAAI,CAAC;IAC7E,cAAc,EAAE,CAAC,KAAK,EAAE,gBAAgB,EAAE,WAAW,CAAC,EAAE,WAAW,KAAK,IAAI,CAAC;IAC7E,oBAAoB,EAAE,CACpB,KAAK,EAAE,gBAAgB,EACvB,WAAW,CAAC,EAAE,WAAW,KACtB,IAAI,CAAC;IACV,oBAAoB,EAAE,CACpB,KAAK,EAAE,gBAAgB,EACvB,WAAW,CAAC,EAAE,WAAW,KACtB,IAAI,CAAC;IACV,kBAAkB,EAAE,CAAC,YAAY,EAAE,MAAM,KAAK,IAAI,CAAC;IACnD,oBAAoB,EAAE,CAAC,KAAK,EAAE,uBAAkC,KAAK,IAAI,CAAC;IAC1E,iBAAiB,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAC3C,kBAAkB,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,WAAW,EAAE,WAAW,KAAK,IAAI,CAAC;IAEtE,qBAAqB,EAAE,MAAM,IAAI,CAAC;IAClC,qBAAqB,EAAE,MAAM,IAAI,CAAC;IAClC,oBAAoB,EAAE,MAAM,IAAI,CAAC;IACjC,oBAAoB,EAAE,MAAM,IAAI,CAAC;IACjC,iBAAiB,EAAE,MAAM,IAAI,CAAC;IAC9B,iBAAiB,EAAE,MAAM,IAAI,CAAC;IAC9B,gBAAgB,EAAE,CAAC,IAAI,EAAE,cAAc,KAAK,IAAI,CAAC;IACjD,WAAW,EAAE,CAAC,IAAI,EAAE,aAAa,KAAK,IAAI,CAAC;IAC3C,0CAA0C;IAC1C,eAAe,EAAE,CAAC,IAAI,EAAE,cAAc,KAAK,IAAI,CAAC;IAEhD,YAAY,EAAE,CAAC,IAAI,EAAE,cAAc,KAAK,IAAI,CAAC;IAC7C,eAAe,EAAE,MAAM,IAAI,CAAC;IAC5B,eAAe,EAAE,MAAM,IAAI,CAAC;IAC5B,YAAY,EAAE,CAAC,IAAI,EAAE,cAAc,KAAK,IAAI,CAAC;IAC7C,eAAe,EAAE,MAAM,IAAI,CAAC;IAC5B,eAAe,EAAE,MAAM,IAAI,CAAC;IAE5B,wBAAwB,EAAE,CAAC,IAAI,EAAE,0BAA0B,KAAK,IAAI,CAAC;IACrE,2BAA2B,EAAE,CAAC,IAAI,EAAE,6BAA6B,KAAK,IAAI,CAAC;IAC3E,wBAAwB,EAAE,CAAC,IAAI,EAAE,0BAA0B,KAAK,IAAI,CAAC;IACrE,sBAAsB,EAAE,CAAC,IAAI,EAAE,wBAAwB,KAAK,IAAI,CAAC;IACjE,0DAA0D;IAC1D,iBAAiB,EAAE,CAAC,IAAI,EAAE,mBAAmB,KAAK,IAAI,CAAC;CACxD,CAAC,CAAC;AAEH;IACE;;OAEG;IACH,SAAS,EAAE,SAAS,CAAC;IAErB;;OAEG;IACH,SAAS,CAAC,EAAE,kBAAkB,CAAC;IAE/B;;;;OAIG;IACH,SAAS,CAAC,EAAE,OAAO,CAAC;IAEpB;;;;OAIG;IACH,SAAS,CAAC,EAAE,OAAO,CAAC;IAEpB;;;;OAIG;IACH,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAE5B;;;;OAIG;IACH,yBAAyB,CAAC,EAAE,OAAO,CAAC;CACrC;qCAEmE,UAAU,YAAY,CAAC,UAAU,CAAC;AAAtG,QAAA,QAAQ,uBAAwB,SAAQ,qBAA+D;CAAG;AAE1G,0BAA2B,SAAQ,gBAAgB;IACjD,SAAS,CAAC,QAAQ,EAAE,oBAAoB,CAAC;IAEzC,SAAS,CAAC,UAAU,EAAE,SAAS,CAAC;IAChC,SAAS,CAAC,iBAAiB,EAAE,gBAAgB,CAAC;IAC9C,SAAS,CAAC,0BAA0B,EAAE,OAAO,CAAC;IAC9C,UAAkB,kBAAkB,EAAE,iBAAiB,CAAC;IACxD,SAAS,CAAC,sBAAsB,EAAE,MAAM,CAAC,MAAM,EAAE,oBAAoB,CAAC,CAAM;IAC5E,SAAS,CAAC,gBAAgB,EAAE,eAAe,GAAG,SAAS,CAAC;gBAe5C,OAAO,EAAE,oBAAoB;IA8OlC,WAAW,CAAC,KAAK,EAAE,QAAQ;IAMlC;;;;;;;;;;;;;;OAcG;IACU,WAAW;IA4ExB;;;;;OAKG;IAEU,QAAQ,CAAC,cAAc,EAAE,UAAU,GAAG,OAAO,CAAC,OAAO,CAAC;IAqCnE;;;;;;;;;;;OAWG;IAEU,OAAO,CAClB,aAAa,CAAC,EAAE,yBAAyB,GAAG,kBAAkB,GAC7D,OAAO,CAAC,YAAY,CAAC;IAgCX,kBAAkB,CAC7B,cAAc,EAAE,UAAU,GACzB,OAAO,CAAC,YAAY,CAAC;IAKxB;;;OAGG;IACU,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IA8IxC;;OAEG;IACH,IAAW,SAAS,IAAI,OAAO,CAE9B;IAED,IAAW,SAAS,IAAI,SAAS,CAEhC;IAED,IAAW,KAAK,IAAI,cAAc,CAEjC;IAED;;;;;;OAMG;IACH,IAAW,UAAU,IAAI,UAAU,CAOlC;IAED;;;;;;;;;OASG;IACI,SAAS,IAAI,OAAO;IAgB3B,IAAW,OAAO,IAAI,MAAM,CAE3B;IAIY,UAAU,IAAI,OAAO,CAAC,eAAe,EAAE,CAAC;IAIxC,UAAU,IAAI,OAAO,CAAC,eAAe,EAAE,CAAC;IAIxC,cAAc,IAAI,OAAO,CAAC,eAAe,EAAE,CAAC;IAIzD,IAAW,WAAW,4CAErB;IAED,IAAW,WAAW,4CAUrB;IAED,IAAW,eAAe,4CAEzB;IAEM,SAAS,CAAC,KAAK,EAAE,MAAM;IAIvB,SAAS,CAAC,KAAK,EAAE,MAAM;IAIvB,aAAa,CAAC,SAAS,EAAE,MAAM;IAI/B,SAAS,CAAC,MAAM,EAAE,OAAO;IAIhC,IAAW,YAAY,IAAI,OAAO,CAEjC;IAEM,SAAS,CAAC,MAAM,EAAE,OAAO;IAYhC,IAAW,YAAY,IAAI,OAAO,CAEjC;IAEM,MAAM,IAAI,MAAM;IAIhB,iBAAiB,CAAC,MAAM,EAAE,OAAO;IAYxC,IAAW,eAAe,IAAI,OAAO,CAEpC;IAID;;;;;OAKG;IAEI,iBAAiB,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,OAAO,GAAG,IAAI;IAS/D;;;;;;OAMG;IAEI,WAAW,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,OAAO,GAAG,IAAI;IAK1D;;;;;;OAMG;IACI,qBAAqB,CAC1B,OAAO,GAAE,2BAAgC,GACxC,IAAI;IAYP;;OAEG;IACI,oBAAoB,IAAI,IAAI;IAkBnC;;;;;OAKG;IAEI,gBAAgB,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI;IAM7D;;;;;;OAMG;IAEU,iBAAiB,CAC5B,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,OAAO,EACb,OAAO,CAAC,EAAE,MAAM;IAYX,2BAA2B,CAChC,YAAY,EAAE,MAAM,EACpB,QAAQ,EAAE,oBAAoB;IAKzB,6BAA6B,CAAC,YAAY,EAAE,MAAM;IAIlD,iCAAiC;IAK3B,eAAe,CAAC,OAAO,EAAE,iBAAiB;IAa1C,QAAQ,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,GAAE,eAAoB;IASpE;;OAEG;IAEI,aAAa,IAAI,IAAI;IAI5B,SAAS,CAAC,aAAa,CAAC,EAAE,EAAE,WAAW,GAAG,IAAI;CA6L/C","sources":["client-js/rtvi/ui.ts","client-js/rtvi/a11y_walker.ts","client-js/client/A11ySnapshotStreamer.ts","client-js/rtvi/common_types.ts","client-js/rtvi/errors.ts","client-js/rtvi/messages.ts","client-js/rtvi/events.ts","client-js/rtvi/index.ts","client-js/client/decorators.ts","client-js/client/logger.ts","client-js/client/dispatcher.ts","client-js/client/rest_helpers.ts","client-js/client/transport.ts","client-js/client/utils.ts","client-js/client/client.ts","client-js/client/index.ts","client-js/index.ts"],"sourcesContent":["/**\n * Copyright (c) 2026, Daily.\n *\n * SPDX-License-Identifier: BSD-2-Clause\n */\n\n// ---------------------------------------------------------------------------\n// Built-in command payload types (mirror the server's UI command models\n// in `pipecat.processors.frameworks.rtvi.models`)\n// ---------------------------------------------------------------------------\n\n/** Payload for the built-in `toast` command. */\nexport interface ToastPayload {\n  title: string;\n  subtitle?: string | null;\n  description?: string | null;\n  image_url?: string | null;\n  duration_ms?: number | null;\n}\n\n/** Payload for the built-in `navigate` command. */\nexport interface NavigatePayload {\n  view: string;\n  params?: Record<string, unknown> | null;\n}\n\n/** Payload for the built-in `scroll_to` command. */\nexport interface ScrollToPayload {\n  /**\n   * Snapshot ref (e.g. `\"e42\"`) assigned by the a11y walker. When\n   * set, the default handler resolves this first; use when the server\n   * is referencing an element it saw in `<ui_state>`.\n   */\n  ref?: string | null;\n  /**\n   * Element id (`document.getElementById`). Used as a fallback when\n   * `ref` is not set or no longer resolves.\n   */\n  target_id?: string | null;\n  /** Typically `\"smooth\"` or `\"instant\"`. Clients may ignore. */\n  behavior?: string | null;\n}\n\n/** Payload for the built-in `highlight` command. */\nexport interface HighlightPayload {\n  ref?: string | null;\n  target_id?: string | null;\n  duration_ms?: number | null;\n}\n\n/** Payload for the built-in `focus` command. */\nexport interface FocusPayload {\n  ref?: string | null;\n  target_id?: string | null;\n}\n\n/**\n * Payload for the built-in `click` command.\n *\n * Closes the form-fill loop for non-text inputs (checkboxes,\n * radios) and exposes the rest of the action vocabulary (submit\n * buttons, links, app-specific clickable nodes). The standard\n * handler refuses on `disabled` targets.\n *\n * For native `<select>`, prefer `set_input_value` (clicking\n * options doesn't reliably change the selection); for custom\n * comboboxes, apps wire their own command matching the library's\n * interaction model.\n */\nexport interface ClickPayload {\n  ref?: string | null;\n  target_id?: string | null;\n}\n\n/**\n * Payload for the built-in `set_input_value` command.\n *\n * Asks the client to write `value` into a text input, textarea, or\n * native `<select>`. The default handler refuses to write into\n * `disabled`, `readonly`, or `<input type=\"hidden\">` targets so the\n * worker can't bypass UI affordances the user is meant to control.\n *\n * For text inputs and textareas, `replace: false` appends the value\n * to whatever is already in the field; the default replaces. The\n * flag is ignored for native `<select>` (a select either has the\n * value or doesn't; \"appending\" is meaningless).\n */\nexport interface SetInputValuePayload {\n  ref?: string | null;\n  target_id?: string | null;\n  value: string;\n  /** When omitted, defaults to `true` (replace existing value). */\n  replace?: boolean | null;\n}\n\n/**\n * Payload for the built-in `select_text` command.\n *\n * Mirror of the read-side {@link A11ySelection}: the worker asks the\n * client to make a text selection on the page so the user can see\n * what content the worker is referring to. With `start_offset` /\n * `end_offset` omitted, the entire target's text is selected.\n *\n * Document elements use a `Range` over descendant text nodes and the\n * default handler walks them to convert character offsets into\n * `(textNode, offsetInNode)` pairs. `<input>` and `<textarea>`\n * targets use `setSelectionRange(start, end)` (or `el.select()` when\n * offsets are absent).\n */\nexport interface SelectTextPayload {\n  ref?: string | null;\n  target_id?: string | null;\n  /** Character offset within the target where the selection starts. */\n  start_offset?: number | null;\n  /** End character offset, exclusive. */\n  end_offset?: number | null;\n}\n\n// ---------------------------------------------------------------------------\n// Structural awareness: a11y snapshot\n// ---------------------------------------------------------------------------\n\n// ---------------------------------------------------------------------------\n// Job lifecycle protocol\n// ---------------------------------------------------------------------------\n\n/**\n * Status of a worker within a job group.\n *\n * Mirrors the server's `pipecat.pipeline.job_context.JobStatus`.\n * Jobs are surfaced to the client as `\"running\"` from the moment the\n * group_started envelope arrives. The terminal status is set when\n * `job_completed` arrives.\n */\nexport type JobStatus =\n  | \"running\"\n  | \"completed\"\n  | \"cancelled\"\n  | \"failed\"\n  | \"error\";\n\n/** Group dispatched: the worker list is now known. */\nexport interface UIJobGroupStartedEnvelope {\n  kind: \"group_started\";\n  /** Shared identifier for every job in the group. */\n  job_id: string;\n  /** Worker names in dispatch order. */\n  workers: string[];\n  /** Optional human-readable label set by the server. */\n  label?: string | null;\n  /** Whether the client may request cancellation via `cancelUIJobGroup`. */\n  cancellable: boolean;\n  /** Epoch ms when the group started. */\n  at: number;\n}\n\n/** Per-worker progress: `data` is whatever the worker passed to `send_job_update`. */\nexport interface UIJobUpdateEnvelope {\n  kind: \"job_update\";\n  job_id: string;\n  /** The worker that produced this update. */\n  worker_name: string;\n  /** Worker-defined payload. Forwarded verbatim. */\n  data: unknown;\n  at: number;\n}\n\n/** Per-worker terminal: status + final response. */\nexport interface UIJobCompletedEnvelope {\n  kind: \"job_completed\";\n  job_id: string;\n  worker_name: string;\n  status: JobStatus;\n  /** Worker's final response payload. */\n  response?: unknown;\n  at: number;\n}\n\n/** Group terminal: every worker has responded (or the group was cancelled). */\nexport interface UIJobGroupCompletedEnvelope {\n  kind: \"group_completed\";\n  job_id: string;\n  at: number;\n}\n\n/** Discriminated union of every `ui-job-group` envelope kind. */\nexport type UIJobGroupEnvelope =\n  | UIJobGroupStartedEnvelope\n  | UIJobUpdateEnvelope\n  | UIJobCompletedEnvelope\n  | UIJobGroupCompletedEnvelope;\n\n/**\n * Signature for a UI job-group lifecycle listener.\n *\n * Receives every `ui-job-group` envelope in arrival order. Switch on\n * `envelope.kind` to react to specific lifecycle phases. The React\n * `useUIJobGroups` hook is the recommended consumer for app code; this\n * lower-level listener is for hosts that want to drive their own\n * state.\n */\nexport type UIJobGroupListener = (envelope: UIJobGroupEnvelope) => void;\n\n/**\n * One node in the accessibility snapshot tree.\n *\n * Shape is modeled on Playwright's accessibility snapshot and the\n * Playwright MCP server's LLM-facing serialization. Portable across\n * web, iOS (UIAccessibility), and Android (AccessibilityNodeInfo).\n *\n * Stability: this is the v1 wire format. Field names and semantics\n * are versioned via the SDK's package version; consumer servers\n * (e.g. `pipecat`'s `UIWorker`) track compatible client\n * releases in their own changelogs.\n */\nexport interface A11yNode {\n  /**\n   * Stable reference id of the form `e{N}`. The same DOM node keeps\n   * the same ref across snapshots for as long as it is mounted. Lets\n   * the LLM cross-reference elements between turns (\"the button I\n   * mentioned earlier\").\n   */\n  ref: string;\n  /** ARIA role (explicit or tag-derived). */\n  role: string;\n  /** Accessible name, truncated to 100 chars. */\n  name?: string;\n  /** Current value for inputs (omitted for passwords), progress, etc. */\n  value?: string;\n  /**\n   * Short state tags. Known values: `\"focused\"`, `\"selected\"`,\n   * `\"expanded\"`, `\"checked\"`, `\"disabled\"`, `\"offscreen\"`.\n   * Apps may add their own, but should stick to single lowercase\n   * words so they render cleanly as `[tag]` in `<ui_state>`.\n   */\n  state?: string[];\n  /** Heading level, 1-6. */\n  level?: number;\n  /**\n   * Column count for grid-like containers. Populated from\n   * `aria-colcount` on the element. Lets the LLM compute\n   * row/column positions from the flat reading order of children.\n   */\n  colcount?: number;\n  /**\n   * Row count for grid-like containers. Populated from\n   * `aria-rowcount` on the element.\n   */\n  rowcount?: number;\n  /** Child nodes. */\n  children?: A11yNode[];\n}\n\n/**\n * The user's current text selection, when one exists.\n *\n * Lets the worker ground deictic references like \"this paragraph\",\n * \"what I selected\", or \"the highlighted text\" against actual on-page\n * content rather than re-asking the user to repeat it.\n *\n * Document selections (selecting text across paragraphs, headings,\n * etc.) carry the closest common-ancestor element's `ref` plus the\n * full selected text. Offsets are not provided for document\n * selections because they would require walking text-node positions\n * inside the ancestor; the worker reasons over the `text` field.\n *\n * Input/textarea selections do carry `start_offset` and\n * `end_offset` (taken straight from\n * `HTMLInputElement.selectionStart` / `selectionEnd`) so a\n * round-trip `select_text` command can reproduce the exact range.\n */\nexport interface A11ySelection {\n  /**\n   * Ref of the element that carries the selection. For document\n   * selections this is the closest common-ancestor element with a\n   * ref; for input/textarea it is the input element itself.\n   */\n  ref: string;\n  /**\n   * The selected text. Truncated at 2000 characters with a trailing\n   * ellipsis to keep `<ui_state>` injections bounded.\n   */\n  text: string;\n  /**\n   * Character offset within the input's `value` where the\n   * selection starts. Only set for `<input>` and `<textarea>`.\n   */\n  start_offset?: number;\n  /**\n   * Character offset within the input's `value` where the\n   * selection ends. Only set for `<input>` and `<textarea>`.\n   */\n  end_offset?: number;\n}\n\n/**\n * Accessibility tree carried inside a first-class `ui-snapshot` RTVI\n * message.\n *\n * `PipecatClient.startUISnapshotStream(...)` sends snapshots with the\n * message data shape `{ tree: A11ySnapshot }`. A full tree is sent on\n * each update; the server keeps the latest and renders it into\n * `<ui_state>...</ui_state>` when a worker injects it.\n */\nexport interface A11ySnapshot {\n  /** The root of the accessibility tree (usually `document.body`'s node). */\n  root: A11yNode;\n  /** Client-side timestamp (ms since epoch) when the snapshot was taken. */\n  captured_at: number;\n  /**\n   * The user's current text selection, when one exists. Omitted when\n   * nothing is selected (or the selection is collapsed to a single\n   * cursor position with no characters in between). The server\n   * renders this as a `<selection ref=\"...\">...</selection>` block\n   * inside `<ui_state>`.\n   */\n  selection?: A11ySelection;\n}\n","/**\n * Copyright (c) 2026, Daily.\n *\n * SPDX-License-Identifier: BSD-2-Clause\n */\n\n/**\n * Framework-agnostic walker that produces an accessibility snapshot\n * from a DOM subtree. Pure browser APIs (no React, no framework\n * dependencies), so it works from any vanilla-JS runtime that has a\n * `document`.\n *\n * Shape and filtering inspired by Playwright's accessibility snapshot\n * and the Playwright MCP server's LLM-facing format. The goal is a\n * compact, semantically meaningful tree the server can render as\n * `<ui_state>` for LLM context, not a raw DOM dump.\n *\n * Viewport awareness: when `trackViewport` is enabled (default),\n * every emitted node that's fully outside the viewport rect gets\n * `\"offscreen\"` in its `state` list. The worker reads this to\n * distinguish \"on the page\" from \"what the user is currently\n * looking at\" and can decide whether to `ScrollTo` before acting.\n * Computing this calls `getBoundingClientRect` per node, which\n * forces layout once for the walk (~1ms for typical pages).\n */\n\nimport type { A11yNode, A11ySelection, A11ySnapshot } from \"../rtvi/ui\";\n\n// ---------------------------------------------------------------------------\n// Tunables\n// ---------------------------------------------------------------------------\n\nconst MAX_DEPTH = 10;\nconst MAX_NODES = 200;\nconst MAX_CHILDREN_PER_NODE = 50;\nconst NAME_MAX = 100;\n// Tighter cap on emitted `<option>` children. Country / state pickers\n// can have hundreds of entries; truncating at 20 keeps the snapshot\n// useful without ballooning LLM context.\nconst MAX_SELECT_OPTIONS = 20;\n// Selections benefit from preserving paragraph structure, but the worker\n// only needs enough text to disambiguate the referent. 2000 chars is\n// roughly 500 tokens — meaningful context without dominating the\n// `<ui_state>` injection.\nconst SELECTION_TEXT_MAX = 2000;\n\n// ---------------------------------------------------------------------------\n// Ref registry: stable `e{N}` IDs per DOM node, persist as long as the\n// node is mounted. WeakMap keeps us from leaking detached nodes.\n// ---------------------------------------------------------------------------\n\nconst refMap = new WeakMap<Element, string>();\n// Reverse index from ref string back to element, so command handlers\n// (e.g. `scroll_to`) can resolve a server-supplied ref like\n// `\"e42\"` back to a live DOM node. Prefer `WeakRef` so entries\n// can become stale after unmount, but fall back to a strong reference\n// in older browsers / embedded webviews that do not implement it.\ntype RefEntry = WeakRef<Element> | Element;\nconst WeakRefCtor: (new (target: Element) => WeakRef<Element>) | undefined =\n  typeof WeakRef === \"undefined\" ? undefined : WeakRef;\nconst refToElement = new Map<string, RefEntry>();\nlet refCounter = 0;\n\nfunction getRef(el: Element): string {\n  const existing = refMap.get(el);\n  if (existing) return existing;\n  const ref = `e${++refCounter}`;\n  refMap.set(el, ref);\n  refToElement.set(ref, WeakRefCtor ? new WeakRefCtor(el) : el);\n  return ref;\n}\n\n/**\n * Resolve a ref string like `\"e42\"` back to a live DOM element.\n * Returns `null` if the ref was never assigned or the element has\n * since been garbage-collected. Command handlers use this to\n * act on nodes the server referenced from a snapshot.\n */\nexport function findElementByRef(ref: string): Element | null {\n  const entry = refToElement.get(ref);\n  if (!entry) return null;\n  const el = \"deref\" in entry ? entry.deref() : entry;\n  if (!el) {\n    refToElement.delete(ref);\n    return null;\n  }\n  if (!el.isConnected) {\n    refToElement.delete(ref);\n    return null;\n  }\n  return el;\n}\n\n/**\n * Inverse of `findElementByRef`: return the snapshot ref the walker\n * has assigned to `el`, if any. Returns `null` for elements the\n * walker has not yet visited (refs are assigned during snapshot\n * walking; an element only has a ref if it appeared in a previous\n * snapshot).\n *\n * Useful when an app needs to associate a user interaction (e.g.\n * the current text selection, a click on a non-tracked element) with\n * a snapshot-known node. Walk up `el.parentElement` looking for the\n * first ancestor that has a ref to find the closest snapshot-known\n * container.\n */\nexport function findRefForElement(el: Element): string | null {\n  return refMap.get(el) ?? null;\n}\n\n/** Reset the ref counter and registry. Test-only helper. */\nexport function __resetRefsForTesting(): void {\n  refCounter = 0;\n  refToElement.clear();\n}\n\n// ---------------------------------------------------------------------------\n// Inclusion / exclusion\n// ---------------------------------------------------------------------------\n\nconst EXCLUDED_TAGS = new Set([\n  \"script\",\n  \"style\",\n  \"link\",\n  \"meta\",\n  \"noscript\",\n  \"template\",\n]);\n\nfunction isExcluded(el: Element): boolean {\n  if (EXCLUDED_TAGS.has(el.tagName.toLowerCase())) return true;\n  if (el.getAttribute(\"aria-hidden\") === \"true\") return true;\n  // Explicit app-level opt-out for PII / sensitive subtrees. Skips the\n  // element and its descendants entirely, without needing to also\n  // hide it from screen readers (unlike aria-hidden).\n  if (el.hasAttribute(\"data-a11y-exclude\")) return true;\n  if ((el as HTMLElement).hidden) return true;\n  // offsetParent == null is a fast-ish check for display:none for most\n  // elements (doesn't catch position:fixed hidden or visibility:hidden,\n  // but catches the common case). Full getComputedStyle is ~10x slower\n  // and we're running on every mutation.\n  if (el instanceof HTMLElement && el.offsetParent === null && el.tagName !== \"BODY\") {\n    // One false positive: position: fixed with display: block looks\n    // like offsetParent=null but is still visible. Fall back to\n    // getComputedStyle only for those.\n    const style = window.getComputedStyle(el);\n    if (style.display === \"none\" || style.visibility === \"hidden\") return true;\n    // If fixed/sticky and rendered, let it through.\n  }\n  return false;\n}\n\n// ---------------------------------------------------------------------------\n// Role derivation\n// ---------------------------------------------------------------------------\n\nconst INTERACTIVE_ROLES = new Set([\n  \"button\",\n  \"link\",\n  \"checkbox\",\n  \"radio\",\n  \"textbox\",\n  \"combobox\",\n  \"switch\",\n  \"menuitem\",\n  \"tab\",\n]);\n\nconst LEAF_ROLES = new Set([...INTERACTIVE_ROLES, \"heading\", \"img\"]);\n\nfunction hasAccessibleName(el: Element): boolean {\n  if (el.hasAttribute(\"aria-label\")) return true;\n  if (el.hasAttribute(\"aria-labelledby\")) return true;\n  if ((el.textContent ?? \"\").trim().length > 0) return true;\n  return false;\n}\n\n/**\n * Derive an ARIA-style role for an element. Returns `null` if the\n * element is a \"pure wrapper\" (no semantic value on its own); the\n * walker will flatten its children into the parent's list rather than\n * emitting a node.\n */\nfunction getRole(el: Element): string | null {\n  const explicit = el.getAttribute(\"role\");\n  if (explicit) return explicit;\n\n  const tag = el.tagName.toLowerCase();\n  switch (tag) {\n    case \"main\":\n    case \"nav\":\n    case \"header\":\n    case \"aside\":\n    case \"footer\":\n      return tag;\n    case \"article\":\n    case \"section\":\n      return hasAccessibleName(el) ? \"region\" : null;\n    case \"h1\":\n    case \"h2\":\n    case \"h3\":\n    case \"h4\":\n    case \"h5\":\n    case \"h6\":\n      return \"heading\";\n    case \"a\":\n      return el.hasAttribute(\"href\") ? \"link\" : null;\n    case \"button\":\n      return \"button\";\n    case \"input\": {\n      const type = (el as HTMLInputElement).type;\n      if (type === \"checkbox\") return \"checkbox\";\n      if (type === \"radio\") return \"radio\";\n      if (type === \"submit\" || type === \"button\" || type === \"reset\") return \"button\";\n      if (type === \"hidden\") return null;\n      return \"textbox\";\n    }\n    case \"select\":\n      return \"combobox\";\n    case \"textarea\":\n      return \"textbox\";\n    case \"label\":\n      return null; // consumed by its associated input\n    case \"img\":\n      return el.getAttribute(\"alt\") !== null ? \"img\" : null;\n    case \"p\":\n      // Promote prose containers so paragraph-level deixis works:\n      // selection anchors at the enclosing paragraph, and the worker\n      // can address individual paragraphs by ref for select_text /\n      // scroll_to / highlight. Pure-wrapper flattening would lose\n      // both. Paragraphs are walked as non-leaf so inline links and\n      // emphasis still nest underneath.\n      return \"paragraph\";\n    case \"ul\":\n    case \"ol\":\n      return \"list\";\n    case \"li\":\n      return \"listitem\";\n    case \"table\":\n      return \"table\";\n    case \"tr\":\n      return \"row\";\n    case \"th\":\n      return \"columnheader\";\n    case \"td\":\n      return \"cell\";\n    default: {\n      // Promote anonymous containers that carry aria/tabindex/click.\n      if (\n        el.hasAttribute(\"aria-label\") ||\n        el.hasAttribute(\"aria-labelledby\") ||\n        el.hasAttribute(\"tabindex\")\n      ) {\n        return \"generic\";\n      }\n      return null;\n    }\n  }\n}\n\n// ---------------------------------------------------------------------------\n// Name / value / state / level\n// ---------------------------------------------------------------------------\n\nfunction collapseWhitespace(s: string): string {\n  return s.replace(/\\s+/g, \" \").trim();\n}\n\nfunction truncate(s: string, max = NAME_MAX): string {\n  const collapsed = collapseWhitespace(s);\n  if (collapsed.length <= max) return collapsed;\n  return collapsed.slice(0, max - 1) + \"…\";\n}\n\nfunction resolveLabelledBy(el: Element): string | undefined {\n  const ids = el.getAttribute(\"aria-labelledby\");\n  if (!ids) return undefined;\n  const parts: string[] = [];\n  for (const id of ids.split(/\\s+/)) {\n    if (!id) continue;\n    const target = el.ownerDocument.getElementById(id);\n    if (target) parts.push(collectAccessibleText(target));\n  }\n  const joined = parts.filter(Boolean).join(\" \");\n  return joined || undefined;\n}\n\n/**\n * Collect the accessible text content of an element by walking its\n * descendant text nodes and joining them with a single space across\n * element boundaries. This fixes the common case where a button\n * contains multiple `<span>` children whose text would otherwise\n * concatenate without a separator (`textContent` returns\n * `\"FooBar\"` for `<span>Foo</span><span>Bar</span>`).\n *\n * Skips aria-hidden and `EXCLUDED_TAGS` descendants.\n */\nfunction collectAccessibleText(el: Element): string {\n  const parts: string[] = [];\n  for (let i = 0; i < el.childNodes.length; i++) {\n    const child = el.childNodes[i];\n    if (child.nodeType === 3 /* TEXT_NODE */) {\n      const t = (child.textContent ?? \"\").trim();\n      if (t) parts.push(t);\n    } else if (child.nodeType === 1 /* ELEMENT_NODE */) {\n      const childEl = child as Element;\n      if (EXCLUDED_TAGS.has(childEl.tagName.toLowerCase())) continue;\n      if (childEl.getAttribute(\"aria-hidden\") === \"true\") continue;\n      const sub = collectAccessibleText(childEl);\n      if (sub) parts.push(sub);\n    }\n  }\n  return parts.join(\" \").replace(/\\s+/g, \" \").trim();\n}\n\nfunction getName(el: Element, role: string): string | undefined {\n  const ariaLabel = el.getAttribute(\"aria-label\");\n  if (ariaLabel) return truncate(ariaLabel);\n\n  const labelled = resolveLabelledBy(el);\n  if (labelled) return truncate(labelled);\n\n  const tag = el.tagName.toLowerCase();\n\n  // Form controls: prefer associated <label>.\n  if (tag === \"input\" || tag === \"textarea\" || tag === \"select\") {\n    const id = el.getAttribute(\"id\");\n    if (id) {\n      // Iterate labels rather than using a CSS attribute selector so we\n      // avoid needing CSS.escape (which isn't available in jsdom).\n      const labels = el.ownerDocument.getElementsByTagName(\"label\");\n      for (let i = 0; i < labels.length; i++) {\n        if (labels[i].htmlFor === id && labels[i].textContent) {\n          return truncate(labels[i].textContent ?? \"\");\n        }\n      }\n    }\n    const wrappingLabel = el.closest(\"label\");\n    if (wrappingLabel?.textContent) return truncate(wrappingLabel.textContent);\n    // Fall back to placeholder for inputs.\n    const placeholder = el.getAttribute(\"placeholder\");\n    if (placeholder) return truncate(placeholder);\n    return undefined;\n  }\n\n  // img: alt text.\n  if (tag === \"img\") {\n    const alt = el.getAttribute(\"alt\");\n    return alt ? truncate(alt) : undefined;\n  }\n\n  // Leaf interactive / heading / link roles, plus paragraphs, use\n  // text from descendants. Paragraphs aren't leaves (they may carry\n  // nested links / emphasis) but we want the prose preview as the\n  // node's name so the LLM has the gist without expanding text\n  // children. `collectAccessibleText` joins sibling children with\n  // spaces so `<span>Foo</span><span>Bar</span>` yields `\"Foo Bar\"`\n  // rather than `\"FooBar\"`.\n  if (LEAF_ROLES.has(role) || role === \"paragraph\") {\n    const text = collectAccessibleText(el);\n    return text ? truncate(text) : undefined;\n  }\n\n  return undefined;\n}\n\nfunction getValue(el: Element): string | undefined {\n  if (el instanceof HTMLInputElement) {\n    if (el.type === \"password\") return undefined;\n    if (el.type === \"checkbox\" || el.type === \"radio\" || el.type === \"hidden\") return undefined;\n    return el.value || undefined;\n  }\n  if (el instanceof HTMLTextAreaElement) {\n    return el.value || undefined;\n  }\n  if (el instanceof HTMLSelectElement) {\n    // Prefer the selected option's visible text; the raw `value` is\n    // often a numeric id or sentinel that means nothing to a reader.\n    const selected = el.selectedOptions[0];\n    const text = selected?.text?.trim();\n    if (text) return text;\n    return el.value || undefined;\n  }\n  return undefined;\n}\n\nfunction getState(el: Element): string[] {\n  const state: string[] = [];\n  if (el.ownerDocument.activeElement === el) state.push(\"focused\");\n  if (el.getAttribute(\"aria-expanded\") === \"true\") state.push(\"expanded\");\n  if (el.getAttribute(\"aria-selected\") === \"true\") state.push(\"selected\");\n  if (el.hasAttribute(\"disabled\") || el.getAttribute(\"aria-disabled\") === \"true\") {\n    state.push(\"disabled\");\n  }\n  const ariaChecked = el.getAttribute(\"aria-checked\");\n  if (ariaChecked === \"true\") state.push(\"checked\");\n  if (el instanceof HTMLInputElement) {\n    if ((el.type === \"checkbox\" || el.type === \"radio\") && el.checked) {\n      if (!state.includes(\"checked\")) state.push(\"checked\");\n    }\n  }\n  return state;\n}\n\n/**\n * Return `true` when the element's bounding rect does not\n * intersect the current viewport at all. Any intersection, even\n * partial, counts as visible (matches user intuition). Elements\n * with zero-size rects (`width === 0 && height === 0`) are\n * treated as offscreen.\n */\nfunction isOffscreen(el: Element): boolean {\n  const rect = el.getBoundingClientRect();\n  if (rect.width === 0 && rect.height === 0) return true;\n  const viewportWidth = window.innerWidth || document.documentElement.clientWidth;\n  const viewportHeight = window.innerHeight || document.documentElement.clientHeight;\n  if (rect.bottom <= 0) return true;\n  if (rect.top >= viewportHeight) return true;\n  if (rect.right <= 0) return true;\n  if (rect.left >= viewportWidth) return true;\n  return false;\n}\n\nfunction getLevel(el: Element, role: string): number | undefined {\n  if (role !== \"heading\") return undefined;\n  const tag = el.tagName.toLowerCase();\n  const m = tag.match(/^h([1-6])$/);\n  if (m) return parseInt(m[1], 10);\n  const aria = el.getAttribute(\"aria-level\");\n  if (aria) {\n    const parsed = parseInt(aria, 10);\n    if (!Number.isNaN(parsed)) return parsed;\n  }\n  return undefined;\n}\n\nfunction getAriaIntAttr(el: Element, name: string): number | undefined {\n  const raw = el.getAttribute(name);\n  if (!raw) return undefined;\n  const parsed = parseInt(raw, 10);\n  if (Number.isNaN(parsed) || parsed < 0) return undefined;\n  return parsed;\n}\n\n// ---------------------------------------------------------------------------\n// Walker\n// ---------------------------------------------------------------------------\n\ninterface Budget {\n  count: number;\n}\n\ninterface WalkOptions {\n  trackViewport: boolean;\n}\n\nfunction walk(\n  el: Element,\n  depth: number,\n  budget: Budget,\n  opts: WalkOptions,\n  inheritSkipTextNodes = false,\n): A11yNode[] {\n  if (isExcluded(el)) return [];\n  if (budget.count >= MAX_NODES) return [];\n\n  if (depth > MAX_DEPTH) {\n    budget.count++;\n    return [\n      {\n        ref: getRef(el),\n        role: \"ellipsis\",\n        name: \"<truncated: max depth>\",\n      },\n    ];\n  }\n\n  const role = getRole(el);\n\n  if (role === null) {\n    // Pure wrapper: inline children into the parent's child list.\n    // Inherit the caller's text-skip flag so e.g. a <span> inside a\n    // <p> doesn't leak its text as a duplicate text-role node.\n    return walkChildren(el, depth, budget, opts, {\n      skipTextNodes: inheritSkipTextNodes,\n    });\n  }\n\n  budget.count++;\n\n  const node: A11yNode = { ref: getRef(el), role };\n  const name = getName(el, role);\n  if (name) node.name = name;\n  const value = getValue(el);\n  if (value !== undefined) node.value = value;\n  const state = getState(el);\n  if (opts.trackViewport && isOffscreen(el)) state.push(\"offscreen\");\n  if (state.length) node.state = state;\n  const level = getLevel(el, role);\n  if (level !== undefined) node.level = level;\n  const colcount = getAriaIntAttr(el, \"aria-colcount\");\n  if (colcount !== undefined) node.colcount = colcount;\n  const rowcount = getAriaIntAttr(el, \"aria-rowcount\");\n  if (rowcount !== undefined) node.rowcount = rowcount;\n\n  if (!LEAF_ROLES.has(role)) {\n    // For paragraphs the text content is already in the node's\n    // `name`. Skip raw text-node children so the same prose\n    // doesn't appear twice in `<ui_state>`.\n    const skipTextNodes = role === \"paragraph\";\n    const children = walkChildren(el, depth + 1, budget, opts, { skipTextNodes });\n    if (children.length > 0) {\n      if (children.length > MAX_CHILDREN_PER_NODE) {\n        const kept = children.slice(0, MAX_CHILDREN_PER_NODE);\n        kept.push({\n          ref: `${node.ref}.more`,\n          role: \"ellipsis\",\n          name: `${children.length - MAX_CHILDREN_PER_NODE} more`,\n        });\n        node.children = kept;\n      } else {\n        node.children = children;\n      }\n    }\n  } else if (el instanceof HTMLSelectElement) {\n    // Combobox is a leaf role, but for native `<select>` we synthesize\n    // `option` children so the worker can see all available choices,\n    // not just the one currently selected. Without this, an LLM has no\n    // way to know what other values it could ask the user to pick.\n    const options = collectSelectOptions(el, budget, node.ref);\n    if (options.length > 0) node.children = options;\n  }\n\n  return [node];\n}\n\nfunction collectSelectOptions(\n  select: HTMLSelectElement,\n  budget: Budget,\n  parentRef: string,\n): A11yNode[] {\n  const out: A11yNode[] = [];\n  const all = select.options;\n  let emitted = 0;\n  for (let i = 0; i < all.length; i++) {\n    if (budget.count >= MAX_NODES) break;\n    const opt = all[i];\n    if (opt.hidden) continue;\n    if (opt.getAttribute(\"aria-hidden\") === \"true\") continue;\n    if (emitted >= MAX_SELECT_OPTIONS) {\n      budget.count++;\n      out.push({\n        ref: `${parentRef}.more`,\n        role: \"ellipsis\",\n        name: `${all.length - emitted} more`,\n      });\n      break;\n    }\n    budget.count++;\n    emitted++;\n    const text = (opt.text || opt.value || \"\").trim();\n    const optNode: A11yNode = {\n      ref: getRef(opt),\n      role: \"option\",\n      name: truncate(text),\n    };\n    const state: string[] = [];\n    if (opt.selected) state.push(\"selected\");\n    if (opt.disabled) state.push(\"disabled\");\n    if (state.length) optNode.state = state;\n    out.push(optNode);\n  }\n  return out;\n}\n\ninterface WalkChildrenOptions {\n  /**\n   * When `true`, raw text-node children are not emitted. Used by\n   * `paragraph` whose `name` already carries the prose; emitting\n   * the same text again as `- text \"...\"` children would duplicate\n   * it in `<ui_state>`.\n   */\n  skipTextNodes?: boolean;\n}\n\nfunction walkChildren(\n  el: Element,\n  depth: number,\n  budget: Budget,\n  opts: WalkOptions,\n  childOpts: WalkChildrenOptions = {},\n): A11yNode[] {\n  const out: A11yNode[] = [];\n  // Iterate `childNodes` rather than `children` so we pick up\n  // direct text nodes too (e.g. track titles sitting in a pure-wrapper\n  // `<div>` next to a Play button). Without this, wrapper divs that\n  // carry meaningful text lose it entirely when they get flattened.\n  for (let i = 0; i < el.childNodes.length; i++) {\n    const child = el.childNodes[i];\n    if (child.nodeType === 3 /* TEXT_NODE */) {\n      if (childOpts.skipTextNodes) continue;\n      const text = collapseWhitespace(child.textContent ?? \"\");\n      if (text) {\n        if (budget.count >= MAX_NODES) break;\n        budget.count++;\n        out.push({ ref: \"\", role: \"text\", name: truncate(text) });\n      }\n    } else if (child.nodeType === 1 /* ELEMENT_NODE */) {\n      const nodes = walk(\n        child as Element,\n        depth,\n        budget,\n        opts,\n        childOpts.skipTextNodes,\n      );\n      for (const n of nodes) out.push(n);\n      if (budget.count >= MAX_NODES) break;\n    }\n  }\n  return out;\n}\n\n// ---------------------------------------------------------------------------\n// Selection\n// ---------------------------------------------------------------------------\n\n/**\n * Look up a ref for `el` without assigning a new one.\n *\n * Selections frequently land on text nodes whose closest element\n * ancestor is a structural tag like `<p>` or `<span>` that the\n * walker treats as a pure wrapper and so doesn't ref. Climb the\n * ancestor chain until we find a walked element.\n *\n * Returns `null` when an `aria-hidden=\"true\"` or\n * `data-a11y-exclude` ancestor is encountered before any\n * ref-bearing element, so selections inside subtrees the app has\n * explicitly hidden from accessibility don't leak into the snapshot.\n */\nfunction findRefBearingAncestor(start: Element | null): Element | null {\n  let el: Element | null = start;\n  while (el) {\n    if (\n      el.getAttribute(\"aria-hidden\") === \"true\" ||\n      el.hasAttribute(\"data-a11y-exclude\")\n    ) {\n      return null;\n    }\n    if (refMap.has(el)) return el;\n    el = el.parentElement;\n  }\n  return null;\n}\n\nfunction clampSelectionText(text: string): string {\n  if (text.length <= SELECTION_TEXT_MAX) return text;\n  return text.slice(0, SELECTION_TEXT_MAX - 1) + \"…\";\n}\n\n/**\n * Capture the user's current text selection as an `A11ySelection`.\n *\n * Returns `null` when nothing is selected, the selection is\n * collapsed (a bare cursor position), or no ancestor of the\n * selection has been assigned a ref by the walker (e.g. selection\n * landed entirely inside an `aria-hidden` subtree).\n *\n * Input/textarea takes precedence over the document selection\n * because `window.getSelection().toString()` is empty for those\n * elements; we read `selectionStart` / `selectionEnd` directly\n * and surface them as offsets so a round-trip `select_text`\n * command can reproduce the range.\n */\nexport function serializeSelection(): A11ySelection | null {\n  if (typeof document === \"undefined\") return null;\n\n  // Input / textarea: own selection model, distinct from\n  // `window.getSelection()`.\n  const active = document.activeElement;\n  if (active instanceof HTMLInputElement || active instanceof HTMLTextAreaElement) {\n    const start = active.selectionStart;\n    const end = active.selectionEnd;\n    if (start !== null && end !== null && start !== end) {\n      const ref = refMap.get(active);\n      if (!ref) return null;\n      const text = active.value.slice(start, end);\n      if (!text) return null;\n      return {\n        ref,\n        text: clampSelectionText(text),\n        start_offset: start,\n        end_offset: end,\n      };\n    }\n  }\n\n  // Document selection.\n  const sel = document.getSelection();\n  if (!sel || sel.rangeCount === 0 || sel.isCollapsed) return null;\n  const text = sel.toString();\n  if (!text) return null;\n\n  const range = sel.getRangeAt(0);\n  let common: Node | null = range.commonAncestorContainer;\n  // Climb to the nearest element node first.\n  while (common && common.nodeType !== 1 /* ELEMENT_NODE */) {\n    common = common.parentNode;\n  }\n  const anchor = findRefBearingAncestor(common as Element | null);\n  if (!anchor) return null;\n  const ref = refMap.get(anchor);\n  if (!ref) return null;\n\n  return {\n    ref,\n    text: clampSelectionText(text),\n  };\n}\n\n// ---------------------------------------------------------------------------\n// Walker entry point\n// ---------------------------------------------------------------------------\n\nexport interface SnapshotOptions {\n  /**\n   * When `true` (default), each emitted node gets `\"offscreen\"`\n   * in its state list if its bounding rect sits entirely outside the\n   * viewport. Set to `false` to skip the per-node layout\n   * measurement (e.g. on very large pages where layout cost\n   * outweighs the viewport signal).\n   */\n  trackViewport?: boolean;\n}\n\n/**\n * Produce an accessibility snapshot of a DOM subtree.\n *\n * @param root - Element to walk. Defaults to `document.body`.\n * @param options - Snapshot options; see `SnapshotOptions`.\n * @returns Snapshot with a `generic` root containing the walked\n *     children, plus a client-side capture timestamp.\n */\nexport function snapshotDocument(\n  root?: Element,\n  options: SnapshotOptions = {},\n): A11ySnapshot {\n  const el = root ?? (typeof document !== \"undefined\" ? document.body : null);\n  if (!el) {\n    return {\n      root: { ref: \"e0\", role: \"generic\" },\n      captured_at: Date.now(),\n    };\n  }\n  const opts: WalkOptions = { trackViewport: options.trackViewport ?? true };\n  const budget: Budget = { count: 0 };\n  const children = walkChildren(el, 0, budget, opts);\n  // Capture selection after the walk so refs are populated for\n  // anything visible on the page.\n  const selection = serializeSelection();\n  return {\n    root: {\n      ref: getRef(el),\n      role: \"generic\",\n      ...(children.length > 0 ? { children } : {}),\n    },\n    captured_at: Date.now(),\n    ...(selection ? { selection } : {}),\n  };\n}\n","/**\n * Copyright (c) 2026, Daily.\n *\n * SPDX-License-Identifier: BSD-2-Clause\n */\n\n/**\n * Framework-agnostic helper that drives accessibility-snapshot\n * streaming. Wraps the walker, a `MutationObserver`, and the other\n * triggers (scrollend, resize, focus, visibilitychange) into a single\n * object with `start()` / `stop()`. React apps use\n * `useUISnapshot` which is a thin wrapper around this; vanilla JS\n * or non-React apps instantiate the class directly.\n */\n\nimport { snapshotDocument } from \"../rtvi/a11y_walker\";\nimport type { A11ySnapshot } from \"../rtvi/ui\";\n\n/** Options for `A11ySnapshotStreamer`. */\nexport interface A11ySnapshotStreamerOptions {\n  /**\n   * Minimum interval between snapshot emissions, in milliseconds.\n   * Multiple mutations within the window coalesce into one snapshot.\n   *\n   * @default 300\n   */\n  debounceMs?: number;\n  /**\n   * When `true` (default), annotate every emitted node with\n   * `\"offscreen\"` in its state list if its bounding rect sits\n   * entirely outside the viewport. Set to `false` to skip the\n   * per-node layout measurement.\n   *\n   * @default true\n   */\n  trackViewport?: boolean;\n  /**\n   * When `true`, log each emitted snapshot to the browser console\n   * (node count, rough token estimate, raw tree). Mirrors the\n   * server's `log_snapshots` flag on `UIWorker`.\n   *\n   * @default false\n   */\n  logSnapshots?: boolean;\n}\n\n/**\n * Stream accessibility snapshots through an emit callback on DOM\n * mutations, focus changes, scroll-end, resize, and visibility\n * change. Fires an initial snapshot shortly after `start()`.\n *\n * Usage (vanilla JS / any framework)::\n *\n *     const streamer = new A11ySnapshotStreamer((snapshot) => {\n *       // Send or persist the snapshot.\n *     });\n *     streamer.start();\n *     // ...later\n *     streamer.stop();\n *\n * In React, `useUISnapshot` handles lifecycle for you.\n *\n * Idempotent: calling `start()` twice is safe; `stop()` detaches\n * all observers/listeners and cancels pending timers.\n */\nexport type A11ySnapshotEmitter = (snapshot: A11ySnapshot) => void;\n\nexport class A11ySnapshotStreamer {\n  private emitSnapshot: A11ySnapshotEmitter;\n  private debounceMs: number;\n  private trackViewport: boolean;\n  private logSnapshots: boolean;\n\n  private running = false;\n  private timer: ReturnType<typeof setTimeout> | undefined;\n  private observer: MutationObserver | undefined;\n  private focusHandler?: () => void;\n  private scrollEndHandler?: () => void;\n  private resizeHandler?: () => void;\n  private visibilityHandler?: () => void;\n  private selectionHandler?: () => void;\n  private formHandler?: () => void;\n\n  constructor(\n    emitSnapshot: A11ySnapshotEmitter,\n    options: A11ySnapshotStreamerOptions = {}\n  ) {\n    this.emitSnapshot = emitSnapshot;\n    this.debounceMs = options.debounceMs ?? 300;\n    this.trackViewport = options.trackViewport ?? true;\n    this.logSnapshots = options.logSnapshots ?? false;\n  }\n\n  /**\n   * Begin streaming. Safe to call multiple times; subsequent calls\n   * are no-ops until `stop()` runs.\n   */\n  start(): void {\n    if (this.running) return;\n    if (typeof document === \"undefined\") return;\n    this.running = true;\n\n    // Prime with an initial snapshot once the caller has had a chance\n    // to mount the UI.\n    this.schedule();\n\n    this.observer = new MutationObserver(() => this.schedule());\n    this.observer.observe(document.body, {\n      childList: true,\n      subtree: true,\n      attributes: true,\n      attributeFilter: [\n        \"role\",\n        \"aria-label\",\n        \"aria-labelledby\",\n        \"aria-expanded\",\n        \"aria-selected\",\n        \"aria-checked\",\n        \"aria-disabled\",\n        \"aria-level\",\n        \"aria-hidden\",\n        \"aria-colcount\",\n        \"aria-rowcount\",\n        \"data-a11y-exclude\",\n        \"disabled\",\n        \"hidden\",\n        \"tabindex\",\n        \"href\",\n      ],\n    });\n\n    this.focusHandler = () => this.schedule();\n    document.addEventListener(\"focusin\", this.focusHandler);\n    document.addEventListener(\"focusout\", this.focusHandler);\n\n    // Scrollend fires once when a scroll gesture settles - no\n    // debounce needed, and firing at rest avoids fighting the\n    // browser's animation frames. `capture: true` catches scroll\n    // on any scrollable ancestor, not just the window.\n    this.scrollEndHandler = () => this.schedule();\n    window.addEventListener(\"scrollend\", this.scrollEndHandler, { capture: true });\n\n    // Resize changes the viewport rect, which shifts which nodes are\n    // `[offscreen]`. Debounced via `schedule` so a drag-resize\n    // doesn't thrash.\n    this.resizeHandler = () => this.schedule();\n    window.addEventListener(\"resize\", this.resizeHandler);\n\n    // Refresh state when the tab becomes visible again; ignore the\n    // transition into `hidden`.\n    this.visibilityHandler = () => {\n      if (document.visibilityState === \"visible\") this.schedule();\n    };\n    document.addEventListener(\"visibilitychange\", this.visibilityHandler);\n\n    // `selectionchange` fires throughout a drag-select; the existing\n    // debounce coalesces the burst into a single snapshot once the\n    // user stops moving. Snapshots end up carrying the latest\n    // selection alongside the rest of the screen state.\n    this.selectionHandler = () => this.schedule();\n    document.addEventListener(\"selectionchange\", this.selectionHandler);\n\n    // Native form controls (checkbox/radio toggles, text and select edits)\n    // change via element PROPERTIES, which a MutationObserver can't see - the\n    // attributeFilter above only catches them when an app mirrors state into\n    // aria-*. Listen for `input`/`change` in the capture phase so a user edit\n    // (or a programmatic change that dispatches these events) refreshes the\n    // snapshot. Debounced via `schedule`, so a burst of typing coalesces into\n    // a single snapshot at rest.\n    this.formHandler = () => this.schedule();\n    document.addEventListener(\"input\", this.formHandler, { capture: true });\n    document.addEventListener(\"change\", this.formHandler, { capture: true });\n  }\n\n  /** Stop streaming. Safe to call before `start()` or multiple times. */\n  stop(): void {\n    if (!this.running) return;\n    this.running = false;\n\n    if (this.timer !== undefined) {\n      clearTimeout(this.timer);\n      this.timer = undefined;\n    }\n    if (this.observer) {\n      this.observer.disconnect();\n      this.observer = undefined;\n    }\n    if (typeof document !== \"undefined\") {\n      if (this.focusHandler) {\n        document.removeEventListener(\"focusin\", this.focusHandler);\n        document.removeEventListener(\"focusout\", this.focusHandler);\n      }\n      if (this.visibilityHandler) {\n        document.removeEventListener(\"visibilitychange\", this.visibilityHandler);\n      }\n      if (this.selectionHandler) {\n        document.removeEventListener(\"selectionchange\", this.selectionHandler);\n      }\n      if (this.formHandler) {\n        document.removeEventListener(\"input\", this.formHandler, {\n          capture: true,\n        });\n        document.removeEventListener(\"change\", this.formHandler, {\n          capture: true,\n        });\n      }\n    }\n    if (typeof window !== \"undefined\") {\n      if (this.scrollEndHandler) {\n        window.removeEventListener(\"scrollend\", this.scrollEndHandler, {\n          capture: true,\n        });\n      }\n      if (this.resizeHandler) {\n        window.removeEventListener(\"resize\", this.resizeHandler);\n      }\n    }\n    this.focusHandler = undefined;\n    this.scrollEndHandler = undefined;\n    this.resizeHandler = undefined;\n    this.visibilityHandler = undefined;\n    this.selectionHandler = undefined;\n    this.formHandler = undefined;\n  }\n\n  private schedule(): void {\n    if (!this.running) return;\n    if (this.timer !== undefined) clearTimeout(this.timer);\n    this.timer = setTimeout(() => this.emit(), this.debounceMs);\n  }\n\n  private emit(): void {\n    this.timer = undefined;\n    if (!this.running) return;\n    try {\n      const snapshot = snapshotDocument(undefined, {\n        trackViewport: this.trackViewport,\n      });\n      this.emitSnapshot(snapshot);\n      if (this.logSnapshots) {\n        const nodeCount = countNodes(snapshot.root);\n        const estTokens = Math.round(JSON.stringify(snapshot).length / 4);\n        // Grouped so it collapses cleanly in DevTools. The raw tree\n        // is included last so it can be expanded on demand.\n        console.groupCollapsed(\n          `[A11ySnapshotStreamer] emit: ${nodeCount} nodes, ~${estTokens} tokens`,\n        );\n        console.log(\"snapshot:\", snapshot);\n        console.groupEnd();\n      }\n    } catch {\n      // Swallow walker errors so we don't crash the host app from a\n      // background snapshot attempt. The browser's default error\n      // reporting still surfaces them in DevTools.\n    }\n  }\n}\n\nfunction countNodes(node: { children?: { children?: unknown[] }[] }): number {\n  let count = 1;\n  const kids = (node as { children?: Array<{ children?: unknown[] }> }).children;\n  if (kids) {\n    for (const child of kids) {\n      count += countNodes(child as Parameters<typeof countNodes>[0]);\n    }\n  }\n  return count;\n}\n","export type TransportState =\n  | \"disconnected\"\n  | \"initializing\"\n  | \"initialized\"\n  | \"authenticating\"\n  | \"authenticated\"\n  | \"connecting\"\n  | \"connected\"\n  | \"ready\"\n  | \"disconnecting\"\n  | \"error\";\n\nexport enum TransportStateEnum {\n  DISCONNECTED = \"disconnected\",\n  INITIALIZING = \"initializing\",\n  INITIALIZED = \"initialized\",\n  AUTHENTICATING = \"authenticating\",\n  AUTHENTICATED = \"authenticated\",\n  CONNECTING = \"connecting\",\n  CONNECTED = \"connected\",\n  READY = \"ready\",\n  DISCONNECTING = \"disconnecting\",\n  ERROR = \"error\",\n}\n\nexport type Participant = {\n  id: string;\n  name: string;\n  local: boolean;\n};\n\n/**\n * Per-device lifecycle state, tracked independently for the mic and the cam.\n * Modelled after daily-react's DailyDevices. Transitions are driven by\n * explicit calls to PipecatClient.initDevices() and by DeviceError events.\n * Never by transport connect/disconnect.\n */\nexport type DeviceState =\n  /** initDevices() has not been called yet for this device */\n  | \"uninitialized\"\n  /** initDevices() is in flight (enumeration / permission request) */\n  | \"initializing\"\n  /** Device is enumerated and ready to use */\n  | \"granted\"\n  /** Device is in an error state and could not be acquired */\n  | \"error\";\n\n/**\n * Per-device error categories. Only meaningful when DeviceStatus.state is\n * 'error'. Mirrors the shape of DeviceErrorType but expressed in\n * MediaState's own vocabulary so consumers can render UI without going\n * through the underlying error object.\n */\nexport type DeviceErrorReason =\n  /** User explicitly denied permission */\n  | \"blocked\"\n  /** Hardware is busy in another application */\n  | \"already-in-use\"\n  /** No matching hardware was found */\n  | \"not-found\"\n  /** getUserMedia constraints couldn't be satisfied */\n  | \"invalid-constraints\"\n  /** Browser API is unavailable (legacy browser, insecure context) */\n  | \"not-supported\"\n  /** Catch-all for errors we couldn't classify */\n  | \"unknown\";\n\n/**\n * Per-device status. A discriminated union: when `state` is `'error'`, the\n * `reason` field describes the error category (and `details` may carry the\n * raw error payload). Consumers branch on `state` to decide what to render.\n */\nexport type DeviceStatus =\n  | { state: \"uninitialized\" | \"initializing\" | \"granted\" }\n  | { state: \"error\"; reason: DeviceErrorReason; details?: unknown };\n\n/**\n * Per-device state on PipecatClient, exposed independently of TransportState.\n * Speakers are intentionally not tracked here: output devices have no\n * permission or in-use failure mode, only enumeration.\n */\nexport type MediaState = {\n  mic: DeviceStatus;\n  cam: DeviceStatus;\n};\n","/**\n * Copyright (c) 2024, Daily.\n *\n * SPDX-License-Identifier: BSD-2-Clause\n */\n\nexport class RTVIError extends Error {\n  readonly status: number | undefined;\n\n  constructor(message?: string, status?: number | undefined) {\n    super(message);\n    this.status = status;\n  }\n}\n\nexport class ConnectionTimeoutError extends RTVIError {\n  constructor(message?: string | undefined) {\n    super(\n      message ??\n        \"Bot did not enter ready state within the specified timeout period.\"\n    );\n  }\n}\n\nexport class StartBotError extends RTVIError {\n  readonly error: string = \"invalid-request-error\";\n  constructor(message?: string | undefined, status?: number) {\n    super(\n      message ?? `Failed to connect / invalid auth bundle from base url`,\n      status ?? 500\n    );\n  }\n}\n\nexport class TransportStartError extends RTVIError {\n  constructor(message?: string | undefined) {\n    super(message ?? \"Unable to connect to transport\");\n  }\n}\n\nexport class InvalidTransportParamsError extends RTVIError {\n  constructor(message?: string | undefined) {\n    super(message ?? \"Invalid transport connection parameters\");\n  }\n}\n\nexport class BotNotReadyError extends RTVIError {\n  constructor(message?: string | undefined) {\n    super(\n      message ??\n        \"Attempt to call action on transport when not in 'ready' state.\"\n    );\n  }\n}\n\nexport class BotAlreadyStartedError extends RTVIError {\n  constructor(message?: string | undefined) {\n    super(\n      message ??\n        \"Pipecat client has already been started. Please call disconnect() before starting again.\"\n    );\n  }\n}\n\nexport class UnsupportedFeatureError extends RTVIError {\n  readonly feature: string;\n  constructor(feature: string, source?: string, message?: string) {\n    let msg = `${feature} not supported${message ? `: ${message}` : \"\"}`;\n    if (source) {\n      msg = `${source} does not support ${feature}${\n        message ? `: ${message}` : \"\"\n      }`;\n    }\n    super(msg);\n    this.feature = feature;\n  }\n}\n\nexport class MessageTooLargeError extends RTVIError {\n  constructor(message?: string | undefined) {\n    super(\n      message ?? \"Message size exceeds the maximum allowed limit for transport.\"\n    );\n  }\n}\n\nexport type DeviceArray = Array<\"cam\" | \"mic\" | \"speaker\">;\nexport type DeviceErrorType =\n  | \"in-use\"\n  | \"permissions\"\n  | \"undefined-mediadevices\"\n  | \"not-found\"\n  | \"constraints\"\n  | \"unknown\";\nexport type DeviceErrorDetails = Record<\n  string,\n  string | boolean | number | Error\n>;\n\nexport class DeviceError extends RTVIError {\n  readonly devices: DeviceArray;\n  readonly type: DeviceErrorType;\n  readonly details: DeviceErrorDetails | undefined;\n  constructor(\n    devices: DeviceArray,\n    type: DeviceErrorType,\n    message?: string,\n    details?: DeviceErrorDetails\n  ) {\n    super(message ?? `Device error for ${devices.join(\", \")}: ${type}`);\n    this.devices = devices;\n    this.type = type;\n    this.details = details;\n  }\n}\n","/**\n * Copyright (c) 2024, Daily.\n *\n * SPDX-License-Identifier: BSD-2-Clause\n */\n\nimport { v4 as uuidv4 } from \"uuid\";\n\nimport {\n  name as packageName,\n  version as packageVersion,\n} from \"../package.json\";\nimport type { A11ySnapshot, UIJobGroupEnvelope } from \"./ui\";\n\nexport const RTVI_PROTOCOL_VERSION = \"1.4.0\";\nexport const RTVI_MESSAGE_LABEL = \"rtvi-ai\";\n\n/**\n * Messages the corresponding server-side client expects to receive about\n * our client-side state.\n */\nexport enum RTVIMessageType {\n  /** Outbound Messages */\n  CLIENT_READY = \"client-ready\",\n  DISCONNECT_BOT = \"disconnect-bot\",\n  // Client-to-server messages\n  CLIENT_MESSAGE = \"client-message\",\n  SEND_TEXT = \"send-text\",\n  // UI Worker Protocol (client-to-server)\n  UI_EVENT = \"ui-event\",\n  UI_SNAPSHOT = \"ui-snapshot\",\n  UI_CANCEL_JOB_GROUP = \"ui-cancel-job-group\",\n  // DEPRECATED\n  APPEND_TO_CONTEXT = \"append-to-context\",\n\n  /**\n   * Inbound Messages\n   * Messages the server-side client sends to our client-side client regarding\n   * its state or other non-service-specific messaging.\n   */\n  BOT_READY = \"bot-ready\", // Bot is connected and ready to receive messages\n  ERROR = \"error\", // Bot initialization error\n  METRICS = \"metrics\", // Bot reporting metrics\n  SERVER_MESSAGE = \"server-message\", // Custom server-to-client message\n  SERVER_RESPONSE = \"server-response\", // Server response to client message\n  ERROR_RESPONSE = \"error-response\", // Error message in response to an outbound message\n  APPEND_TO_CONTEXT_RESULT = \"append-to-context-result\", // Result of appending to context\n  // UI Worker Protocol (server-to-client)\n  UI_COMMAND = \"ui-command\",\n  UI_JOB_GROUP = \"ui-job-group\",\n\n  /** Speaking and Transcription Messages */\n  USER_STARTED_SPEAKING = \"user-started-speaking\", // User started speaking\n  USER_STOPPED_SPEAKING = \"user-stopped-speaking\", // User stopped speaking\n  BOT_STARTED_SPEAKING = \"bot-started-speaking\", // Bot started speaking\n  BOT_STOPPED_SPEAKING = \"bot-stopped-speaking\", // Bot stopped speaking\n  // User muted events. These events notify when the server is ignoring audio from the client.\n  // The client should continue sending audio normally but may want to show some indication to the user.\n  USER_MUTE_STARTED = \"user-mute-started\", // User muted server-side.\n  USER_MUTE_STOPPED = \"user-mute-stopped\", // User unmuted server-side.\n\n  USER_TRANSCRIPTION = \"user-transcription\", // Local user speech to text transcription (partials and finals)\n  BOT_OUTPUT = \"bot-output\", // A best effort aggregation of all bot output along with metadata like if it's spoken\n  // DEPRECATED\n  BOT_TRANSCRIPTION = \"bot-transcription\", // Bot full text transcription (sentence aggregated)\n\n  /** LLM Messages */\n  USER_LLM_TEXT = \"user-llm-text\", // Aggregated user input text which is sent to LLM\n  BOT_LLM_TEXT = \"bot-llm-text\", // Streamed token returned by the LLM\n  BOT_LLM_STARTED = \"bot-llm-started\", // Bot LLM inference starts\n  BOT_LLM_STOPPED = \"bot-llm-stopped\", // Bot LLM inference stops\n\n  // Function calling\n  // DECPRECATED\n  LLM_FUNCTION_CALL = \"llm-function-call\", // Inbound function call from LLM\n  LLM_FUNCTION_CALL_STARTED = \"llm-function-call-started\", // Inbound function call started\n  LLM_FUNCTION_CALL_IN_PROGRESS = \"llm-function-call-in-progress\", // Inbound function call in progress\n  LLM_FUNCTION_CALL_STOPPED = \"llm-function-call-stopped\", // Inbound function call stopped\n  LLM_FUNCTION_CALL_RESULT = \"llm-function-call-result\", // Outbound result of function call\n\n  BOT_LLM_SEARCH_RESPONSE = \"bot-llm-search-response\", // Bot LLM search response\n\n  /** TTS Messages */\n  BOT_TTS_TEXT = \"bot-tts-text\", // Bot TTS text output (streamed word as it is spoken)\n  BOT_TTS_STARTED = \"bot-tts-started\", // Bot TTS response starts\n  BOT_TTS_STOPPED = \"bot-tts-stopped\", // Bot TTS response stops\n}\n\n// ----- Message Data Types\n\nexport type BotReadyData = {\n  version: string;\n  about?: unknown; // Optional about data from the bot\n};\n\ntype PlatformDetailsValue = undefined | string | number | boolean;\ntype NestedPlatformDetails =\n  | PlatformDetailsValue\n  | Record<string, PlatformDetailsValue>;\n\n// This is an interface so that different client libraries can provide their own\n// implementation of the about data, e.g., with more platform-specific details.\n// The client library should call `setAboutClient` to set this data before sending\n// the `client-ready` message.\nexport interface AboutClientData {\n  library: string; // Library name, e.g., \"@pipecat-ai/client-js\"\n  library_version?: string; // Library version, e.g., \"1.0.0\"\n  platform?: string; // Platform name, e.g., \"Android\"\n  platform_version?: string; // Platform version, e.g., \"14.0\"\n  platform_details?: Record<string, NestedPlatformDetails>; // Optional platform details, e.g., browser info\n}\n\nexport type ClientReadyData = {\n  version: string;\n  about: AboutClientData; // Information about the client library\n};\n\nexport type ErrorData = {\n  message: string;\n  fatal: boolean;\n};\n\nexport type PipecatMetricData = {\n  processor: string;\n  value: number;\n};\n\nexport type PipecatMetricsData = {\n  processing?: PipecatMetricData[];\n  ttfb?: PipecatMetricData[];\n  characters?: PipecatMetricData[];\n};\n\nexport type TranscriptData = {\n  text: string;\n  final: boolean;\n  timestamp: string;\n  user_id: string;\n};\n\nexport enum AggregationType {\n  WORD = \"word\",\n  SENTENCE = \"sentence\",\n}\n\nexport type BotOutputData = {\n  text: string;\n  spoken: boolean;\n  aggregated_by?: AggregationType | string;\n};\n\nexport type BotLLMTextData = {\n  text: string;\n};\n\nexport type BotTTSTextData = {\n  text: string;\n};\n\nexport type ServerMessageData = {\n  // eslint-disable-next-line @typescript-eslint/no-explicit-any\n  data: any;\n};\n\nexport type ClientMessageData = {\n  t: string;\n  d?: unknown;\n};\n\nexport type UIEventData = {\n  event: string;\n  payload?: unknown;\n};\n\nexport type UISnapshotData = {\n  tree: A11ySnapshot;\n};\n\nexport type UICancelJobGroupData = {\n  job_id: string;\n  reason?: string;\n};\n\nexport type UICommandData = {\n  command: string;\n  payload: unknown;\n};\n\nexport type UIJobGroupData = UIJobGroupEnvelope;\n\nexport type LLMSearchResult = {\n  text: string;\n  confidence: number[];\n};\n\nexport type BotLLMSearchResponseData = {\n  search_result?: string;\n  rendered_content?: string;\n  origins: LLMSearchOrigin[];\n};\n\nexport type LLMSearchOrigin = {\n  site_uri?: string;\n  site_title?: string;\n  results: LLMSearchResult[];\n};\n\nexport type LLMFunctionCallStartedData = {\n  function_name?: string;\n};\n\nexport type LLMFunctionCallInProgressData = {\n  function_name?: string;\n  tool_call_id: string;\n  arguments?: Record<string, unknown>;\n};\n\n/** @deprecated Use LLMFunctionCallInProgressData instead */\nexport type LLMFunctionCallData = {\n  function_name?: string;\n  tool_call_id: string;\n  args: Record<string, unknown>;\n};\n\nexport type LLMFunctionCallResult = Record<string, unknown> | string;\n\nexport type LLMFunctionCallResultResponse = {\n  function_name: string;\n  tool_call_id: string;\n  arguments: Record<string, unknown>;\n  result: LLMFunctionCallResult;\n};\n\nexport type LLMFunctionCallStoppedData = {\n  function_name?: string;\n  tool_call_id: string;\n  cancelled: boolean;\n  result?: unknown;\n};\n\nexport type SendTextOptions = {\n  run_immediately?: boolean;\n  audio_response?: boolean;\n};\n\n/** DEPRECATED */\nexport type LLMContextMessage = {\n  role: \"user\" | \"assistant\";\n  content: unknown;\n  run_immediately?: boolean;\n};\n\n/** DEPRECATED */\nexport type AppendToContextResultData = {\n  result: Record<string, unknown> | string;\n};\n\n// ----- Message Classes\n\nlet _aboutClient: AboutClientData | undefined;\nexport function setAboutClient(about: AboutClientData) {\n  // allow for partial updates to the about data\n  // this allows the client to set the about data at any time\n  // before sending the `client-ready` message and not worry about\n  // overwriting existing data\n  if (_aboutClient) {\n    _aboutClient = { ..._aboutClient, ...about };\n  } else {\n    // if no about data is set, set it to the provided value\n    _aboutClient = about;\n  }\n}\n\nexport class RTVIMessage {\n  id: string;\n  label: string = RTVI_MESSAGE_LABEL;\n  type: string;\n  data: unknown;\n\n  constructor(type: string, data: unknown, id?: string) {\n    this.type = type;\n    this.data = data;\n    this.id = id || uuidv4().slice(0, 8);\n  }\n\n  // Outbound message types\n  static clientReady(): RTVIMessage {\n    return new RTVIMessage(RTVIMessageType.CLIENT_READY, {\n      version: RTVI_PROTOCOL_VERSION,\n      about: _aboutClient || {\n        library: packageName,\n        library_version: packageVersion,\n      },\n    });\n  }\n\n  static disconnectBot(): RTVIMessage {\n    return new RTVIMessage(RTVIMessageType.DISCONNECT_BOT, {});\n  }\n\n  static error(message: string, fatal = false): RTVIMessage {\n    return new RTVIMessage(RTVIMessageType.ERROR, { message, fatal });\n  }\n}\n","/**\n * Copyright (c) 2024, Daily.\n *\n * SPDX-License-Identifier: BSD-2-Clause\n */\n\nimport { MediaState, Participant, TransportState } from \"./common_types\";\nimport { DeviceError, UnsupportedFeatureError } from \"./errors\";\nimport {\n  BotLLMSearchResponseData,\n  BotLLMTextData,\n  BotOutputData,\n  BotReadyData,\n  BotTTSTextData,\n  LLMFunctionCallData,\n  LLMFunctionCallInProgressData,\n  LLMFunctionCallStartedData,\n  LLMFunctionCallStoppedData,\n  PipecatMetricsData,\n  RTVIMessage,\n  TranscriptData,\n  UICommandData,\n  UIJobGroupData,\n} from \"./messages\";\n\nexport enum RTVIEvent {\n  /** local connection state events */\n  Connected = \"connected\",\n  Disconnected = \"disconnected\",\n  TransportStateChanged = \"transportStateChanged\",\n\n  /** remote connection state events */\n  BotStarted = \"botStarted\",\n  BotConnected = \"botConnected\",\n  BotReady = \"botReady\",\n  BotDisconnected = \"botDisconnected\",\n  Error = \"error\",\n\n  /** server messaging */\n  ServerMessage = \"serverMessage\",\n  ServerResponse = \"serverResponse\",\n  MessageError = \"messageError\",\n\n  /** UI Worker Protocol */\n  UICommand = \"uiCommand\",\n  UIJobGroup = \"uiJobGroup\",\n\n  /** service events */\n  Metrics = \"metrics\",\n\n  // vad events\n  BotStartedSpeaking = \"botStartedSpeaking\",\n  BotStoppedSpeaking = \"botStoppedSpeaking\",\n  UserStartedSpeaking = \"userStartedSpeaking\",\n  UserStoppedSpeaking = \"userStoppedSpeaking\",\n\n  // user mute strategy events\n  UserMuteStarted = \"userMuteStarted\",\n  UserMuteStopped = \"userMuteStopped\",\n\n  // stt events\n  UserTranscript = \"userTranscript\",\n  BotOutput = \"botOutput\",\n  // DEPRECATED\n  BotTranscript = \"botTranscript\",\n\n  // llm events\n  BotLlmText = \"botLlmText\",\n  BotLlmStarted = \"botLlmStarted\",\n  BotLlmStopped = \"botLlmStopped\",\n\n  // DEPRECATED\n  LLMFunctionCall = \"llmFunctionCall\",\n  LLMFunctionCallStarted = \"llmFunctionCallStarted\",\n  LLMFunctionCallInProgress = \"llmFunctionCallInProgress\",\n  LLMFunctionCallStopped = \"llmFunctionCallStopped\",\n\n  BotLlmSearchResponse = \"botLlmSearchResponse\",\n\n  // tts events\n  BotTtsText = \"botTtsText\",\n  BotTtsStarted = \"botTtsStarted\",\n  BotTtsStopped = \"botTtsStopped\",\n\n  /** participant events */\n  ParticipantConnected = \"participantConnected\",\n  ParticipantLeft = \"participantLeft\",\n\n  /** media events */\n  TrackStarted = \"trackStarted\",\n  TrackStopped = \"trackStopped\",\n  ScreenTrackStarted = \"screenTrackStarted\",\n  ScreenTrackStopped = \"screenTrackStopped\",\n  ScreenShareError = \"screenShareError\",\n\n  LocalAudioLevel = \"localAudioLevel\",\n  RemoteAudioLevel = \"remoteAudioLevel\",\n\n  /** media device events */\n  AvailableCamsUpdated = \"availableCamsUpdated\",\n  AvailableMicsUpdated = \"availableMicsUpdated\",\n  AvailableSpeakersUpdated = \"availableSpeakersUpdated\",\n  CamUpdated = \"camUpdated\",\n  MicUpdated = \"micUpdated\",\n  SpeakerUpdated = \"speakerUpdated\",\n  DeviceError = \"deviceError\",\n  MediaStateUpdated = \"mediaStateUpdated\",\n  UnsupportedFeature = \"unsupportedFeature\",\n}\n\nexport type RTVIEvents = Partial<{\n  /** local connection state events */\n  connected: () => void;\n  disconnected: () => void;\n  transportStateChanged: (state: TransportState) => void;\n\n  /** remote connection state events */\n  botStarted: (botResponse: unknown) => void;\n  botConnected: (participant: Participant) => void;\n  botReady: (botData: BotReadyData) => void;\n  botDisconnected: (participant: Participant) => void;\n  error: (message: RTVIMessage) => void;\n\n  /** server messaging */\n  // eslint-disable-next-line @typescript-eslint/no-explicit-any\n  serverMessage: (data: any) => void;\n  // eslint-disable-next-line @typescript-eslint/no-explicit-any\n  serverResponse: (data: any) => void;\n  messageError: (message: RTVIMessage) => void;\n\n  /** UI Worker Protocol */\n  uiCommand: (data: UICommandData) => void;\n  uiJobGroup: (data: UIJobGroupData) => void;\n\n  /** service events */\n  metrics: (data: PipecatMetricsData) => void;\n\n  // vad events\n  botStartedSpeaking: () => void;\n  botStoppedSpeaking: () => void;\n  userStartedSpeaking: () => void;\n  userStoppedSpeaking: () => void;\n\n  // user mute strategy events\n  userMuteStarted: () => void;\n  userMuteStopped: () => void;\n\n  // stt events\n  userTranscript: (data: TranscriptData) => void;\n  botOutput: (data: BotOutputData) => void;\n  botTranscript: (data: BotLLMTextData) => void;\n\n  // llm events\n  botLlmText: (data: BotLLMTextData) => void;\n  botLlmStarted: () => void;\n  botLlmStopped: () => void;\n\n  /** @deprecated Use LLMFunctionCallInProgress instead */\n  llmFunctionCall: (func: LLMFunctionCallData) => void;\n  llmFunctionCallStarted: (data: LLMFunctionCallStartedData) => void;\n  llmFunctionCallInProgress: (data: LLMFunctionCallInProgressData) => void;\n  llmFunctionCallStopped: (data: LLMFunctionCallStoppedData) => void;\n\n  botLlmSearchResponse: (data: BotLLMSearchResponseData) => void;\n\n  // tts events\n  botTtsText: (data: BotTTSTextData) => void;\n  botTtsStarted: () => void;\n  botTtsStopped: () => void;\n\n  /** participant events */\n  participantConnected: (participant: Participant) => void;\n  participantLeft: (participant: Participant) => void;\n\n  /** media events */\n  trackStarted: (track: MediaStreamTrack, participant?: Participant) => void;\n  trackStopped: (track: MediaStreamTrack, participant?: Participant) => void;\n  screenTrackStarted: (track: MediaStreamTrack, p?: Participant) => void;\n  screenTrackStopped: (track: MediaStreamTrack, p?: Participant) => void;\n  screenShareError: (errorMessage: string) => void;\n\n  localAudioLevel: (level: number) => void;\n  remoteAudioLevel: (level: number, p: Participant) => void;\n\n  /** media device events */\n  availableCamsUpdated: (cams: MediaDeviceInfo[]) => void;\n  availableMicsUpdated: (mics: MediaDeviceInfo[]) => void;\n  availableSpeakersUpdated: (speakers: MediaDeviceInfo[]) => void;\n  camUpdated: (cam: MediaDeviceInfo) => void;\n  micUpdated: (mic: MediaDeviceInfo) => void;\n  speakerUpdated: (speaker: MediaDeviceInfo) => void;\n  deviceError: (error: DeviceError) => void;\n  mediaStateUpdated: (mediaState: MediaState) => void;\n  unsupportedFeature: (error: UnsupportedFeatureError) => void;\n}>;\n\nexport type RTVIEventHandler<E extends RTVIEvent> = E extends keyof RTVIEvents\n  ? RTVIEvents[E]\n  : never;\n","/**\n * Copyright (c) 2024, Daily.\n *\n * SPDX-License-Identifier: BSD-2-Clause\n */\n\nexport {\n  findElementByRef,\n  findRefForElement,\n  serializeSelection,\n  snapshotDocument,\n  type SnapshotOptions,\n} from \"./a11y_walker\";\nexport * from \"./common_types\";\nexport * from \"./errors\";\nexport * from \"./events\";\nexport * from \"./messages\";\nexport * from \"./ui\";\n","/**\n * Copyright (c) 2024, Daily.\n *\n * SPDX-License-Identifier: BSD-2-Clause\n */\n\nimport { BotAlreadyStartedError, BotNotReadyError } from \"../rtvi\";\nimport { PipecatClient } from \".\";\n\nexport function transportReady<T extends PipecatClient>(\n  _target: T,\n  propertyKey: string | symbol,\n  descriptor: PropertyDescriptor\n): PropertyDescriptor | void {\n  const originalMethod = descriptor.value;\n\n  descriptor.value = function (this: T, ...args: unknown[]) {\n    if (this.state === \"ready\") {\n      return originalMethod.apply(this, args);\n    } else {\n      throw new BotNotReadyError(\n        `Attempt to call ${propertyKey.toString()} when transport not in ready state. Await connect() first.`\n      );\n    }\n  };\n\n  return descriptor;\n}\n\nexport function transportAlreadyStarted<T extends PipecatClient>(\n  _target: T,\n  propertyKey: string | symbol,\n  descriptor: PropertyDescriptor\n): PropertyDescriptor | void {\n  const originalMethod = descriptor.value;\n\n  const states = [\"authenticating\", \"connecting\", \"connected\", \"ready\"];\n\n  descriptor.value = function (this: T, ...args: unknown[]) {\n    if (states.includes(this.state)) {\n      throw new BotAlreadyStartedError(\n        `Attempt to call ${propertyKey.toString()} when client already started. Please call disconnect() before starting again.`\n      );\n    } else {\n      return originalMethod.apply(this, args);\n    }\n  };\n\n  return descriptor;\n}\n\nexport function transportInState<T extends PipecatClient>(states: string[]) {\n  return function (\n    _target: T,\n    propertyKey: string | symbol,\n    descriptor: PropertyDescriptor\n  ): PropertyDescriptor | void {\n    const originalMethod = descriptor.value;\n\n    descriptor.get = function (this: T, ...args: unknown[]) {\n      if (states.includes(this.state)) {\n        return originalMethod.apply(this, args);\n      } else {\n        throw new BotNotReadyError(\n          `Attempt to call ${propertyKey.toString()} when transport not in ${states}.`\n        );\n      }\n    };\n\n    return descriptor;\n  };\n}\n\nexport function getIfTransportInState<T extends PipecatClient>(\n  ...states: string[]\n) {\n  states = [\"ready\", ...states];\n\n  return function (\n    _target: T,\n    propertyKey: string | symbol,\n    descriptor: PropertyDescriptor\n  ): PropertyDescriptor | void {\n    const originalGetter = descriptor.get;\n\n    descriptor.get = function (this: T) {\n      if (states.includes(this.state)) {\n        return originalGetter?.apply(this);\n      } else {\n        throw new BotNotReadyError(\n          `Attempt to call ${propertyKey.toString()} when transport not in ${states}. Await connect() first.`\n        );\n      }\n    };\n\n    return descriptor;\n  };\n}\n","/**\n * Copyright (c) 2024, Daily.\n *\n * SPDX-License-Identifier: BSD-2-Clause\n */\n\nexport enum LogLevel {\n  NONE = 0,\n  ERROR = 1,\n  WARN = 2,\n  INFO = 3,\n  DEBUG = 4,\n}\n\nclass Logger {\n  private static instance: Logger;\n  private level: LogLevel = LogLevel.DEBUG;\n\n  private constructor() {}\n\n  static getInstance(): Logger {\n    if (!Logger.instance) {\n      Logger.instance = new Logger();\n    }\n    return Logger.instance;\n  }\n\n  setLevel(level: LogLevel) {\n    this.level = level;\n  }\n\n  debug(...args: unknown[]) {\n    if (this.level >= LogLevel.DEBUG) {\n      console.debug(...args);\n    }\n  }\n\n  info(...args: unknown[]) {\n    if (this.level >= LogLevel.INFO) {\n      console.info(...args);\n    }\n  }\n\n  warn(...args: unknown[]) {\n    if (this.level >= LogLevel.WARN) {\n      console.warn(...args);\n    }\n  }\n\n  error(...args: unknown[]) {\n    if (this.level >= LogLevel.ERROR) {\n      console.error(...args);\n    }\n  }\n}\n\nexport const logger = Logger.getInstance();\n\nexport type ILogger = Logger;\n","/**\n * Copyright (c) 2024, Daily.\n *\n * SPDX-License-Identifier: BSD-2-Clause\n */\n\nimport { ClientMessageData, RTVIMessage, RTVIMessageType } from \"../rtvi\";\nimport { logger } from \"./logger\";\n\ninterface QueuedRTVIMessage {\n  message: RTVIMessage;\n  timestamp: number;\n  timeout: number;\n  resolve: (value: unknown) => void;\n  reject: (reason?: unknown) => void;\n}\n\nexport class MessageDispatcher {\n  protected _sendMethod: (message: RTVIMessage) => void;\n  protected _queue = new Array<QueuedRTVIMessage>();\n  protected _gcInterval: ReturnType<typeof setInterval> | undefined = undefined;\n\n  constructor(sendMethod: (message: RTVIMessage) => void) {\n    this._queue = [];\n    this._sendMethod = sendMethod;\n  }\n\n  public disconnect() {\n    this.clearQueue();\n    clearInterval(this._gcInterval);\n    this._gcInterval = undefined;\n  }\n\n  public dispatch(\n    message_data: unknown,\n    type = RTVIMessageType.CLIENT_MESSAGE,\n    timeout = 10000\n  ): Promise<RTVIMessage> {\n    if (!this._gcInterval) {\n      // start garbage collection if not already running\n      this._gcInterval = setInterval(() => {\n        this._gc();\n      }, 2000); // Run garbage collection every 2 seconds\n    }\n\n    const message = new RTVIMessage(type, message_data);\n    const promise = new Promise((resolve, reject) => {\n      this._queue.push({\n        message,\n        timestamp: Date.now(),\n        timeout,\n        resolve,\n        reject,\n      });\n    });\n\n    logger.debug(\"[MessageDispatcher] dispatch\", message);\n\n    try {\n      this._sendMethod(message);\n    } catch (e) {\n      logger.error(\"[MessageDispatcher] Error sending message\", e);\n      return Promise.reject(e);\n    }\n\n    this._gc();\n\n    return promise as Promise<RTVIMessage>;\n  }\n\n  public clearQueue() {\n    this._queue = [];\n  }\n\n  private _resolveReject(\n    message: RTVIMessage,\n    resolve: boolean = true\n  ): RTVIMessage {\n    const queuedMessage = this._queue.find(\n      (msg) => msg.message.id === message.id\n    );\n\n    if (queuedMessage) {\n      if (resolve) {\n        logger.debug(\"[MessageDispatcher] Resolve\", message);\n        queuedMessage.resolve(message as RTVIMessage);\n      } else {\n        logger.debug(\"[MessageDispatcher] Reject\", message);\n        queuedMessage.reject(message as RTVIMessage);\n      }\n      // Remove message from queue\n      this._queue = this._queue.filter((msg) => msg.message.id !== message.id);\n      logger.debug(\"[MessageDispatcher] Queue\", this._queue);\n    }\n\n    return message;\n  }\n\n  public resolve(message: RTVIMessage): RTVIMessage {\n    return this._resolveReject(message, true);\n  }\n\n  public reject(message: RTVIMessage): RTVIMessage {\n    return this._resolveReject(message, false);\n  }\n\n  protected _gc() {\n    const expired: QueuedRTVIMessage[] = [];\n    this._queue = this._queue.filter((msg) => {\n      const isValid = Date.now() - msg.timestamp < msg.timeout;\n      if (!isValid) {\n        expired.push(msg);\n      }\n      return isValid;\n    });\n\n    expired.forEach((msg) => {\n      if (msg.message.type === RTVIMessageType.CLIENT_MESSAGE) {\n        msg.reject(\n          new RTVIMessage(RTVIMessageType.ERROR_RESPONSE, {\n            error: \"Timed out waiting for response\",\n            msgType: (msg.message.data as ClientMessageData).t,\n            data: (msg.message.data as ClientMessageData).d,\n            fatal: false,\n          })\n        );\n      }\n    });\n    logger.debug(\"[MessageDispatcher] GC\", this._queue);\n  }\n}\n","import { logger } from \"./logger\";\n\ntype Serializable =\n  | string\n  | number\n  | boolean\n  | null\n  | Serializable[]\n  | { [key: number | string]: Serializable };\n\nexport interface APIRequest {\n  endpoint: string | URL | globalThis.Request;\n  headers?: Headers;\n  requestData?: Serializable;\n  timeout?: number;\n}\n\n/**\n * @deprecated Use APIRequest instead\n */\nexport type ConnectionEndpoint = APIRequest;\n\nexport function isAPIRequest(value: unknown): boolean {\n  if (\n    typeof value === \"object\" &&\n    value !== null &&\n    Object.keys(value).includes(\"endpoint\")\n  ) {\n    const endpoint = (value as APIRequest)[\"endpoint\"];\n    return (\n      typeof endpoint === \"string\" ||\n      endpoint instanceof URL ||\n      (typeof Request !== \"undefined\" && endpoint instanceof Request)\n    );\n  }\n  return false;\n}\n\nexport async function makeRequest(\n  cxnOpts: APIRequest,\n  abortController?: AbortController\n): Promise<unknown> {\n  if (!abortController) {\n    abortController = new AbortController();\n  }\n  let handshakeTimeout: ReturnType<typeof setTimeout> | undefined;\n\n  return new Promise((resolve, reject) => {\n    (async () => {\n      if (cxnOpts.timeout) {\n        handshakeTimeout = setTimeout(async () => {\n          abortController.abort();\n          reject(new Error(\"Timed out\"));\n        }, cxnOpts.timeout);\n      }\n\n      let request: globalThis.Request;\n      if (\n        typeof Request !== \"undefined\" &&\n        cxnOpts.endpoint instanceof Request\n      ) {\n        request = new Request(cxnOpts.endpoint, {\n          signal: abortController.signal,\n        });\n        if (cxnOpts.requestData) {\n          logger.warn(\n            \"[Pipecat Client] requestData in APIRequest is ignored when endpoint is a Request object\"\n          );\n        }\n        if (cxnOpts.headers) {\n          logger.warn(\n            \"[Pipecat Client] headers in APIRequest is ignored when endpoint is a Request object\"\n          );\n        }\n      } else {\n        request = new Request(cxnOpts.endpoint, {\n          method: \"POST\",\n          mode: \"cors\",\n          headers: new Headers({\n            \"Content-Type\": \"application/json\",\n            ...Object.fromEntries((cxnOpts.headers ?? new Headers()).entries()),\n          }),\n          body: JSON.stringify(cxnOpts.requestData),\n          signal: abortController.signal,\n        });\n      }\n      logger.debug(`[Pipecat Client] Fetching from ${request.url}`);\n      fetch(request)\n        .then((res) => {\n          logger.debug(\n            `[Pipecat Client] Received response from ${request.url}`,\n            res\n          );\n          if (!res.ok) {\n            reject(res);\n            return;\n          }\n          return res.json();\n        })\n        .then((data) => {\n          resolve(data);\n        })\n        .catch((err) => {\n          logger.error(`[Pipecat Client] Error fetching: ${err}`);\n          reject(err);\n        })\n        .finally(() => {\n          if (handshakeTimeout) {\n            clearTimeout(handshakeTimeout);\n          }\n        });\n    })();\n  });\n}\n","/**\n * Copyright (c) 2024, Daily.\n *\n * SPDX-License-Identifier: BSD-2-Clause\n */\n\nimport { RTVIError, RTVIMessage, TransportState } from \"../rtvi\";\nimport { PipecatClientOptions, RTVIEventCallbacks } from \"./client\";\nimport { APIRequest } from \"./rest_helpers.ts\";\n\nexport type Tracks = {\n  local: {\n    audio?: MediaStreamTrack;\n    video?: MediaStreamTrack;\n    screenAudio?: MediaStreamTrack;\n    screenVideo?: MediaStreamTrack;\n  };\n  bot?: {\n    audio?: MediaStreamTrack;\n    screenAudio?: undefined;\n    screenVideo?: undefined;\n    video?: MediaStreamTrack;\n  };\n};\n\nexport type TransportConnectionParams = unknown;\n\nexport abstract class Transport {\n  declare protected _options: PipecatClientOptions;\n  declare protected _onMessage: (ev: RTVIMessage) => void;\n  declare protected _callbacks: RTVIEventCallbacks;\n  declare protected _abortController: AbortController | undefined;\n  protected _state: TransportState = \"disconnected\";\n  protected _startBotParams: APIRequest | undefined;\n  /**\n   * Maximum allowed size in bytes for a single signaling/message payload.\n   *\n   * The default is 64 KiB (`64 * 1024`), which is chosen to stay well within\n   * typical WebSocket, proxy, and intermediary limits and to discourage\n   * transports from sending very large payloads in a single message.\n   *\n   * Transport implementations may override this value in subclasses or\n   * constructors if their underlying transport has stricter or more relaxed\n   * limits, as long as they continue to honor this field when enforcing\n   * message size constraints.\n   */\n  protected _maxMessageSize = 64 * 1024; // 64 KiB\n\n  constructor() {}\n\n  /** called from PipecatClient constructor to wire up callbacks */\n  abstract initialize(\n    options: PipecatClientOptions,\n    messageHandler: (ev: RTVIMessage) => void\n  ): void;\n\n  /**\n   * This method is intended to initialize cam/mic devices. It is wrapped\n   * by PipecatClient.initDevices and should not be called directly. It is also\n   * called as part of PipecatClient.connect if it has not already called.\n   */\n  abstract initDevices(): Promise<void>;\n\n  /**\n   * Establishes a connection with the remote server. This is the main entry\n   * point for the transport to start sending and receiving media and messages.\n   * This is called from PipecatClient.connect() and should not be called directly.\n   * @param connectParams - This type will ultimately be defned by the transport\n   * implementation. It is used to pass connection parameters to the transport.\n   */\n  connect(connectParams?: TransportConnectionParams): Promise<void> {\n    this._abortController = new AbortController();\n    let validatedParams = connectParams;\n    try {\n      validatedParams = this._validateConnectionParams(connectParams);\n      // eslint-disable-next-line @typescript-eslint/no-explicit-any\n    } catch (e: any) {\n      throw new RTVIError(\n        `Invalid connection params: ${e.message}. Please check your connection params and try again.`\n      );\n    }\n    return this._connect(validatedParams);\n  }\n\n  /**\n   * Allow the transports to determine how the bot was started.\n   */\n  get startBotParams(): APIRequest | undefined {\n    return this._startBotParams;\n  }\n\n  /**\n   * Set the parameters used to start the bot.\n   * @param startBotParams\n   */\n  set startBotParams(startBotParams: APIRequest) {\n    if (\n      typeof Request !== \"undefined\" &&\n      startBotParams.endpoint instanceof Request\n    ) {\n      // If the endpoint is a Request object, we have to clone it.\n      // Otherwise, we might run into issues with body being already used.\n      this._startBotParams = {\n        ...startBotParams,\n        endpoint: startBotParams.endpoint.clone(),\n      };\n      return;\n    }\n    this._startBotParams = startBotParams;\n  }\n\n  abstract _validateConnectionParams(connectParams?: unknown): unknown;\n\n  abstract _connect(connectParams?: TransportConnectionParams): Promise<void>;\n  /**\n   * Disconnects the transport from the remote server. This is called from\n   * PipecatClient.disconnect() and should not be called directly.\n   */\n  disconnect(): Promise<void> {\n    if (this._abortController) {\n      this._abortController.abort();\n    }\n    return this._disconnect();\n  }\n  abstract _disconnect(): Promise<void>;\n  abstract sendReadyMessage(): void;\n\n  abstract get state(): TransportState;\n  abstract set state(state: TransportState);\n\n  abstract getAllMics(): Promise<MediaDeviceInfo[]>;\n  abstract getAllCams(): Promise<MediaDeviceInfo[]>;\n  abstract getAllSpeakers(): Promise<MediaDeviceInfo[]>;\n\n  abstract updateMic(micId: string): void;\n  abstract updateCam(camId: string): void;\n  abstract updateSpeaker(speakerId: string): void;\n\n  abstract get selectedMic(): MediaDeviceInfo | Record<string, never>;\n  abstract get selectedCam(): MediaDeviceInfo | Record<string, never>;\n  abstract get selectedSpeaker(): MediaDeviceInfo | Record<string, never>;\n\n  abstract enableMic(enable: boolean): void;\n  abstract enableCam(enable: boolean): void;\n  abstract enableScreenShare(enable: boolean): void;\n  abstract get isCamEnabled(): boolean;\n  abstract get isMicEnabled(): boolean;\n  abstract get isSharingScreen(): boolean;\n\n  abstract sendMessage(message: RTVIMessage): void;\n  /**\n   * Maximum size, in bytes, of a single message that this transport will attempt\n   * to send. Callers should ensure that any outbound {@link RTVIMessage} payloads\n   * do not exceed this limit to avoid transport or server errors.\n   */\n  get maxMessageSize(): number {\n    return this._maxMessageSize;\n  }\n\n  abstract tracks(): Tracks;\n}\n\nexport class TransportWrapper {\n  private _transport: Transport;\n  private _proxy: Transport;\n\n  constructor(transport: Transport) {\n    this._transport = transport;\n    this._proxy = new Proxy(this._transport, {\n      get: (target, prop, receiver) => {\n        if (typeof target[prop as keyof Transport] === \"function\") {\n          let errMsg;\n          switch (String(prop)) {\n            // Disable methods that modify the lifecycle of the call. These operations\n            // should be performed via the Pipecat client in order to keep state in sync.\n            case \"initialize\":\n              errMsg = `Direct calls to initialize() are disabled and used internally by the PipecatClient.`;\n              break;\n            case \"initDevices\":\n              errMsg = `Direct calls to initDevices() are disabled. Please use the PipecatClient.initDevices() wrapper or let PipecatClient.connect() call it for you.`;\n              break;\n            case \"sendReadyMessage\":\n              errMsg = `Direct calls to sendReadyMessage() are disabled and used internally by the PipecatClient.`;\n              break;\n            case \"connect\":\n              errMsg = `Direct calls to connect() are disabled. Please use the PipecatClient.connect() wrapper.`;\n              break;\n            case \"disconnect\":\n              errMsg = `Direct calls to disconnect() are disabled. Please use the PipecatClient.disconnect() wrapper.`;\n              break;\n          }\n          if (errMsg) {\n            return () => {\n              throw new Error(errMsg);\n            };\n          }\n          // Forward other method calls\n          return (...args: unknown[]) => {\n            // eslint-disable-next-line @typescript-eslint/no-unsafe-function-type\n            return (target[prop as keyof Transport] as Function)(...args);\n          };\n        }\n        // Forward property access\n        return Reflect.get(target, prop, receiver);\n      },\n    });\n  }\n\n  get proxy(): Transport {\n    return this._proxy;\n  }\n}\n","import Bowser from \"bowser\";\n\nimport {\n  name as packageName,\n  version as packageVersion,\n} from \"../package.json\";\nimport { AboutClientData } from \"../rtvi/messages\";\n\ninterface JSAboutClientData extends AboutClientData {\n  platform_details: {\n    browser?: string;\n    browser_version?: string;\n    platform_type?: string;\n    engine?: string;\n    device_memory?: number;\n    language?: string;\n    connection?: {\n      effectiveType?: string;\n      downlink?: number;\n    };\n  };\n}\n\nexport function learnAboutClient() {\n  let about: JSAboutClientData = {\n    library: packageName,\n    library_version: packageVersion,\n    platform_details: {},\n  };\n  // This uses legacy browser user agent parsing, which we still fall\n  // back to if the User Agent Hints API is not available\n  let navAgentInfo = null;\n  if (window?.navigator?.userAgent) {\n    try {\n      navAgentInfo = Bowser.parse(window.navigator.userAgent);\n      // eslint-disable-next-line @typescript-eslint/no-unused-vars\n    } catch (_) {\n      // void\n    }\n  }\n\n  if (navAgentInfo?.browser?.name) {\n    about.platform_details.browser = navAgentInfo.browser.name;\n  }\n  if (\n    navAgentInfo?.browser?.name === \"Safari\" &&\n    !navAgentInfo.browser.version\n  ) {\n    about.platform_details.browser_version = \"Web View\";\n  } else if (navAgentInfo?.browser?.version) {\n    about.platform_details.browser_version = navAgentInfo.browser.version;\n  }\n\n  if (navAgentInfo?.platform?.type) {\n    about.platform_details.platform_type = navAgentInfo.platform.type;\n  }\n\n  if (navAgentInfo?.engine?.name) {\n    about.platform_details.engine = navAgentInfo.engine.name;\n  }\n\n  if (navAgentInfo?.os) {\n    about.platform = navAgentInfo.os.name;\n    about.platform_version = navAgentInfo.os.version;\n  }\n  return about;\n}\n\nexport function messageSizeWithinLimit(\n  message: unknown,\n  maxSize: number\n): boolean {\n  const getSizeInBytes = (obj: unknown) => {\n    const jsonString = JSON.stringify(obj);\n    const encoder = new TextEncoder();\n    const bytes = encoder.encode(jsonString);\n    return bytes.length;\n  };\n  const size = getSizeInBytes(message);\n  return size <= maxSize;\n}\n","/**\n * Copyright (c) 2024, Daily.\n *\n * SPDX-License-Identifier: BSD-2-Clause\n */\n\nimport EventEmitter from \"events\";\nimport TypedEmitter from \"typed-emitter\";\n\nimport packageJson from \"../package.json\";\nimport {\n  A11ySnapshot,\n  BotLLMSearchResponseData,\n  BotLLMTextData,\n  BotOutputData,\n  BotReadyData,\n  BotTTSTextData,\n  ClientMessageData,\n  DeviceErrorReason,\n  DeviceStatus,\n  ErrorData,\n  LLMContextMessage,\n  LLMFunctionCallData,\n  LLMFunctionCallInProgressData,\n  LLMFunctionCallResult,\n  LLMFunctionCallResultResponse,\n  LLMFunctionCallStartedData,\n  LLMFunctionCallStoppedData,\n  MediaState,\n  Participant,\n  PipecatMetricsData,\n  RTVIEvent,\n  RTVIEvents,\n  RTVIMessage,\n  RTVIMessageType,\n  SendTextOptions,\n  setAboutClient,\n  TranscriptData,\n  TransportState,\n  UICancelJobGroupData,\n  UICommandData,\n  UIEventData,\n  UIJobGroupData,\n  UISnapshotData,\n} from \"../rtvi\";\nimport * as RTVIErrors from \"../rtvi/errors\";\nimport {\n  A11ySnapshotStreamer,\n  type A11ySnapshotStreamerOptions,\n} from \"./A11ySnapshotStreamer\";\nimport { transportAlreadyStarted, transportReady } from \"./decorators\";\nimport { MessageDispatcher } from \"./dispatcher\";\nimport { logger, LogLevel } from \"./logger\";\nimport {\n  APIRequest,\n  ConnectionEndpoint,\n  isAPIRequest,\n  makeRequest,\n} from \"./rest_helpers\";\nimport {\n  Tracks,\n  Transport,\n  TransportConnectionParams,\n  TransportWrapper,\n} from \"./transport\";\nimport { learnAboutClient, messageSizeWithinLimit } from \"./utils\";\n\nexport type FunctionCallParams = {\n  functionName: string;\n  arguments: Record<string, unknown>;\n};\n\n/**\n * Map a DeviceErrorType onto a DeviceErrorReason that captures the per-device\n * failure mode. Speaker-affecting errors are not represented here because\n * MediaState only tracks mic and cam.\n */\nfunction deviceErrorReasonFromType(\n  type: RTVIErrors.DeviceErrorType\n): DeviceErrorReason {\n  switch (type) {\n    case \"in-use\":\n      return \"already-in-use\";\n    case \"permissions\":\n      return \"blocked\";\n    case \"not-found\":\n      return \"not-found\";\n    case \"undefined-mediadevices\":\n      return \"not-supported\";\n    case \"constraints\":\n      return \"invalid-constraints\";\n    case \"unknown\":\n    default:\n      return \"unknown\";\n  }\n}\n\nexport type FunctionCallCallback = (\n  fn: FunctionCallParams\n) => Promise<LLMFunctionCallResult | void>;\n\nexport type RTVIEventCallbacks = Partial<{\n  onConnected: () => void;\n  onDisconnected: () => void;\n  onError: (message: RTVIMessage) => void;\n  onTransportStateChanged: (state: TransportState) => void;\n\n  onBotStarted: (botResponse: unknown) => void;\n  onBotConnected: (participant: Participant) => void;\n  onBotReady: (botReadyData: BotReadyData) => void;\n  onBotDisconnected: (participant: Participant) => void;\n  onMetrics: (data: PipecatMetricsData) => void;\n\n  // eslint-disable-next-line @typescript-eslint/no-explicit-any\n  onServerMessage: (data: any) => void;\n  onMessageError: (message: RTVIMessage) => void;\n  onUICommand: (data: UICommandData) => void;\n  onUIJobGroup: (data: UIJobGroupData) => void;\n\n  onParticipantJoined: (participant: Participant) => void;\n  onParticipantLeft: (participant: Participant) => void;\n\n  onAvailableCamsUpdated: (cams: MediaDeviceInfo[]) => void;\n  onAvailableMicsUpdated: (mics: MediaDeviceInfo[]) => void;\n  onAvailableSpeakersUpdated: (speakers: MediaDeviceInfo[]) => void;\n  onCamUpdated: (cam: MediaDeviceInfo) => void;\n  onMicUpdated: (mic: MediaDeviceInfo) => void;\n  onSpeakerUpdated: (speaker: MediaDeviceInfo) => void;\n  onDeviceError: (error: RTVIErrors.DeviceError) => void;\n  onMediaStateChanged: (mediaState: MediaState) => void;\n  onTrackStarted: (track: MediaStreamTrack, participant?: Participant) => void;\n  onTrackStopped: (track: MediaStreamTrack, participant?: Participant) => void;\n  onScreenTrackStarted: (\n    track: MediaStreamTrack,\n    participant?: Participant\n  ) => void;\n  onScreenTrackStopped: (\n    track: MediaStreamTrack,\n    participant?: Participant\n  ) => void;\n  onScreenShareError: (errorMessage: string) => void;\n  onUnsupportedFeature: (error: RTVIErrors.UnsupportedFeatureError) => void;\n  onLocalAudioLevel: (level: number) => void;\n  onRemoteAudioLevel: (level: number, participant: Participant) => void;\n\n  onUserStartedSpeaking: () => void;\n  onUserStoppedSpeaking: () => void;\n  onBotStartedSpeaking: () => void;\n  onBotStoppedSpeaking: () => void;\n  onUserMuteStarted: () => void;\n  onUserMuteStopped: () => void;\n  onUserTranscript: (data: TranscriptData) => void;\n  onBotOutput: (data: BotOutputData) => void;\n  /** @deprecated Use onBotOutput instead */\n  onBotTranscript: (data: BotLLMTextData) => void;\n\n  onBotLlmText: (data: BotLLMTextData) => void;\n  onBotLlmStarted: () => void;\n  onBotLlmStopped: () => void;\n  onBotTtsText: (data: BotTTSTextData) => void;\n  onBotTtsStarted: () => void;\n  onBotTtsStopped: () => void;\n\n  onLLMFunctionCallStarted: (data: LLMFunctionCallStartedData) => void;\n  onLLMFunctionCallInProgress: (data: LLMFunctionCallInProgressData) => void;\n  onLLMFunctionCallStopped: (data: LLMFunctionCallStoppedData) => void;\n  onBotLlmSearchResponse: (data: BotLLMSearchResponseData) => void;\n  /** @deprecated Use onLLMFunctionCallInProgress instead */\n  onLLMFunctionCall: (data: LLMFunctionCallData) => void;\n}>;\n\nexport interface PipecatClientOptions {\n  /**\n   * Transport class for media streaming\n   */\n  transport: Transport;\n\n  /**\n   * Optional callback methods for RTVI events\n   */\n  callbacks?: RTVIEventCallbacks;\n\n  /**\n   * Enable user mic input\n   *\n   * Default to true\n   */\n  enableMic?: boolean;\n\n  /**\n   * Enable user cam input\n   *\n   * Default to false\n   */\n  enableCam?: boolean;\n\n  /**\n   * Enable screen sharing\n   *\n   * Default to false\n   */\n  enableScreenShare?: boolean;\n\n  /**\n   * Disconnect when the bot disconnects.\n   *\n   * Default to true\n   */\n  disconnectOnBotDisconnect?: boolean;\n}\n\nabstract class RTVIEventEmitter extends (EventEmitter as unknown as new () => TypedEmitter<RTVIEvents>) {}\n\nexport class PipecatClient extends RTVIEventEmitter {\n  protected _options: PipecatClientOptions;\n  private _connectResolve: ((value: BotReadyData) => void) | undefined;\n  protected _transport: Transport;\n  protected _transportWrapper: TransportWrapper;\n  protected _disconnectOnBotDisconnect: boolean;\n  declare protected _messageDispatcher: MessageDispatcher;\n  protected _functionCallCallbacks: Record<string, FunctionCallCallback> = {};\n  protected _abortController: AbortController | undefined;\n  private _uiSnapshotStreamer: A11ySnapshotStreamer | undefined;\n  private _pendingUISnapshot: A11ySnapshot | undefined;\n\n  private _botTranscriptionWarned = false;\n  private _llmFunctionCallWarned = false;\n\n  // Per-device device state. Independent of TransportState — driven by\n  // initDevices() and DeviceError events, never by transport connect/disconnect.\n  // See common_types.ts for the rationale and the daily-react reference.\n  private _mediaState: MediaState = {\n    mic: { state: \"uninitialized\" },\n    cam: { state: \"uninitialized\" },\n  };\n\n  constructor(options: PipecatClientOptions) {\n    super();\n\n    setAboutClient(learnAboutClient());\n\n    this._transport = options.transport;\n    this._transportWrapper = new TransportWrapper(this._transport);\n\n    this._disconnectOnBotDisconnect = options.disconnectOnBotDisconnect ?? true;\n\n    // Wrap transport callbacks with event triggers\n    // This allows for either functional callbacks or .on / .off event listeners\n    const wrappedCallbacks: RTVIEventCallbacks = {\n      ...options.callbacks,\n      onMessageError: (message: RTVIMessage) => {\n        options?.callbacks?.onMessageError?.(message);\n        this.emit(RTVIEvent.MessageError, message);\n      },\n      onError: (message: RTVIMessage) => {\n        options?.callbacks?.onError?.(message);\n        try {\n          this.emit(RTVIEvent.Error, message);\n        } catch (e) {\n          if (e instanceof Error && e.message.includes(\"Unhandled error\")) {\n            if (!options?.callbacks?.onError) {\n              logger.debug(\n                \"No onError callback registered to handle error\",\n                message\n              );\n            }\n          } else {\n            logger.debug(\"Could not emit error\", message, e);\n          }\n        }\n        const data = message.data as ErrorData;\n        if (data?.fatal) {\n          logger.error(\"Fatal error reported. Disconnecting...\");\n          void this.disconnect();\n        }\n      },\n      onConnected: () => {\n        options?.callbacks?.onConnected?.();\n        this.emit(RTVIEvent.Connected);\n      },\n      onDisconnected: () => {\n        options?.callbacks?.onDisconnected?.();\n        this.emit(RTVIEvent.Disconnected);\n      },\n      onTransportStateChanged: (state: TransportState) => {\n        options?.callbacks?.onTransportStateChanged?.(state);\n        this.emit(RTVIEvent.TransportStateChanged, state);\n        if (state === \"ready\") this._flushPendingUISnapshot();\n      },\n      onParticipantJoined: (p) => {\n        options?.callbacks?.onParticipantJoined?.(p);\n        this.emit(RTVIEvent.ParticipantConnected, p);\n      },\n      onParticipantLeft: (p) => {\n        options?.callbacks?.onParticipantLeft?.(p);\n        this.emit(RTVIEvent.ParticipantLeft, p);\n      },\n      onTrackStarted: (track, p) => {\n        options?.callbacks?.onTrackStarted?.(track, p);\n        this.emit(RTVIEvent.TrackStarted, track, p);\n      },\n      onTrackStopped: (track, p) => {\n        options?.callbacks?.onTrackStopped?.(track, p);\n        this.emit(RTVIEvent.TrackStopped, track, p);\n      },\n      onScreenTrackStarted: (track, p) => {\n        options?.callbacks?.onScreenTrackStarted?.(track, p);\n        this.emit(RTVIEvent.ScreenTrackStarted, track, p);\n      },\n      onScreenTrackStopped: (track, p) => {\n        options?.callbacks?.onScreenTrackStopped?.(track, p);\n        this.emit(RTVIEvent.ScreenTrackStopped, track, p);\n      },\n      onScreenShareError: (errorMessage) => {\n        options?.callbacks?.onScreenShareError?.(errorMessage);\n        this.emit(RTVIEvent.ScreenShareError, errorMessage);\n      },\n      onUnsupportedFeature: (error) => {\n        options?.callbacks?.onUnsupportedFeature?.(error);\n        this.emit(RTVIEvent.UnsupportedFeature, error);\n      },\n      onAvailableCamsUpdated: (cams) => {\n        options?.callbacks?.onAvailableCamsUpdated?.(cams);\n        this.emit(RTVIEvent.AvailableCamsUpdated, cams);\n      },\n      onAvailableMicsUpdated: (mics) => {\n        options?.callbacks?.onAvailableMicsUpdated?.(mics);\n        this.emit(RTVIEvent.AvailableMicsUpdated, mics);\n      },\n      onAvailableSpeakersUpdated: (speakers) => {\n        options?.callbacks?.onAvailableSpeakersUpdated?.(speakers);\n        this.emit(RTVIEvent.AvailableSpeakersUpdated, speakers);\n      },\n      onCamUpdated: (cam) => {\n        // Real device selected → permission was granted. Upgrade MediaState\n        // (no-op if already granted, sticky if blocked / in-use / etc).\n        if (cam?.deviceId) this._markDeviceGranted(\"cam\");\n        options?.callbacks?.onCamUpdated?.(cam);\n        this.emit(RTVIEvent.CamUpdated, cam);\n      },\n      onMicUpdated: (mic) => {\n        if (mic?.deviceId) this._markDeviceGranted(\"mic\");\n        options?.callbacks?.onMicUpdated?.(mic);\n        this.emit(RTVIEvent.MicUpdated, mic);\n      },\n      onSpeakerUpdated: (speaker) => {\n        options?.callbacks?.onSpeakerUpdated?.(speaker);\n        this.emit(RTVIEvent.SpeakerUpdated, speaker);\n      },\n      onDeviceError: (error) => {\n        // Classify into MediaState in real time. Works the same whether the\n        // error fires during an initDevices() call (mid-await) or out of band\n        // (e.g. devicechange-driven). The post-transport Permissions API\n        // re-query in initDevices() then has the final word for any 'denied'\n        // override.\n        this._classifyAndApplyDeviceError(error);\n        options?.callbacks?.onDeviceError?.(error);\n        this.emit(RTVIEvent.DeviceError, error);\n      },\n      onBotStarted: (botResponse: unknown) => {\n        options?.callbacks?.onBotStarted?.(botResponse);\n        this.emit(RTVIEvent.BotStarted, botResponse);\n      },\n      onBotConnected: (p) => {\n        options?.callbacks?.onBotConnected?.(p);\n        this.emit(RTVIEvent.BotConnected, p);\n      },\n      onBotReady: (botReadyData: BotReadyData) => {\n        options?.callbacks?.onBotReady?.(botReadyData);\n        this.emit(RTVIEvent.BotReady, botReadyData);\n      },\n      onBotDisconnected: (p) => {\n        options?.callbacks?.onBotDisconnected?.(p);\n        this.emit(RTVIEvent.BotDisconnected, p);\n        if (this._disconnectOnBotDisconnect) {\n          logger.info(\"Bot disconnected. Disconnecting client...\");\n          void this.disconnect();\n        }\n      },\n      onUserStartedSpeaking: () => {\n        options?.callbacks?.onUserStartedSpeaking?.();\n        this.emit(RTVIEvent.UserStartedSpeaking);\n      },\n      onUserStoppedSpeaking: () => {\n        options?.callbacks?.onUserStoppedSpeaking?.();\n        this.emit(RTVIEvent.UserStoppedSpeaking);\n      },\n      onBotStartedSpeaking: () => {\n        options?.callbacks?.onBotStartedSpeaking?.();\n        this.emit(RTVIEvent.BotStartedSpeaking);\n      },\n      onBotStoppedSpeaking: () => {\n        options?.callbacks?.onBotStoppedSpeaking?.();\n        this.emit(RTVIEvent.BotStoppedSpeaking);\n      },\n      onRemoteAudioLevel: (level, p) => {\n        options?.callbacks?.onRemoteAudioLevel?.(level, p);\n        this.emit(RTVIEvent.RemoteAudioLevel, level, p);\n      },\n      onLocalAudioLevel: (level) => {\n        options?.callbacks?.onLocalAudioLevel?.(level);\n        this.emit(RTVIEvent.LocalAudioLevel, level);\n      },\n      onUserMuteStarted: () => {\n        options?.callbacks?.onUserMuteStarted?.();\n        this.emit(RTVIEvent.UserMuteStarted);\n      },\n      onUserMuteStopped: () => {\n        options?.callbacks?.onUserMuteStopped?.();\n        this.emit(RTVIEvent.UserMuteStopped);\n      },\n      onUserTranscript: (data) => {\n        options?.callbacks?.onUserTranscript?.(data);\n        this.emit(RTVIEvent.UserTranscript, data);\n      },\n      onBotOutput: (data) => {\n        options?.callbacks?.onBotOutput?.(data);\n        this.emit(RTVIEvent.BotOutput, data);\n      },\n      onBotTranscript: (text) => {\n        const hasSubscriber =\n          !!options?.callbacks?.onBotTranscript ||\n          this.listenerCount(RTVIEvent.BotTranscript) > 0;\n        if (hasSubscriber && !this._botTranscriptionWarned) {\n          logger.warn(\n            \"[Pipecat Client] Bot transcription is deprecated. Please use the onBotOutput instead.\"\n          );\n          this._botTranscriptionWarned = true;\n        }\n        options?.callbacks?.onBotTranscript?.(text);\n        this.emit(RTVIEvent.BotTranscript, text);\n      },\n      onBotLlmText: (text) => {\n        options?.callbacks?.onBotLlmText?.(text);\n        this.emit(RTVIEvent.BotLlmText, text);\n      },\n      onBotLlmStarted: () => {\n        options?.callbacks?.onBotLlmStarted?.();\n        this.emit(RTVIEvent.BotLlmStarted);\n      },\n      onBotLlmStopped: () => {\n        options?.callbacks?.onBotLlmStopped?.();\n        this.emit(RTVIEvent.BotLlmStopped);\n      },\n      onBotTtsText: (text) => {\n        options?.callbacks?.onBotTtsText?.(text);\n        this.emit(RTVIEvent.BotTtsText, text);\n      },\n      onBotTtsStarted: () => {\n        options?.callbacks?.onBotTtsStarted?.();\n        this.emit(RTVIEvent.BotTtsStarted);\n      },\n      onBotTtsStopped: () => {\n        options?.callbacks?.onBotTtsStopped?.();\n        this.emit(RTVIEvent.BotTtsStopped);\n      },\n    };\n\n    // Update options to reference wrapped callbacks and config defaults\n    this._options = {\n      ...options,\n      callbacks: wrappedCallbacks,\n      enableMic: options.enableMic ?? true,\n      enableCam: options.enableCam ?? false,\n      enableScreenShare: options.enableScreenShare ?? false,\n    };\n\n    // Instantiate the transport class and bind message handler\n    this._initialize();\n\n    // Get package version number\n    logger.debug(\"[Pipecat Client] Initialized\", this.version);\n  }\n\n  public setLogLevel(level: LogLevel) {\n    logger.setLevel(level);\n  }\n\n  // ------ Transport methods\n\n  /**\n   * Initialize local media devices.\n   *\n   * Drives MediaState transitions: both mic and cam move to 'initializing' on\n   * entry. On success, each device moves to 'granted' only if the transport\n   * reports it as acquired (via onMicUpdated / onCamUpdated with a real\n   * deviceId); otherwise that device falls back to 'uninitialized'. On\n   * failure the in-flight DeviceError (if any) classifies the affected\n   * device(s) per-device; anything still at 'initializing' falls back to\n   * 'unknown'. The original error is always re-thrown.\n   *\n   * Calling this again after a failure is the recovery path — a second call\n   * re-enters 'initializing' and reclassifies. There is no separate\n   * retryDevices() method.\n   */\n  public async initDevices() {\n    logger.debug(\"[Pipecat Client] Initializing devices...\");\n    // Both devices enter the lifecycle, regardless of enableMic / enableCam.\n    // The actual transport behavior is asymmetric and not predictable from\n    // options alone (e.g. daily-js's startCamera honors startVideoOff but not\n    // startAudioOff — it acquires the mic even when the caller said\n    // enableMic: false). MediaState mirrors what the transport actually did,\n    // sourced from onMicUpdated / onCamUpdated events that fire with a real\n    // deviceId only when permission was granted. Devices the transport never\n    // speaks to fall back to 'uninitialized' below.\n    this._setMediaState({\n      mic: { state: \"initializing\" },\n      cam: { state: \"initializing\" },\n    });\n\n    try {\n      await this._transport.initDevices();\n      // Transport resolved. Per-device transitions during the await:\n      //   - onMicUpdated / onCamUpdated upgraded reported devices to 'granted'\n      //   - onDeviceError applied per-device 'error' classifications\n      // Anything still at 'initializing' wasn't reported either way — the\n      // transport simply didn't speak to that device (e.g. daily-js skipping\n      // cam under startVideoOff: true). Fall it back to 'uninitialized'.\n      this._resolveLingeringInitializing({ state: \"uninitialized\" });\n    } catch (error) {\n      // Transport rejected. Same as above but the fallback for unspoken-to\n      // devices is 'unknown' — something failed and we can't tell whether\n      // this device would have worked.\n      this._resolveLingeringInitializing({\n        state: \"error\",\n        reason: \"unknown\",\n      });\n      throw error;\n    } finally {\n      // Re-query the Permissions API now that the prompt (if any) has been\n      // dismissed. Authoritative source for 'denied' regardless of what the\n      // transport said. See the helper for the under-reporting rationale.\n      await this._enrichFromPermissionsAPI();\n    }\n  }\n\n  /**\n   * After the transport's initDevices() resolves or rejects, any device\n   * still at 'initializing' didn't receive a 'granted' upgrade from\n   * onMicUpdated / onCamUpdated and wasn't classified by a DeviceError\n   * (which would have moved it to 'error'). Apply the supplied fallback so\n   * it doesn't linger.\n   *\n   * On success, fallback is 'uninitialized' (the transport simply didn't\n   * speak to that device — e.g. daily-js skipping cam under\n   * startVideoOff: true). On failure, fallback is an 'unknown' error (we\n   * know something went wrong but can't pin it on this device).\n   */\n  private _resolveLingeringInitializing(fallback: DeviceStatus): void {\n    const patch: Partial<MediaState> = {};\n    for (const kind of [\"mic\", \"cam\"] as const) {\n      if (this._mediaState[kind].state === \"initializing\") {\n        patch[kind] = fallback;\n      }\n    }\n    if (Object.keys(patch).length > 0) this._setMediaState(patch);\n  }\n\n  /**\n   * Upgrade a device to 'granted'. Called from the wrapped onMicUpdated /\n   * onCamUpdated when the transport reports an actual selected device.\n   * Allowed from any state — a previously errored device (e.g. 'not-found'\n   * because the cam was unplugged) can recover when the device reappears\n   * on a subsequent initDevices() call.\n   */\n  private _markDeviceGranted(kind: \"mic\" | \"cam\"): void {\n    if (this._mediaState[kind].state !== \"granted\") {\n      this._setMediaState({ [kind]: { state: \"granted\" } });\n    }\n  }\n\n  /**\n   * startBot() is a method that initiates the bot by posting to a specified endpoint\n   * that optionally returns connection parameters for establishing a transport session.\n   * @param startBotParams\n   * @returns Promise that resolves to TransportConnectionParams or unknown\n   */\n  @transportAlreadyStarted\n  public async startBot(startBotParams: APIRequest): Promise<unknown> {\n    // Implicit init when devices haven't been initialized yet. Pre-Plan-A\n    // this gate read transport.state === \"disconnected\", which fired both\n    // pre-init AND post-session — leading to redundant initDevices() calls\n    // on reconnect. needsInit(mediaState) is the unambiguous replacement.\n    if (this.needsInit()) {\n      await this.initDevices();\n    }\n    this._transport.state = \"authenticating\";\n    this._transport.startBotParams = startBotParams;\n    this._abortController = new AbortController();\n    let response: unknown;\n    try {\n      response = await makeRequest(startBotParams, this._abortController);\n    } catch (e) {\n      let errMsg = \"An unknown error occurred while starting the bot.\";\n      let status;\n      if (e instanceof Response) {\n        const errResp = await e.json();\n        errMsg = errResp.info ?? errResp.detail ?? e.statusText;\n        status = e.status;\n      } else if (e instanceof Error) {\n        errMsg = e.message;\n      }\n      this._options.callbacks?.onError?.(\n        new RTVIMessage(RTVIMessageType.ERROR_RESPONSE, {\n          message: errMsg,\n          fatal: true,\n        })\n      );\n      throw new RTVIErrors.StartBotError(errMsg, status);\n    }\n    this._transport.state = \"authenticated\";\n    this._options.callbacks?.onBotStarted?.(response);\n    return response;\n  }\n\n  /**\n   * The `connect` function establishes a transport session and awaits a\n   * bot-ready signal, handling various connection states and errors.\n   * @param {TransportConnectionParams} [connectParams] -\n   * The `connectParams` parameter in the `connect` method should be of type\n   * `TransportConnectionParams`. This parameter is passed to the transport\n   * for establishing a transport session.\n   * NOTE: `connectParams` as type `ConnectionEndpoint` IS NOW DEPRECATED. If you\n   * want to authenticate and connect to a bot in one step, use\n   * `startBotAndConnect()` instead.\n   * @returns The `connect` method returns a Promise that resolves to an unknown value.\n   */\n  @transportAlreadyStarted\n  public async connect(\n    connectParams?: TransportConnectionParams | ConnectionEndpoint\n  ): Promise<BotReadyData> {\n    if (connectParams && isAPIRequest(connectParams)) {\n      logger.warn(\n        \"Calling connect with an API endpoint is deprecated. Use startBotAndConnect() instead.\"\n      );\n      return this.startBotAndConnect(connectParams as APIRequest);\n    }\n\n    // Establish transport session and await bot ready signal\n    return new Promise((resolve, reject) => {\n      (async () => {\n        this._connectResolve = resolve;\n\n        if (this.needsInit()) {\n          await this.initDevices();\n        }\n\n        try {\n          await this._transport.connect(\n            connectParams as TransportConnectionParams\n          );\n          await this._transport.sendReadyMessage();\n        } catch (e) {\n          void this.disconnect();\n          reject(e);\n          return;\n        }\n      })();\n    });\n  }\n\n  @transportAlreadyStarted\n  public async startBotAndConnect(\n    startBotParams: APIRequest\n  ): Promise<BotReadyData> {\n    const connectionParams = await this.startBot(startBotParams);\n    return this.connect(connectionParams);\n  }\n\n  /**\n   * Disconnect the voice client from the transport\n   * Reset / reinitialize transport and abort any pending requests\n   */\n  public async disconnect(): Promise<void> {\n    this.stopUISnapshotStream();\n    await this._transport.disconnect();\n    this._messageDispatcher.disconnect();\n  }\n\n  /**\n   * The _initialize function performs internal set up of the transport and\n   * message dispatcher.\n   */\n  private _initialize() {\n    this._transport.initialize(this._options, this.handleMessage.bind(this));\n\n    // Create a new message dispatch queue for async message handling\n    this._messageDispatcher = new MessageDispatcher(\n      this._sendMessage.bind(this)\n    );\n  }\n\n  /**\n   * Apply a partial MediaState patch and emit MediaStateUpdated if the patch\n   * actually changes anything. The callback always receives a fresh object.\n   */\n  private _setMediaState(patch: Partial<MediaState>): void {\n    const next: MediaState = { ...this._mediaState, ...patch };\n    if (\n      this._statusEquals(next.mic, this._mediaState.mic) &&\n      this._statusEquals(next.cam, this._mediaState.cam)\n    ) {\n      return;\n    }\n    this._mediaState = next;\n    this._options.callbacks?.onMediaStateChanged?.(this.mediaState);\n    this.emit(RTVIEvent.MediaStateUpdated, this.mediaState);\n  }\n\n  /**\n   * Structural equality for two DeviceStatus values. Distinct error\n   * statuses (different `reason` or `details`) are treated as distinct so a\n   * status update fires when the underlying error changes, even if `state`\n   * was already 'error'.\n   */\n  private _statusEquals(a: DeviceStatus, b: DeviceStatus): boolean {\n    if (a.state !== b.state) return false;\n    if (a.state === \"error\" && b.state === \"error\") {\n      return a.reason === b.reason && a.details === b.details;\n    }\n    return true;\n  }\n\n  /**\n   * Map a DeviceError onto a partial MediaState patch and apply it. Mirrors\n   * daily-react's camera-error classifier — affected devices flip to an\n   * `'error'` status carrying the reason and the original error payload.\n   */\n  private _classifyAndApplyDeviceError(error: RTVIErrors.DeviceError): void {\n    const status: DeviceStatus = {\n      state: \"error\",\n      reason: deviceErrorReasonFromType(error.type),\n      details: error.details,\n    };\n    const patch: Partial<MediaState> = {};\n    if (error.devices.includes(\"mic\")) patch.mic = status;\n    if (error.devices.includes(\"cam\")) patch.cam = status;\n    if (Object.keys(patch).length === 0) return; // speaker-only or empty\n    this._setMediaState(patch);\n  }\n\n  /**\n   * Permissions API enrichment, run AFTER the transport's initDevices()\n   * resolves. By that point the prompt (if any) has been dismissed, and the\n   * Permissions API's `denied` answer is authoritative — it overrides any\n   * under-reported DeviceError.\n   *\n   * Concrete case worth flagging: on a page where the user previously\n   * blocked permissions, daily-js's `camera-error` only names whichever\n   * device the transport tried first when re-initializing — even though\n   * both are blocked. Re-querying here catches the missing one. Worth a\n   * follow-up daily-js ticket.\n   *\n   * Silently no-ops where the API is unavailable (Safari, some mobile\n   * browsers) or throws on an unsupported descriptor.\n   */\n  private async _enrichFromPermissionsAPI(): Promise<void> {\n    // PermissionDescriptor's `name` field isn't a standard enum across\n    // browsers (Safari historically narrower than Chrome/Firefox), and\n    // 'microphone' / 'camera' are not in lib.dom's PermissionName union in\n    // every TS version. Hand-roll the descriptor type and cast.\n    type PermDescriptor = { name: \"microphone\" | \"camera\" };\n    type Q = (descriptor: PermDescriptor) => Promise<{ state: string }>;\n    const permissions = (\n      globalThis as unknown as {\n        navigator?: { permissions?: { query: Q } };\n      }\n    ).navigator?.permissions;\n    if (!permissions?.query) return;\n    const query = permissions.query.bind(permissions);\n\n    const patch: Partial<MediaState> = {};\n    await Promise.all(\n      ([\"mic\", \"cam\"] as const).map(async (kind) => {\n        try {\n          const result = await query({\n            name: kind === \"mic\" ? \"microphone\" : \"camera\",\n          });\n          if (result.state === \"denied\") {\n            patch[kind] = { state: \"error\", reason: \"blocked\" };\n          }\n        } catch {\n          // Browsers may throw on unsupported descriptor names — swallow.\n        }\n      })\n    );\n    if (Object.keys(patch).length > 0) this._setMediaState(patch);\n  }\n\n  /**\n   * Internal wrapper around the transport's sendMessage method\n   */\n  private _sendMessage(message: RTVIMessage): void {\n    if (!messageSizeWithinLimit(message, this._transport.maxMessageSize)) {\n      const msg = `Message data too large. Max size is ${this._transport.maxMessageSize}`;\n      this._options.callbacks?.onError?.(RTVIMessage.error(msg, false));\n      throw new RTVIErrors.MessageTooLargeError(msg);\n    }\n\n    try {\n      this._transport.sendMessage(message);\n    } catch (error) {\n      if (error instanceof Error) {\n        this._options.callbacks?.onError?.(\n          RTVIMessage.error(error.message, false)\n        );\n      } else {\n        this._options.callbacks?.onError?.(\n          RTVIMessage.error(\"Unknown error sending message\", false)\n        );\n      }\n      throw error;\n    }\n  }\n\n  /**\n   * Get the current state of the transport\n   */\n  public get connected(): boolean {\n    return [\"connected\", \"ready\"].includes(this._transport.state);\n  }\n\n  public get transport(): Transport {\n    return this._transportWrapper.proxy;\n  }\n\n  public get state(): TransportState {\n    return this._transport.state;\n  }\n\n  /**\n   * Per-device device state (mic, cam). Independent of transport state.\n   *\n   * Updated by initDevices() and DeviceError events. Returns a snapshot — to\n   * track changes, subscribe to RTVIEvent.MediaStateUpdated or pass an\n   * onMediaStateChanged callback in the client constructor.\n   */\n  public get mediaState(): MediaState {\n    // Deep snapshot — DeviceStatus is a nested object, so a shallow spread\n    // would still hand the caller a reference to our per-device records.\n    return {\n      mic: { ...this._mediaState.mic },\n      cam: { ...this._mediaState.cam },\n    };\n  }\n\n  /**\n   * Whether initDevices() still has work to do. Returns true if any device\n   * the caller opted into (enableMic / enableCam) is still 'uninitialized'.\n   * Devices the caller opted out of are not considered — they stay\n   * 'uninitialized' by design and must not gate the implicit init.\n   *\n   * Used internally by connect() / startBot() to decide whether to drive an\n   * implicit initDevices(); exposed publicly so consumers (e.g. step 3's\n   * useMediaState hook) can branch on the same logic.\n   */\n  public needsInit(): boolean {\n    if (\n      this._options.enableMic !== false &&\n      this._mediaState.mic.state === \"uninitialized\"\n    ) {\n      return true;\n    }\n    if (\n      this._options.enableCam !== false &&\n      this._mediaState.cam.state === \"uninitialized\"\n    ) {\n      return true;\n    }\n    return false;\n  }\n\n  public get version(): string {\n    return packageJson.version;\n  }\n\n  // ------ Device methods\n\n  public async getAllMics(): Promise<MediaDeviceInfo[]> {\n    return await this._transport.getAllMics();\n  }\n\n  public async getAllCams(): Promise<MediaDeviceInfo[]> {\n    return await this._transport.getAllCams();\n  }\n\n  public async getAllSpeakers(): Promise<MediaDeviceInfo[]> {\n    return await this._transport.getAllSpeakers();\n  }\n\n  public get selectedMic() {\n    return this._transport.selectedMic;\n  }\n\n  public get selectedCam() {\n    try {\n      return this._transport.selectedCam;\n    } catch (e) {\n      if (e instanceof RTVIErrors.UnsupportedFeatureError) {\n        this._options.callbacks?.onUnsupportedFeature?.(e);\n        return {};\n      }\n      throw e;\n    }\n  }\n\n  public get selectedSpeaker() {\n    return this._transport.selectedSpeaker;\n  }\n\n  public updateMic(micId: string) {\n    this._transport.updateMic(micId);\n  }\n\n  public updateCam(camId: string) {\n    this._transport.updateCam(camId);\n  }\n\n  public updateSpeaker(speakerId: string) {\n    this._transport.updateSpeaker(speakerId);\n  }\n\n  public enableMic(enable: boolean) {\n    this._transport.enableMic(enable);\n  }\n\n  public get isMicEnabled(): boolean {\n    return this._transport.isMicEnabled;\n  }\n\n  public enableCam(enable: boolean) {\n    try {\n      this._transport.enableCam(enable);\n    } catch (e) {\n      if (e instanceof RTVIErrors.UnsupportedFeatureError) {\n        this._options.callbacks?.onUnsupportedFeature?.(e);\n      } else {\n        throw e;\n      }\n    }\n  }\n\n  public get isCamEnabled(): boolean {\n    return this._transport.isCamEnabled;\n  }\n\n  public tracks(): Tracks {\n    return this._transport.tracks();\n  }\n\n  public enableScreenShare(enable: boolean) {\n    try {\n      return this._transport.enableScreenShare(enable);\n    } catch (e) {\n      if (e instanceof RTVIErrors.UnsupportedFeatureError) {\n        this._options.callbacks?.onUnsupportedFeature?.(e);\n      } else {\n        throw e;\n      }\n    }\n  }\n\n  public get isSharingScreen(): boolean {\n    return this._transport.isSharingScreen;\n  }\n\n  // ------ Messages\n\n  /**\n   * Directly send a message to the bot via the transport.\n   * Do not await a response.\n   * @param msgType - a string representing the message type\n   * @param data - a dictionary of data to send with the message\n   */\n  @transportReady\n  public sendClientMessage(msgType: string, data?: unknown): void {\n    this._sendMessage(\n      new RTVIMessage(RTVIMessageType.CLIENT_MESSAGE, {\n        t: msgType,\n        d: data,\n      } as ClientMessageData)\n    );\n  }\n\n  /**\n   * Send a named UI event to the server as a first-class RTVI\n   * `ui-event` message.\n   *\n   * @param event - App-defined event.\n   * @param payload - App-defined payload. Optional.\n   */\n  @transportReady\n  public sendUIEvent(event: string, payload?: unknown): void {\n    const data: UIEventData = { event, payload };\n    this._sendMessage(new RTVIMessage(RTVIMessageType.UI_EVENT, data));\n  }\n\n  /**\n   * Start streaming UI snapshots to the server as\n   * first-class `ui-snapshot` RTVI messages.\n   *\n   * Calling this again replaces any existing managed streamer with\n   * the new options.\n   */\n  public startUISnapshotStream(\n    options: A11ySnapshotStreamerOptions = {}\n  ): void {\n    this.stopUISnapshotStream();\n    this._uiSnapshotStreamer = new A11ySnapshotStreamer((snapshot) => {\n      if (this.state !== \"ready\") {\n        this._pendingUISnapshot = snapshot;\n        return;\n      }\n      this._sendUISnapshot(snapshot);\n    }, options);\n    this._uiSnapshotStreamer.start();\n  }\n\n  /**\n   * Stop the managed UI snapshot stream, if one is active.\n   */\n  public stopUISnapshotStream(): void {\n    this._uiSnapshotStreamer?.stop();\n    this._uiSnapshotStreamer = undefined;\n    this._pendingUISnapshot = undefined;\n  }\n\n  private _sendUISnapshot(snapshot: A11ySnapshot): void {\n    const data: UISnapshotData = { tree: snapshot };\n    this._sendMessage(new RTVIMessage(RTVIMessageType.UI_SNAPSHOT, data));\n  }\n\n  private _flushPendingUISnapshot(): void {\n    if (!this._pendingUISnapshot || this.state !== \"ready\") return;\n    const snapshot = this._pendingUISnapshot;\n    this._pendingUISnapshot = undefined;\n    this._sendUISnapshot(snapshot);\n  }\n\n  /**\n   * Ask the server to cancel an in-flight UI job group.\n   *\n   * @param jobId - Shared job identifier of the group to cancel.\n   * @param reason - Optional human-readable reason logged on the server.\n   */\n  @transportReady\n  public cancelUIJobGroup(jobId: string, reason?: string): void {\n    const payload: UICancelJobGroupData = { job_id: jobId };\n    if (reason !== undefined) payload.reason = reason;\n    this._sendMessage(new RTVIMessage(RTVIMessageType.UI_CANCEL_JOB_GROUP, payload));\n  }\n\n  /**\n   * Directly send a message to the bot via the transport.\n   * Wait for and return the response.\n   * @param msgType - a string representing the message type\n   * @param data - a dictionary of data to send with the message\n   * @param timeout - optional timeout in milliseconds for the response\n   */\n  @transportReady\n  public async sendClientRequest(\n    msgType: string,\n    data: unknown,\n    timeout?: number\n  ) {\n    const msgData: ClientMessageData = { t: msgType, d: data };\n    const response = await this._messageDispatcher.dispatch(\n      msgData,\n      RTVIMessageType.CLIENT_MESSAGE,\n      timeout\n    );\n    const ret_data = response.data as ClientMessageData;\n    return ret_data.d;\n  }\n\n  public registerFunctionCallHandler(\n    functionName: string,\n    callback: FunctionCallCallback\n  ) {\n    this._functionCallCallbacks[functionName] = callback;\n  }\n\n  public unregisterFunctionCallHandler(functionName: string) {\n    delete this._functionCallCallbacks[functionName];\n  }\n\n  public unregisterAllFunctionCallHandlers() {\n    this._functionCallCallbacks = {};\n  }\n\n  @transportReady\n  public async appendToContext(context: LLMContextMessage) {\n    logger.warn(\"appendToContext() is deprecated. Use sendText() instead.\");\n    await this._sendMessage(\n      new RTVIMessage(RTVIMessageType.APPEND_TO_CONTEXT, {\n        role: context.role,\n        content: context.content,\n        run_immediately: context.run_immediately,\n      } as LLMContextMessage)\n    );\n    return true;\n  }\n\n  @transportReady\n  public async sendText(content: string, options: SendTextOptions = {}) {\n    await this._sendMessage(\n      new RTVIMessage(RTVIMessageType.SEND_TEXT, {\n        content,\n        options,\n      })\n    );\n  }\n\n  /**\n   * Disconnects the bot, but keeps the session alive\n   */\n  @transportReady\n  public disconnectBot(): void {\n    this._sendMessage(new RTVIMessage(RTVIMessageType.DISCONNECT_BOT, {}));\n  }\n\n  protected handleMessage(ev: RTVIMessage): void {\n    logger.debug(\"[RTVI Message]\", ev);\n\n    switch (ev.type) {\n      case RTVIMessageType.BOT_READY: {\n        const data = ev.data as BotReadyData;\n        const botVersion = data.version\n          ? data.version.split(\".\").map(Number)\n          : [0, 0, 0];\n        logger.debug(`[Pipecat Client] Bot is ready. Version: ${data.version}`);\n        if (botVersion[0] < 1) {\n          logger.warn(\n            \"[Pipecat Client] Bot version is less than 1.0.0, which may not be compatible with this client.\"\n          );\n        }\n        this._connectResolve?.(ev.data as BotReadyData);\n        this._options.callbacks?.onBotReady?.(ev.data as BotReadyData);\n        break;\n      }\n      case RTVIMessageType.ERROR:\n        this._options.callbacks?.onError?.(ev);\n        break;\n      case RTVIMessageType.SERVER_RESPONSE: {\n        this._messageDispatcher.resolve(ev);\n        break;\n      }\n      case RTVIMessageType.ERROR_RESPONSE: {\n        const resp = this._messageDispatcher.reject(ev);\n        this._options.callbacks?.onMessageError?.(resp as RTVIMessage);\n        break;\n      }\n      case RTVIMessageType.USER_STARTED_SPEAKING:\n        this._options.callbacks?.onUserStartedSpeaking?.();\n        break;\n      case RTVIMessageType.USER_STOPPED_SPEAKING:\n        this._options.callbacks?.onUserStoppedSpeaking?.();\n        break;\n      case RTVIMessageType.BOT_STARTED_SPEAKING:\n        this._options.callbacks?.onBotStartedSpeaking?.();\n        break;\n      case RTVIMessageType.BOT_STOPPED_SPEAKING:\n        this._options.callbacks?.onBotStoppedSpeaking?.();\n        break;\n      case RTVIMessageType.USER_MUTE_STARTED:\n        this._options.callbacks?.onUserMuteStarted?.();\n        break;\n      case RTVIMessageType.USER_MUTE_STOPPED:\n        this._options.callbacks?.onUserMuteStopped?.();\n        break;\n      case RTVIMessageType.USER_TRANSCRIPTION: {\n        const TranscriptData = ev.data as TranscriptData;\n        this._options.callbacks?.onUserTranscript?.(TranscriptData);\n        break;\n      }\n      case RTVIMessageType.BOT_OUTPUT: {\n        this._options.callbacks?.onBotOutput?.(ev.data as BotOutputData);\n        break;\n      }\n      case RTVIMessageType.BOT_TRANSCRIPTION: {\n        this._options.callbacks?.onBotTranscript?.(ev.data as BotLLMTextData);\n        break;\n      }\n      case RTVIMessageType.BOT_LLM_TEXT:\n        this._options.callbacks?.onBotLlmText?.(ev.data as BotLLMTextData);\n        break;\n      case RTVIMessageType.BOT_LLM_STARTED:\n        this._options.callbacks?.onBotLlmStarted?.();\n        break;\n      case RTVIMessageType.BOT_LLM_STOPPED:\n        this._options.callbacks?.onBotLlmStopped?.();\n        break;\n      case RTVIMessageType.BOT_TTS_TEXT:\n        this._options.callbacks?.onBotTtsText?.(ev.data as BotTTSTextData);\n        break;\n      case RTVIMessageType.BOT_TTS_STARTED:\n        this._options.callbacks?.onBotTtsStarted?.();\n        break;\n      case RTVIMessageType.BOT_TTS_STOPPED:\n        this._options.callbacks?.onBotTtsStopped?.();\n        break;\n      case RTVIMessageType.METRICS:\n        this._options.callbacks?.onMetrics?.(ev.data as PipecatMetricsData);\n        this.emit(RTVIEvent.Metrics, ev.data as PipecatMetricsData);\n        break;\n      case RTVIMessageType.SERVER_MESSAGE: {\n        this._options.callbacks?.onServerMessage?.(ev.data);\n        this.emit(RTVIEvent.ServerMessage, ev.data);\n        break;\n      }\n      case RTVIMessageType.UI_COMMAND: {\n        const data = ev.data as UICommandData;\n        this._options.callbacks?.onUICommand?.(data);\n        this.emit(RTVIEvent.UICommand, data);\n        break;\n      }\n      case RTVIMessageType.UI_JOB_GROUP: {\n        const data = ev.data as UIJobGroupData;\n        this._options.callbacks?.onUIJobGroup?.(data);\n        this.emit(RTVIEvent.UIJobGroup, data);\n        break;\n      }\n      case RTVIMessageType.LLM_FUNCTION_CALL_STARTED: {\n        const data = ev.data as LLMFunctionCallStartedData;\n        this._options.callbacks?.onLLMFunctionCallStarted?.(data);\n        this.emit(RTVIEvent.LLMFunctionCallStarted, data);\n        break;\n      }\n      case RTVIMessageType.LLM_FUNCTION_CALL_IN_PROGRESS: {\n        const data = ev.data as LLMFunctionCallInProgressData;\n        this._maybeTriggerFunctionCallCallback(data);\n        this._options.callbacks?.onLLMFunctionCallInProgress?.(data);\n        this.emit(RTVIEvent.LLMFunctionCallInProgress, data);\n        break;\n      }\n      case RTVIMessageType.LLM_FUNCTION_CALL_STOPPED: {\n        const data = ev.data as LLMFunctionCallStoppedData;\n        this._options.callbacks?.onLLMFunctionCallStopped?.(data);\n        this.emit(RTVIEvent.LLMFunctionCallStopped, data);\n        break;\n      }\n      case RTVIMessageType.LLM_FUNCTION_CALL: {\n        const data = ev.data as LLMFunctionCallData;\n        const inProgressData: LLMFunctionCallInProgressData = {\n          function_name: data.function_name,\n          tool_call_id: data.tool_call_id,\n          arguments: data.args,\n        };\n        this._maybeTriggerFunctionCallCallback(inProgressData);\n        if (this._options.callbacks?.onLLMFunctionCall) {\n          if (!this._llmFunctionCallWarned) {\n            logger.warn(\n              \"[Pipecat Client] onLLMFunctionCall is deprecated. Please use onLLMFunctionCallInProgress instead.\"\n            );\n            this._llmFunctionCallWarned = true;\n          }\n        }\n        this._options.callbacks?.onLLMFunctionCall?.(data);\n        this.emit(RTVIEvent.LLMFunctionCall, data);\n        break;\n      }\n      case RTVIMessageType.BOT_LLM_SEARCH_RESPONSE: {\n        const data = ev.data as BotLLMSearchResponseData;\n        this._options.callbacks?.onBotLlmSearchResponse?.(data);\n        this.emit(RTVIEvent.BotLlmSearchResponse, data);\n        break;\n      }\n      default: {\n        logger.debug(\"[Pipecat Client] Unrecognized message type\", ev.type);\n        break;\n      }\n    }\n  }\n\n  private _maybeTriggerFunctionCallCallback(\n    data: LLMFunctionCallInProgressData\n  ) {\n    // Function call callbacks are meant only for function calls that need information\n    // from the client to complete and generate a result. This process requires that\n    // the event includes the function name. For client-side logic meant simply to\n    // react to the fact that a function call is happening, you should use the\n    // traditional onLLMFunctionCallStarted/InProgress/Stopped events instead.\n    if (!data.function_name) return;\n    const fc = this._functionCallCallbacks[data.function_name];\n    if (fc) {\n      const params = {\n        functionName: data.function_name ?? \"\",\n        arguments: data.arguments ?? {},\n      };\n      fc(params)\n        .then((result) => {\n          if (result == undefined) {\n            return;\n          }\n          this._sendMessage(\n            new RTVIMessage(RTVIMessageType.LLM_FUNCTION_CALL_RESULT, {\n              function_name: data.function_name,\n              tool_call_id: data.tool_call_id,\n              arguments: data.arguments ?? {},\n              result,\n            } as LLMFunctionCallResultResponse)\n          );\n        })\n        .catch((error) => {\n          logger.error(\"Error in function call callback\", error);\n        });\n    }\n  }\n\n  // ------ Helpers\n}\n","/**\n * Copyright (c) 2024, Daily.\n *\n * SPDX-License-Identifier: BSD-2-Clause\n */\n\nexport * from \"./A11ySnapshotStreamer\";\nexport * from \"./client\";\nexport * from \"./dispatcher\";\nexport * from \"./logger\";\nexport * from \"./rest_helpers\";\nexport * from \"./transport\";\nexport * from \"./utils\";\n","/**\n * Copyright (c) 2024, Daily.\n *\n * SPDX-License-Identifier: BSD-2-Clause\n */\n\nexport * from \"./client\";\nexport * from \"./rtvi\";\n"],"names":[],"version":3,"file":"index.d.ts.map"}