@agentproto/pair-client 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/errors.ts","../src/channel.ts","../src/client.ts","../src/pair.ts","../src/credential.ts"],"names":["c","PAIR_VERSION"],"mappings":";;;;;;;;;;;;AA6BO,IAAM,iBAAA,GAAN,cAAgC,KAAA,CAAM;AAAA,EAClC,IAAA;AAAA,EACT,WAAA,CAAY,IAAA,EAA6B,OAAA,EAAiB,OAAA,EAA+B;AACvF,IAAA,KAAA,CAAM,SAAS,OAAO,CAAA;AACtB,IAAA,IAAA,CAAK,IAAA,GAAO,mBAAA;AACZ,IAAA,IAAA,CAAK,IAAA,GAAO,IAAA;AAAA,EACd;AACF;AAGO,SAAS,aAAa,UAAA,EAAuC;AAClE,EAAA,OAAO,IAAI,iBAAA;AAAA,IACT,SAAA;AAAA,IACA,iCAAiC,UAAU,CAAA,uBAAA;AAAA,GAC7C;AACF;AAGO,SAAS,aAAA,CAAc,MAAc,OAAA,EAAkD;AAC5F,EAAA,OAAO,IAAI,iBAAA;AAAA,IACT,mBAAA;AAAA,IACA,GAAG,IAAI,CAAA,+HAAA,CAAA;AAAA,IAEP;AAAA,GACF;AACF;AAEO,SAAS,OAAO,GAAA,EAAsB;AAC3C,EAAA,OAAO,GAAA,YAAe,KAAA,GAAQ,GAAA,CAAI,OAAA,GAAU,OAAO,GAAG,CAAA;AACxD;;;ACzBO,IAAM,oBAAA,GAAuB;AAE7B,IAAM,8BAAA,GAAiC,2BAAA;AAcvC,IAAM,uBAAA,GAA0B,IAAA;AAChC,IAAM,4BAAA,GAA+B,IAAA;AACrC,IAAM,2BAAA,GAA8B,GAAA;AAE3C,SAAS,mBAAA,CAAoB,MAAc,KAAA,EAAuB;AAChE,EAAA,MAAM,GAAA,GAAM,IAAA,CAAK,QAAA,CAAS,GAAG,IAAI,GAAA,GAAM,GAAA;AACvC,EAAA,OAAO,GAAG,IAAI,CAAA,EAAG,GAAG,CAAA,cAAA,EAAiB,kBAAA,CAAmB,KAAK,CAAC,CAAA,CAAA;AAChE;AAGO,SAAS,cAAA,CACd,aAAA,EACA,KAAA,EACA,aAAA,EACA,SAAA,EACoB;AACpB,EAAA,OAAO,IAAI,OAAA,CAAQ,CAAC,OAAA,EAAS,MAAA,KAAW;AACtC,IAAA,IAAI,EAAA;AACJ,IAAA,IAAI;AACF,MAAA,EAAA,GAAK,IAAI,aAAA,CAAc,mBAAA,CAAoB,aAAA,EAAe,KAAK,CAAC,CAAA;AAAA,IAClE,SAAS,GAAA,EAAK;AACZ,MAAA,MAAA,CAAO,GAAG,CAAA;AACV,MAAA;AAAA,IACF;AACA,IAAA,IAAI,OAAA,GAAU,KAAA;AACd,IAAA,MAAM,MAAA,GAAS,CAAC,EAAA,KAAyB;AACvC,MAAA,IAAI,OAAA,EAAS;AACb,MAAA,OAAA,GAAU,IAAA;AACV,MAAA,YAAA,CAAa,KAAK,CAAA;AAClB,MAAA,EAAA,CAAG,mBAAA,CAAoB,QAAQ,MAAM,CAAA;AACrC,MAAA,EAAA,CAAG,mBAAA,CAAoB,SAAS,MAAM,CAAA;AACtC,MAAA,EAAA,CAAG,mBAAA,CAAoB,SAAS,MAAM,CAAA;AACtC,MAAA,EAAA,EAAG;AAAA,IACL,CAAA;AACA,IAAA,MAAM,MAAA,GAAS,MACb,MAAA,CAAO,MAAM;AAIX,MAAA,IAAI,GAAG,UAAA,KAAe,CAAA,SAAU,IAAI,KAAA,CAAM,6CAA6C,CAAC,CAAA;AAAA,WACnF,OAAA,CAAQ,aAAA,CAAc,EAA8B,CAAC,CAAA;AAAA,IAC5D,CAAC,CAAA;AACH,IAAA,MAAM,MAAA,GAAS,MAAY,MAAA,CAAO,MAAM,OAAO,IAAI,KAAA,CAAM,wBAAwB,CAAC,CAAC,CAAA;AACnF,IAAA,MAAM,KAAA,GAAQ,UAAA;AAAA,MACZ,MACE,OAAO,MAAM;AACX,QAAA,IAAI;AACF,UAAA,EAAA,CAAG,KAAA,EAAM;AAAA,QACX,CAAA,CAAA,MAAQ;AAAA,QAER;AACA,QAAA,MAAA,CAAO,IAAI,KAAA,CAAM,CAAA,gCAAA,EAAmC,SAAS,IAAI,CAAC,CAAA;AAAA,MACpE,CAAC,CAAA;AAAA,MACH;AAAA,KACF;AACA,IAAA,EAAA,CAAG,gBAAA,CAAiB,QAAQ,MAAM,CAAA;AAClC,IAAA,EAAA,CAAG,gBAAA,CAAiB,SAAS,MAAM,CAAA;AACnC,IAAA,EAAA,CAAG,gBAAA,CAAiB,SAAS,MAAM,CAAA;AAAA,EACrC,CAAC,CAAA;AACH;AAqCA,eAAsB,YAAY,MAAA,EAAmD;AACnF,EAAA,MAAM,MAAM,MAAM,cAAA;AAAA,IAChB,MAAA,CAAO,aAAA;AAAA,IACP,MAAA,CAAO,KAAA;AAAA,IACP,MAAA,CAAO,SAAA;AAAA,IACP,OAAO,aAAA,IAAiB;AAAA,GAC1B;AACA,EAAA,IAAI,IAAA;AACJ,EAAA,IAAI,OAAA,GAAiC,IAAA;AACrC,EAAA,IAAI;AACF,IAAA,MAAM,OAAA,GAAU,MAAM,oBAAA,CAAqB;AAAA,MACzC,iBAAiB,MAAA,CAAO,eAAA;AAAA,MACxB,kBAAkB,MAAA,CAAO,gBAAA;AAAA,MACzB,WAAW,MAAA,CAAO,IAAA;AAAA,MAClB,YAAY,MAAA,CAAO;AAAA,KACpB,CAAA;AACD,IAAA,IAAA,GAAO,MAAM,uBAAA;AAAA,MACX,GAAA;AAAA,MACA,oBAAA,CAAqB,QAAQ,KAAK,CAAA;AAAA,MAClC,OAAM,KAAA,KAAS;AACb,QAAA,OAAA,GAAU,MAAM,OAAA,CAAQ,QAAA,CAAS,kBAAA,CAAmB,KAAK,CAAC,CAAA;AAC1D,QAAA,OAAO,OAAA;AAAA,MACT,CAAA;AAAA,MACA,EAAE,SAAA,EAAW,MAAA,CAAO,kBAAA,IAAsB,4BAAA;AAA6B,KACzE;AAAA,EACF,SAAS,GAAA,EAAK;AACZ,IAAA,GAAA,CAAI,MAAM,kBAAkB,CAAA;AAC5B,IAAA,MAAM,GAAA;AAAA,EACR;AACA,EAAA,IAAI,CAAC,OAAA,EAAS;AACZ,IAAA,IAAA,CAAK,MAAM,kBAAkB,CAAA;AAC7B,IAAA,MAAM,IAAI,MAAM,oCAAoC,CAAA;AAAA,EACtD;AAKA,EAAA,IAAI,MAAA,GAAgD,IAAA;AACpD,EAAA,MAAM,UAAyB,EAAC;AAChC,EAAA,IAAI,UAAA,GAAoD,IAAA;AACxD,EAAA,IAAA,CAAK,QAAQ,CAAA,KAAA,KAAS;AACpB,IAAA,IAAI,UAAA,EAAY;AACd,MAAA,MAAM,EAAA,GAAK,UAAA;AACX,MAAA,UAAA,GAAa,IAAA;AACb,MAAA,EAAA,CAAG,KAAK,CAAA;AACR,MAAA;AAAA,IACF;AACA,IAAA,IAAI,MAAA,SAAe,KAAK,CAAA;AAAA,SACnB,OAAA,CAAQ,KAAK,KAAK,CAAA;AAAA,EACzB,CAAC,CAAA;AAED,EAAA,MAAM,SAAA,GAAY,OAAO,iBAAA,IAAqB,2BAAA;AAC9C,EAAA,IAAI,QAAA;AACJ,EAAA,IAAI;AACF,IAAA,QAAA,GAAW,MAAM,IAAI,OAAA,CAAkB,CAAC,SAAS,MAAA,KAAW;AAC1D,MAAA,MAAM,KAAA,GAAQ,WAAW,MAAM,MAAA,CAAO,IAAI,KAAA,CAAM,6BAA6B,CAAC,CAAA,EAAG,SAAS,CAAA;AAC1F,MAAA,MAAM,QAAA,GAAW,IAAA,CAAK,OAAA,CAAQ,CAAA,MAAA,KAAU;AACtC,QAAA,YAAA,CAAa,KAAK,CAAA;AAClB,QAAA,MAAA,CAAO,IAAI,KAAA,CAAM,CAAA,0CAAA,EAA6C,MAAA,IAAU,QAAQ,EAAE,CAAC,CAAA;AAAA,MACrF,CAAC,CAAA;AACD,MAAA,UAAA,GAAa,CAAA,KAAA,KAAS;AACpB,QAAA,YAAA,CAAa,KAAK,CAAA;AAClB,QAAA,QAAA,EAAS;AACT,QAAA,IAAI,KAAA,CAAM,MAAM,OAAA,EAAS,OAAA,CAAQ,EAAE,IAAA,EAAM,OAAA,EAAS,KAAA,EAAO,KAAA,EAAO,CAAA;AAAA,aAAA,IACvD,KAAA,CAAM,CAAA,KAAM,OAAA,IAAW,KAAA,CAAM,IAAA,KAAS,oBAAA;AAC7C,UAAA,OAAA,CAAQ,EAAE,IAAA,EAAM,SAAA,EAAW,KAAA,EAAO,CAAA;AAAA,aAAA,IAC3B,KAAA,CAAM,CAAA,KAAM,OAAA,IAAW,KAAA,CAAM,IAAA,KAAS,8BAAA;AAC7C,UAAA,OAAA,CAAQ,EAAE,IAAA,EAAM,UAAA,EAAY,KAAA,EAAO,CAAA;AAAA,oBACzB,IAAI,KAAA,CAAM,4CAA4C,KAAA,CAAM,CAAC,GAAG,CAAC,CAAA;AAAA,MAC/E,CAAA;AAAA,IACF,CAAC,CAAA;AAAA,EACH,SAAS,GAAA,EAAK;AACZ,IAAA,IAAA,CAAK,MAAM,aAAa,CAAA;AACxB,IAAA,MAAM,GAAA;AAAA,EACR;AAEA,EAAA,OAAO;AAAA,IACL,IAAA;AAAA,IACA,OAAA;AAAA,IACA,QAAA;AAAA,IACA,MAAM,OAAA,EAAS;AACb,MAAA,MAAA,GAAS,OAAA;AACT,MAAA,KAAA,MAAW,KAAK,OAAA,CAAQ,MAAA,CAAO,CAAC,CAAA,UAAW,CAAC,CAAA;AAAA,IAC9C;AAAA,GACF;AACF;AAIO,SAAS,mBAAA,CAAoB,OAA0B,QAAA,EAA0B;AACtF,EAAA,IAAI,KAAA,EAAO,KAAA,EAAO,OAAO,KAAA,CAAM,KAAA;AAC/B,EAAA,MAAM,QAAA,GAAW,OAAO,MAAA,EAAQ,QAAA;AAChC,EAAA,MAAM,IAAA,GAAO,QAAA,EAAU,QAAA,CAAS,GAAG,CAAA,GAAI,QAAA,CAAS,KAAA,CAAM,QAAA,CAAS,OAAA,CAAQ,GAAG,CAAA,GAAI,CAAC,CAAA,GAAI,MAAA;AACnF,EAAA,OAAO,IAAA,IAAQ,QAAA;AACjB;AAEO,SAAS,gBAAA,GAAyC;AACvD,EAAA,MAAM,OAAQ,UAAA,CAAoD,SAAA;AAClE,EAAA,IAAI,CAAC,IAAA,EAAM;AACT,IAAA,MAAM,IAAI,iBAAA,CAAkB,SAAA,EAAW,mEAAmE,CAAA;AAAA,EAC5G;AACA,EAAA,OAAO,IAAA;AACT;;;ACrIA,IAAM,gBAAA,uBAAuB,GAAA,CAAI,CAAC,KAAK,GAAA,EAAK,GAAA,EAAK,GAAA,EAAK,GAAG,CAAC,CAAA;AAE1D,IAAM,qBAAA,uBAA4B,GAAA,CAAI,CAAC,cAAc,mBAAA,EAAqB,kBAAA,EAAoB,gBAAA,EAAkB,YAAY,CAAC,CAAA;AAC7H,IAAM,IAAA,GAAO,uBAAA;AAuBN,SAAS,OAAA,CAAQ,UAAA,EAA4B,IAAA,GAAuB,EAAC,EAAiB;AAC3F,EAAA,MAAM,GAAA,GAAM,IAAA,CAAK,GAAA,IAAO,IAAA,CAAK,GAAA;AAC7B,EAAA,MAAM,MAAA,GAAS,IAAA,CAAK,MAAA,IAAU,IAAA,CAAK,MAAA;AACnC,EAAA,MAAM,aAAA,GAAgB,IAAA,CAAK,SAAA,IAAa,gBAAA,EAAiB;AACzD,EAAA,MAAM,KAAA,GAAQ,KAAK,cAAA,IAAkB,GAAA;AACrC,EAAA,MAAM,KAAA,GAAQ,KAAK,cAAA,IAAkB,GAAA;AACrC,EAAA,MAAM,aAAA,GAAgB,KAAK,aAAA,IAAiB,GAAA;AAC5C,EAAA,MAAM,WAAA,GAAc,KAAK,WAAA,IAAe,IAAA;AACxC,EAAA,MAAM,aAAA,GAAgB,KAAK,aAAA,IAAiB,GAAA;AAC5C,EAAA,MAAM,OAAA,GAAU,IAAA,CAAK,OAAA,KAAY,CAAC,GAAA,KAAa,GAAG,GAAA,CAAI,QAAQ,CAAA,EAAG,GAAA,CAAI,MAAM,CAAA,CAAA,CAAA;AAC3E,EAAA,MAAM,SAAA,GAAY,KAAK,KAAA,CAAM,MAAA,KAAW,UAAW,CAAA,CAAE,SAAS,EAAE,CAAA;AAEhE,EAAA,IAAI,KAAA,GAAyB,YAAA;AAC7B,EAAA,IAAI,SAAA,GAAsC,IAAA;AAC1C,EAAA,IAAI,KAAA,GAA2B,IAAA;AAC/B,EAAA,IAAI,IAAA,GAAoB,IAAA;AACxB,EAAA,IAAI,OAAA,GAAU,KAAA;AACd,EAAA,IAAI,GAAA,GAAM,CAAA;AACV,EAAA,MAAM,SAAA,uBAAgB,GAAA,EAAmC;AAEzD,EAAA,IAAI,IAAA,GAA4B,IAAA;AAEhC,EAAA,MAAM,MAAA,GAAS,CAAC,MAAA,KAA8B;AAC5C,IAAA,KAAA,MAAW,CAAA,IAAK,CAAC,GAAG,SAAS,CAAA,EAAG;AAC9B,MAAA,IAAI;AACF,QAAA,CAAA,CAAE,MAAM,CAAA;AAAA,MACV,CAAA,CAAA,MAAQ;AAAA,MAER;AAAA,IACF;AAAA,EACF,CAAA;AAEA,EAAA,MAAM,QAAA,GAAW,CAAC,IAAA,EAAuB,KAAA,KAAoC;AAC3E,IAAA,IAAI,OAAO,SAAA,GAAY,KAAA;AACvB,IAAA,IAAI,IAAA,KAAS,KAAA,IAAS,CAAC,KAAA,EAAO;AAC9B,IAAA,KAAA,GAAQ,IAAA;AACR,IAAA,MAAA,CAAO,QAAQ,EAAE,KAAA,EAAO,OAAM,GAAI,EAAE,OAAO,CAAA;AAAA,EAC7C,CAAA;AAEA,EAAA,MAAM,WAAA,GAAc,CAAC,CAAA,EAAS,GAAA,KAAiC;AAC7D,IAAA,KAAA,MAAW,GAAG,CAAC,CAAA,IAAK,EAAE,OAAA,EAAS;AAC7B,MAAA,CAAA,CAAE,MAAA,EAAO;AACT,MAAA,IAAI,CAAC,EAAE,OAAA,EAAS;AACd,QAAA,CAAA,CAAE,OAAA,GAAU,IAAA;AACZ,QAAA,CAAA,CAAE,OAAO,GAAG,CAAA;AAAA,MACd,CAAA,MAAA,IAAW,EAAE,UAAA,EAAY;AACvB,QAAA,IAAI;AACF,UAAA,CAAA,CAAE,UAAA,CAAW,MAAM,GAAG,CAAA;AAAA,QACxB,CAAA,CAAA,MAAQ;AAAA,QAER;AAAA,MACF;AAAA,IACF;AACA,IAAA,CAAA,CAAE,QAAQ,KAAA,EAAM;AAAA,EAClB,CAAA;AAIA,EAAA,MAAM,KAAA,GAAQ,CAAC,EAAA,KACb,IAAI,QAAQ,CAAA,OAAA,KAAW;AACrB,IAAA,MAAM,KAAA,GAAQ,UAAA,CAAW,IAAA,EAAM,EAAE,CAAA;AACjC,IAAA,SAAS,IAAA,GAAa;AACpB,MAAA,YAAA,CAAa,KAAK,CAAA;AAClB,MAAA,IAAA,GAAO,IAAA;AACP,MAAA,OAAA,EAAQ;AAAA,IACV;AACA,IAAA,IAAA,GAAO,IAAA;AAAA,EACT,CAAC,CAAA;AAGH,EAAA,eAAe,SAAA,GAA8G;AAC3H,IAAA,MAAM,KAAA,GAAQ,YAAA,CAAa,GAAA,EAAK,CAAA;AAChC,IAAA,IAAI,OAAA;AACJ,IAAA,KAAA,MAAW,CAAA,IAAK,CAAC,KAAA,EAAO,KAAA,GAAQ,CAAC,CAAA,EAAG;AAClC,MAAA,IAAI,OAAA,EAAS;AACb,MAAA,IAAI;AACF,QAAA,MAAM,EAAE,OAAO,IAAA,EAAK,GAAI,MAAM,iBAAA,CAAkB,UAAA,CAAW,UAAU,CAAC,CAAA;AACtE,QAAA,MAAM,EAAA,GAAK,MAAM,WAAA,CAAY;AAAA,UAC3B,eAAe,UAAA,CAAW,aAAA;AAAA,UAC1B,KAAA;AAAA,UACA,IAAA;AAAA,UACA,iBAAiB,UAAA,CAAW,eAAA;AAAA,UAC5B,kBAAkB,UAAA,CAAW,gBAAA;AAAA,UAC7B,YAAY,UAAA,CAAW,UAAA;AAAA,UACvB,SAAA,EAAW,aAAA;AAAA,UACX,GAAI,KAAK,aAAA,KAAkB,KAAA,CAAA,GAAY,EAAE,aAAA,EAAe,IAAA,CAAK,aAAA,EAAc,GAAI,EAAC;AAAA,UAChF,GAAI,KAAK,kBAAA,KAAuB,KAAA,CAAA,GAAY,EAAE,kBAAA,EAAoB,IAAA,CAAK,kBAAA,EAAmB,GAAI,EAAC;AAAA,UAC/F,GAAI,KAAK,iBAAA,KAAsB,KAAA,CAAA,GAAY,EAAE,iBAAA,EAAmB,IAAA,CAAK,iBAAA,EAAkB,GAAI;AAAC,SAC7F,CAAA;AACD,QAAA,IAAI,EAAA,CAAG,QAAA,CAAS,IAAA,KAAS,SAAA,EAAW;AAClC,UAAA,EAAA,CAAG,IAAA,CAAK,MAAM,SAAS,CAAA;AACvB,UAAA,MAAM,YAAA,CAAa,WAAW,IAAI,CAAA;AAAA,QACpC;AACA,QAAA,IAAI,EAAA,CAAG,QAAA,CAAS,IAAA,KAAS,UAAA,EAAY;AACnC,UAAA,EAAA,CAAG,IAAA,CAAK,MAAM,UAAU,CAAA;AACxB,UAAA,MAAM,aAAA,CAAc,CAAA,2BAAA,EAA8B,UAAA,CAAW,IAAI,CAAA,CAAE,CAAA;AAAA,QACrE;AACA,QAAA,OAAO,EAAE,IAAA,EAAM,EAAA,CAAG,IAAA,EAAM,KAAA,EAAO,GAAG,QAAA,CAAS,KAAA,EAAO,KAAA,EAAO,EAAA,CAAG,KAAA,EAAM;AAAA,MACpE,SAAS,GAAA,EAAK;AACZ,QAAA,IAAI,GAAA,YAAe,sBAAsB,GAAA,CAAI,IAAA,KAAS,aAAa,GAAA,CAAI,IAAA,KAAS,sBAAsB,MAAM,GAAA;AAC5G,QAAA,OAAA,GAAU,GAAA;AAAA,MACZ;AAAA,IACF;AACA,IAAA,MAAM,IAAI,iBAAA;AAAA,MACR,SAAA;AAAA,MACA,CAAA,gBAAA,EAAmB,WAAW,IAAI,CAAA,KAAA,EAAQ,WAAW,aAAa,CAAA,EAAA,EAAK,MAAA,CAAO,OAAO,CAAC,CAAA,CAAA;AAAA,MACtF,EAAE,OAAO,OAAA;AAAQ,KACnB;AAAA,EACF;AAIA,EAAA,SAAS,MAAM,EAAA,EAA8E;AAC3F,IAAA,MAAM,CAAA,GAAU,EAAE,IAAA,EAAM,EAAA,CAAG,MAAM,OAAA,kBAAS,IAAI,KAAI,EAAE;AACpD,IAAA,IAAA,GAAO,CAAA;AACP,IAAA,KAAA,GAAQ,EAAA,CAAG,KAAA;AACX,IAAA,IAAI,OAAA,GAAoC,IAAA;AACxC,IAAA,IAAI,SAAA,GAAmD,IAAA;AACvD,IAAA,IAAI,SAAA,GAAkD,IAAA;AACtD,IAAA,IAAI,OAAA,GAAU,CAAA;AAEd,IAAA,OAAO,IAAI,QAAQ,CAAA,OAAA,KAAW;AAC5B,MAAA,EAAA,CAAG,MAAM,CAAA,KAAA,KAAS;AAChB,QAAA,QAAQ,MAAM,CAAA;AAAG,UACf,KAAK,eAAA;AAAA,UACL,KAAK,oBAAA;AAAA,UACL,KAAK,qBAAA;AACH,YAAA,WAAA,CAAY,GAAG,KAAK,CAAA;AACpB,YAAA;AAAA,UACF,KAAK,MAAA;AACH,YAAA,IAAI,SAAA,eAAwB,SAAS,CAAA;AACrC,YAAA,SAAA,GAAY,IAAA;AACZ,YAAA;AAAA,UACF,KAAK,MAAA;AACH,YAAA,CAAA,CAAE,IAAA,CAAK,KAAK,EAAE,CAAA,EAAG,QAAQ,KAAA,EAAO,KAAA,CAAM,OAAO,CAAA;AAC7C,YAAA;AAAA,UACF,KAAK,OAAA;AACH,YAAA,IAAI,KAAA,CAAM,SAAS,oBAAA,EAAsB;AACvC,cAAA,OAAA,GAAU,YAAA,CAAa,WAAW,IAAI,CAAA;AACtC,cAAA,CAAA,CAAE,IAAA,CAAK,MAAM,SAAS,CAAA;AAAA,YACxB;AACA,YAAA;AAAA,UACF;AACE,YAAA;AAAA;AACJ,MACF,CAAC,CAAA;AACD,MAAA,IAAI,cAAc,CAAA,EAAG;AACnB,QAAA,SAAA,GAAY,YAAY,MAAM;AAC5B,UAAA,IAAI,SAAA,EAAW;AACf,UAAA,CAAA,CAAE,IAAA,CAAK,IAAA,CAAK,EAAE,CAAA,EAAG,MAAA,EAAQ,OAAO,CAAA,GAAA,EAAM,EAAE,OAAO,CAAA,CAAA,EAAI,CAAA;AACnD,UAAA,SAAA,GAAY,WAAW,MAAM,CAAA,CAAE,KAAK,KAAA,CAAM,mBAAmB,GAAG,aAAa,CAAA;AAAA,QAC/E,GAAG,WAAW,CAAA;AAAA,MAChB;AACA,MAAA,CAAA,CAAE,IAAA,CAAK,QAAQ,MAAM;AACnB,QAAA,IAAI,SAAA,gBAAyB,SAAS,CAAA;AACtC,QAAA,IAAI,SAAA,eAAwB,SAAS,CAAA;AACrC,QAAA,IAAI,IAAA,KAAS,GAAG,IAAA,GAAO,IAAA;AACvB,QAAA,WAAA;AAAA,UACE,CAAA;AAAA,UACA,OAAA,KACG,OAAA,GACG,IAAI,iBAAA,CAAkB,QAAA,EAAU,8BAA8B,CAAA,GAC9D,IAAI,iBAAA,CAAkB,cAAA,EAAgB,CAAA,uBAAA,EAA0B,UAAA,CAAW,IAAI,CAAA,CAAE,CAAA;AAAA,SACzF;AACA,QAAA,OAAA,CAAQ,OAAO,CAAA;AAAA,MACjB,CAAC,CAAA;AACD,MAAA,IAAI,CAAC,CAAA,CAAE,IAAA,CAAK,MAAA,EAAQ;AAElB,QAAA,WAAA,CAAY,CAAA,EAAG,IAAI,iBAAA,CAAkB,cAAA,EAAgB,0BAA0B,UAAA,CAAW,IAAI,EAAE,CAAC,CAAA;AACjG,QAAA,OAAA,CAAQ,OAAO,CAAA;AAAA,MACjB;AAAA,IACF,CAAC,CAAA;AAAA,EACH;AAEA,EAAA,eAAe,GAAA,GAAqB;AAClC,IAAA,IAAI,OAAA,GAAU,CAAA;AACd,IAAA,OAAO,CAAC,OAAA,EAAS;AACf,MAAA,QAAA,CAAS,YAAY,CAAA;AACrB,MAAA,IAAI,EAAA;AACJ,MAAA,IAAI;AACF,QAAA,EAAA,GAAK,MAAM,SAAA,EAAU;AAAA,MACvB,SAAS,GAAA,EAAK;AACZ,QAAA,IAAI,OAAA,EAAS;AACb,QAAA,MAAM,CAAA,GAAI,GAAA,YAAe,iBAAA,GAAoB,GAAA,GAAM,IAAI,iBAAA,CAAkB,SAAA,EAAW,MAAA,CAAO,GAAG,CAAA,EAAG,EAAE,KAAA,EAAO,KAAK,CAAA;AAC/G,QAAA,IAAI,CAAA,CAAE,SAAS,SAAA,EAAW;AACxB,UAAA,QAAA,CAAS,WAAW,CAAC,CAAA;AACrB,UAAA;AAAA,QACF;AACA,QAAA,IAAI,CAAA,CAAE,SAAS,mBAAA,EAAqB;AAClC,UAAA,QAAA,CAAS,YAAY,CAAC,CAAA;AACtB,UAAA;AAAA,QACF;AACA,QAAA,QAAA,CAAS,WAAW,CAAC,CAAA;AACrB,QAAA,MAAM,KAAA,CAAM,OAAA,CAAQ,OAAA,EAAS,CAAC,CAAA;AAC9B,QAAA;AAAA,MACF;AACA,MAAA,IAAI,OAAA,EAAS;AACX,QAAA,EAAA,CAAG,IAAA,CAAK,MAAM,eAAe,CAAA;AAC7B,QAAA;AAAA,MACF;AACA,MAAA,OAAA,GAAU,CAAA;AACV,MAAA,MAAM,MAAA,GAAS,MAAM,EAAE,CAAA;AACvB,MAAA,QAAA,CAAS,MAAM,CAAA;AACf,MAAA,IAAI,KAAK,KAAA,EAAO;AACd,QAAA,KAAK,KAAK,KAAA,CAAM,GAAA,CAAI,EAAE,GAAG,YAAY,QAAA,EAAU,IAAI,IAAA,CAAK,GAAA,EAAK,CAAA,CAAE,WAAA,IAAe,CAAA,CAAE,MAAM,MAAM;AAAA,QAAC,CAAC,CAAA;AAAA,MAChG;AACA,MAAA,MAAM,UAAU,MAAM,MAAA;AACtB,MAAA,IAAI,OAAA,EAAS;AACb,MAAA,IAAI,OAAA,EAAS;AACX,QAAA,QAAA,CAAS,WAAW,OAAO,CAAA;AAC3B,QAAA;AAAA,MACF;AAEA,MAAA,QAAA,CAAS,SAAA,EAAW,IAAI,iBAAA,CAAkB,cAAA,EAAgB,0BAA0B,UAAA,CAAW,IAAI,EAAE,CAAC,CAAA;AACtG,MAAA,MAAM,KAAA,CAAM,OAAA,CAAQ,OAAA,EAAS,CAAC,CAAA;AAAA,IAChC;AAAA,EACF;AAGA,EAAA,SAAS,QAAQ,CAAA,EAAmB;AAClC,IAAA,MAAM,GAAA,GAAM,IAAA,CAAK,GAAA,CAAI,KAAA,EAAO,KAAA,GAAQ,KAAK,IAAA,CAAK,GAAA,CAAI,CAAA,EAAG,EAAE,CAAC,CAAA;AACxD,IAAA,OAAO,GAAA,GAAM,CAAA,GAAI,MAAA,EAAO,IAAK,GAAA,GAAM,CAAA,CAAA;AAAA,EACrC;AAIA,EAAA,SAAS,WAAA,CACP,GACA,KAAA,EACM;AACN,IAAA,MAAM,CAAA,GAAI,CAAA,CAAE,OAAA,CAAQ,GAAA,CAAI,MAAM,KAAK,CAAA;AACnC,IAAA,IAAI,CAAC,CAAA,EAAG;AACR,IAAA,IAAI,KAAA,CAAM,MAAM,eAAA,EAAiB;AAC/B,MAAA,CAAA,CAAE,OAAA,CAAQ,MAAA,CAAO,KAAA,CAAM,KAAK,CAAA;AAC5B,MAAA,CAAA,CAAE,MAAA,EAAO;AACT,MAAA,IAAI,EAAE,OAAA,EAAS;AACf,MAAA,CAAA,CAAE,OAAA,GAAU,IAAA;AACZ,MAAA,IAAI,OAA0B,KAAA,CAAM,IAAA,GAAO,UAAA,CAAW,KAAA,CAAM,IAAI,CAAA,GAAI,IAAA;AACpE,MAAA,IAAI,CAAC,IAAA,EAAM,MAAA,IAAU,KAAA,CAAM,KAAA,EAAO;AAChC,QAAA,IAAA,GAAO,IAAI,WAAA,EAAY,CAAE,MAAA,CAAO,IAAA,CAAK,UAAU,EAAE,KAAA,EAAO,KAAA,CAAM,KAAA,CAAM,MAAM,OAAA,EAAS,KAAA,CAAM,KAAA,CAAM,OAAA,EAAS,CAAC,CAAA;AAAA,MAC3G;AACA,MAAA,CAAA,CAAE,QAAQ,YAAA,CAAa,KAAA,CAAM,QAAQ,KAAA,CAAM,OAAA,EAAS,IAAI,CAAC,CAAA;AACzD,MAAA;AAAA,IACF;AACA,IAAA,IAAI,KAAA,CAAM,MAAM,oBAAA,EAAsB;AACpC,MAAA,IAAI,EAAE,OAAA,EAAS;AACf,MAAA,CAAA,CAAE,OAAA,GAAU,IAAA;AACZ,MAAA,MAAM,MAAA,GAAS,IAAI,cAAA,CAA2B;AAAA,QAC5C,KAAA,EAAO,CAAAA,EAAAA,KAAK;AACV,UAAA,CAAA,CAAE,UAAA,GAAaA,EAAAA;AAAA,QACjB,CAAA;AAAA,QACA,QAAQ,MAAM;AAGZ,UAAA,IAAI,EAAE,OAAA,CAAQ,GAAA,CAAI,KAAA,CAAM,KAAK,MAAM,CAAA,EAAG;AACpC,YAAA,CAAA,CAAE,OAAA,CAAQ,MAAA,CAAO,KAAA,CAAM,KAAK,CAAA;AAC5B,YAAA,CAAA,CAAE,MAAA,EAAO;AACT,YAAA,CAAA,CAAE,IAAA,CAAK,KAAK,EAAE,CAAA,EAAG,eAAe,KAAA,EAAO,KAAA,CAAM,OAAO,CAAA;AAAA,UACtD;AAAA,QACF;AAAA,OACD,CAAA;AACD,MAAA,CAAA,CAAE,QAAQ,YAAA,CAAa,KAAA,CAAM,QAAQ,KAAA,CAAM,OAAA,EAAS,MAAM,CAAC,CAAA;AAC3D,MAAA;AAAA,IACF;AAEA,IAAA,MAAM,IAAI,CAAA,CAAE,UAAA;AACZ,IAAA,IAAI,CAAC,CAAA,EAAG;AACR,IAAA,IAAI;AACF,MAAA,IAAI,MAAM,IAAA,EAAM,CAAA,CAAE,QAAQ,UAAA,CAAW,KAAA,CAAM,IAAI,CAAC,CAAA;AAChD,MAAA,IAAI,MAAM,KAAA,EAAO;AACf,QAAA,CAAA,CAAE,OAAA,CAAQ,MAAA,CAAO,KAAA,CAAM,KAAK,CAAA;AAC5B,QAAA,CAAA,CAAE,MAAA,EAAO;AACT,QAAA,CAAA,CAAE,KAAA,CAAM,IAAI,iBAAA,CAAkB,cAAA,EAAgB,CAAA,EAAG,KAAA,CAAM,KAAA,CAAM,IAAI,CAAA,EAAA,EAAK,KAAA,CAAM,KAAA,CAAM,OAAO,EAAE,CAAC,CAAA;AAAA,MAC9F,CAAA,MAAA,IAAW,MAAM,GAAA,EAAK;AACpB,QAAA,CAAA,CAAE,OAAA,CAAQ,MAAA,CAAO,KAAA,CAAM,KAAK,CAAA;AAC5B,QAAA,CAAA,CAAE,MAAA,EAAO;AACT,QAAA,CAAA,CAAE,KAAA,EAAM;AAAA,MACV;AAAA,IACF,CAAA,CAAA,MAAQ;AAAA,IAER;AAAA,EACF;AAEA,EAAA,SAAS,YAAY,MAAA,EAAoC;AACvD,IAAA,IAAI,UAAU,MAAA,IAAU,IAAA,EAAM,OAAO,OAAA,CAAQ,QAAQ,IAAI,CAAA;AACzD,IAAA,IAAI,KAAA,KAAU,WAAW,OAAO,OAAA,CAAQ,OAAO,SAAA,IAAa,YAAA,CAAa,UAAA,CAAW,IAAI,CAAC,CAAA;AACzF,IAAA,IAAI,KAAA,KAAU,UAAA,EAAY,OAAO,OAAA,CAAQ,MAAA,CAAO,SAAA,IAAa,aAAA,CAAc,CAAA,2BAAA,EAA8B,UAAA,CAAW,IAAI,CAAA,CAAE,CAAC,CAAA;AAC3H,IAAA,IAAI,KAAA,KAAU,UAAU,OAAO,OAAA,CAAQ,OAAO,IAAI,iBAAA,CAAkB,QAAA,EAAU,8BAA8B,CAAC,CAAA;AAC7G,IAAA,OAAO,IAAI,OAAA,CAAQ,CAAC,OAAA,EAAS,MAAA,KAAW;AACtC,MAAA,MAAM,IAAA,GAAO,CAAC,EAAA,KAAyB;AACrC,QAAA,YAAA,CAAa,KAAK,CAAA;AAClB,QAAA,GAAA,EAAI;AACJ,QAAA,MAAA,CAAO,mBAAA,CAAoB,SAAS,OAAO,CAAA;AAC3C,QAAA,EAAA,EAAG;AAAA,MACL,CAAA;AACA,MAAA,MAAM,KAAA,GAAQ,UAAA;AAAA,QACZ,MACE,IAAA;AAAA,UAAK,MACH,MAAA;AAAA,YACE,IAAI,iBAAA;AAAA,cACF,SAAA;AAAA,cACA,CAAA,EAAG,UAAA,CAAW,IAAI,CAAA,sCAAA,EAAyC,aAAa,SACrE,SAAA,GAAY,CAAA,EAAA,EAAK,SAAA,CAAU,OAAO,CAAA,CAAA,GAAK,EAAA,CAAA;AAAA,cAC1C,SAAA,GAAY,EAAE,KAAA,EAAO,SAAA,EAAU,GAAI;AAAA;AACrC;AACF,SACF;AAAA,QACF;AAAA,OACF;AACA,MAAA,MAAM,UAAU,MAAY,IAAA,CAAK,MAAM,MAAA,CAAO,MAAA,CAAO,MAAM,CAAC,CAAA;AAC5D,MAAA,MAAA,CAAO,gBAAA,CAAiB,SAAS,OAAO,CAAA;AACxC,MAAA,MAAM,MAAM,iBAAA,CAAkB,CAAC,EAAE,KAAA,EAAO,CAAA,EAAG,OAAM,KAAM;AACrD,QAAA,IAAI,CAAA,KAAM,UAAU,IAAA,EAAM;AACxB,UAAA,MAAM,CAAA,GAAI,IAAA;AACV,UAAA,IAAA,CAAK,MAAM,OAAA,CAAQ,CAAC,CAAC,CAAA;AAAA,QACvB,WAAW,CAAA,KAAM,SAAA,IAAa,CAAA,KAAM,UAAA,IAAc,MAAM,QAAA,EAAU;AAChE,UAAA,IAAA;AAAA,YAAK,MACH,MAAA;AAAA,cACE,KAAA,IACE,IAAI,iBAAA,CAAkB,CAAA,KAAM,aAAa,mBAAA,GAAsB,CAAA,EAAG,CAAA,qBAAA,EAAwB,CAAC,CAAA,CAAE;AAAA;AACjG,WACF;AAAA,QACF;AAAA,MACF,CAAC,CAAA;AAAA,IACH,CAAC,CAAA;AAAA,EACH;AAEA,EAAA,eAAe,WAAA,CAAY,OAA0B,IAAA,EAAuC;AAC1F,IAAA,MAAM,UACJ,KAAA,YAAiB,OAAA,GACb,OACE,IAAI,OAAA,CAAQ,OAAO,IAAI,CAAA,GACvB,QACF,IAAI,OAAA,CAAQ,IAAI,GAAA,CAAI,MAAA,CAAO,KAAK,CAAA,EAAG,IAAI,GAAG,IAAI,CAAA;AACpD,IAAA,MAAM,SAAS,OAAA,CAAQ,MAAA;AACvB,IAAA,IAAI,MAAA,CAAO,OAAA,EAAS,MAAM,MAAA,CAAO,MAAA;AACjC,IAAA,MAAM,MAAA,GAAS,OAAA,CAAQ,MAAA,CAAO,WAAA,EAAY;AAC1C,IAAA,MAAM,IAAA,GACJ,MAAA,KAAW,KAAA,IAAS,MAAA,KAAW,MAAA,GAAS,IAAA,GAAO,IAAI,UAAA,CAAW,MAAM,OAAA,CAAQ,WAAA,EAAa,CAAA;AAC3F,IAAA,MAAM,UAAkC,EAAC;AACzC,IAAA,OAAA,CAAQ,OAAA,CAAQ,OAAA,CAAQ,CAAC,KAAA,EAAO,GAAA,KAAQ;AACtC,MAAA,OAAA,CAAQ,GAAG,CAAA,GAAI,KAAA;AAAA,IACjB,CAAC,CAAA;AACD,IAAA,MAAM,OAAO,OAAA,CAAQ,IAAI,GAAA,CAAI,OAAA,CAAQ,GAAG,CAAC,CAAA;AACzC,IAAA,IAAI,CAAC,IAAA,CAAK,UAAA,CAAW,GAAG,CAAA,QAAS,IAAI,SAAA,CAAU,CAAA,sCAAA,EAAyC,IAAI,CAAA,EAAA,CAAI,CAAA;AAEhG,IAAA,MAAM,CAAA,GAAI,MAAM,WAAA,CAAY,MAAM,CAAA;AAClC,IAAA,IAAI,MAAA,CAAO,OAAA,EAAS,MAAM,MAAA,CAAO,MAAA;AAGjC,IAAA,IAAI,CAAC,CAAA,CAAE,IAAA,CAAK,MAAA,EAAQ;AAClB,MAAA,MAAM,IAAI,iBAAA,CAAkB,cAAA,EAAgB,CAAA,uBAAA,EAA0B,UAAA,CAAW,IAAI,CAAA,CAAE,CAAA;AAAA,IACzF;AACA,IAAA,MAAM,KAAA,GAAQ,GAAG,SAAS,CAAA,CAAA,EAAA,CAAK,EAAE,GAAA,EAAK,QAAA,CAAS,EAAE,CAAC,CAAA,CAAA;AAElD,IAAA,OAAO,IAAI,OAAA,CAAkB,CAAC,OAAA,EAAS,MAAA,KAAW;AAChD,MAAA,MAAM,UAAU,MAAY;AAC1B,QAAA,MAAM,CAAA,GAAI,CAAA,CAAE,OAAA,CAAQ,GAAA,CAAI,KAAK,CAAA;AAC7B,QAAA,IAAI,CAAC,CAAA,EAAG;AACR,QAAA,CAAA,CAAE,OAAA,CAAQ,OAAO,KAAK,CAAA;AACtB,QAAA,CAAA,CAAE,MAAA,EAAO;AACT,QAAA,CAAA,CAAE,KAAK,IAAA,CAAK,EAAE,CAAA,EAAG,aAAA,EAAe,OAAO,CAAA;AACvC,QAAA,IAAI,CAAC,EAAE,OAAA,EAAS;AACd,UAAA,CAAA,CAAE,OAAA,GAAU,IAAA;AACZ,UAAA,MAAA,CAAO,OAAO,MAAM,CAAA;AAAA,QACtB,CAAA,MAAO;AACL,UAAA,IAAI;AACF,YAAA,CAAA,CAAE,UAAA,EAAY,KAAA,CAAM,MAAA,CAAO,MAAM,CAAA;AAAA,UACnC,CAAA,CAAA,MAAQ;AAAA,UAER;AAAA,QACF;AAAA,MACF,CAAA;AACA,MAAA,MAAM,OAAA,GAAmB;AAAA,QACvB,OAAA;AAAA,QACA,MAAA;AAAA,QACA,UAAA,EAAY,IAAA;AAAA,QACZ,OAAA,EAAS,KAAA;AAAA,QACT,MAAA,EAAQ,MAAM,MAAA,CAAO,mBAAA,CAAoB,SAAS,OAAO;AAAA,OAC3D;AACA,MAAA,CAAA,CAAE,OAAA,CAAQ,GAAA,CAAI,KAAA,EAAO,OAAO,CAAA;AAC5B,MAAA,MAAA,CAAO,gBAAA,CAAiB,SAAS,OAAO,CAAA;AACxC,MAAA,MAAM,IAAA,GAAO;AAAA,QACX,CAAA,EAAG,cAAA;AAAA,QACH,KAAA;AAAA,QACA,MAAA;AAAA,QACA,IAAA;AAAA,QACA,GAAI,OAAO,IAAA,CAAK,OAAO,EAAE,MAAA,GAAS,EAAE,OAAA,EAAQ,GAAI;AAAC,OACnD;AACA,MAAA,IAAI,QAAQ,IAAA,CAAK,MAAA,GAAS,2BAA2B,KAAA,EAAO,YAAA,CAAa,sBAAsB,IAAA,EAAM;AAGnG,QAAA,CAAA,CAAE,KAAK,IAAA,CAAK,EAAE,GAAG,IAAA,EAAM,WAAA,EAAa,MAAM,CAAA;AAC1C,QAAA,MAAM,MAAA,GAAS,aAAa,IAAI,CAAA;AAChC,QAAA,MAAA,CAAO,OAAA,CAAQ,CAAC,KAAA,EAAO,CAAA,KAAM;AAC3B,UAAA,CAAA,CAAE,KAAK,IAAA,CAAK;AAAA,YACV,CAAA,EAAG,oBAAA;AAAA,YACH,KAAA;AAAA,YACA,IAAA,EAAM,WAAW,KAAK,CAAA;AAAA,YACtB,GAAI,MAAM,MAAA,CAAO,MAAA,GAAS,IAAI,EAAE,GAAA,EAAK,IAAA,EAAK,GAAI;AAAC,WAChD,CAAA;AAAA,QACH,CAAC,CAAA;AAAA,MACH,CAAA,MAAO;AACL,QAAA,CAAA,CAAE,KAAK,IAAA,CAAK,EAAE,GAAG,IAAA,EAAM,GAAI,IAAA,IAAQ,IAAA,CAAK,MAAA,GAAS,EAAE,MAAM,UAAA,CAAW,IAAI,GAAE,GAAI,IAAK,CAAA;AAAA,MACrF;AAAA,IACF,CAAC,CAAA;AAAA,EACH;AAIA,EAAA,SAAS,kBAAkB,QAAA,EAAqD;AAC9E,IAAA,SAAA,CAAU,IAAI,QAAQ,CAAA;AACtB,IAAA,OAAO,MAAM,SAAA,CAAU,MAAA,CAAO,QAAQ,CAAA;AAAA,EACxC;AAIA,EAAA,IAAI,UAAA,CAAW,aAAa,YAAA,EAAc;AACxC,IAAA,QAAA,CAAS,YAAY,aAAA,CAAc,CAAA,2BAAA,EAA8B,UAAA,CAAW,IAAI,EAAE,CAAC,CAAA;AAGnF,IAAA,cAAA,CAAe,MAAM;AACnB,MAAA,IAAI,KAAA,KAAU,cAAc,SAAA,EAAW,MAAA,CAAO,EAAE,KAAA,EAAO,KAAA,EAAO,WAAW,CAAA;AAAA,IAC3E,CAAC,CAAA;AAAA,EACH,CAAA,MAAO,KAAK,GAAA,EAAI,CAAE,MAAM,CAAA,GAAA,KAAO;AAC7B,IAAA,QAAA,CAAS,SAAA,EAAW,IAAI,iBAAA,CAAkB,SAAA,EAAW,MAAA,CAAO,GAAG,CAAA,EAAG,EAAE,KAAA,EAAO,GAAA,EAAK,CAAC,CAAA;AAAA,EACnF,CAAC,CAAA;AAED,EAAA,OAAO;AAAA,IACL,UAAA;AAAA,IACA,IAAI,KAAA,GAAQ;AACV,MAAA,OAAO,KAAA;AAAA,IACT,CAAA;AAAA,IACA,IAAI,KAAA,GAAQ;AACV,MAAA,OAAO,KAAA;AAAA,IACT,CAAA;AAAA,IACA,IAAI,SAAA,GAAY;AACd,MAAA,OAAO,SAAA;AAAA,IACT,CAAA;AAAA,IACA,aAAA,EAAe,iBAAA;AAAA,IACf,KAAA,GAAQ;AACN,MAAA,OAAO,WAAA,CAAY,IAAI,eAAA,EAAgB,CAAE,MAAM,CAAA,CAAE,IAAA,CAAK,MAAM,MAAS,CAAA;AAAA,IACvE,CAAA;AAAA,IACA,KAAA,EAAO,WAAA;AAAA,IACP,SAAA,GAAY;AACV,MAAA,IAAA,IAAO;AAAA,IACT,CAAA;AAAA,IACA,KAAA,GAAQ;AACN,MAAA,IAAI,OAAA,EAAS;AACb,MAAA,OAAA,GAAU,IAAA;AACV,MAAA,IAAA,IAAO;AACP,MAAA,MAAM,CAAA,GAAI,IAAA;AACV,MAAA,IAAA,GAAO,IAAA;AACP,MAAA,IAAI,CAAA,EAAG;AACL,QAAA,WAAA,CAAY,CAAA,EAAG,IAAI,iBAAA,CAAkB,QAAA,EAAU,8BAA8B,CAAC,CAAA;AAC9E,QAAA,CAAA,CAAE,IAAA,CAAK,MAAM,eAAe,CAAA;AAAA,MAC9B;AAGA,MAAA,IAAI,KAAA,KAAU,SAAA,IAAa,KAAA,KAAU,UAAA,WAAqB,QAAQ,CAAA;AAAA,IACpE;AAAA,GACF;AACF;AAEA,SAAS,YAAA,CACP,MAAA,EACA,OAAA,EACA,IAAA,EACU;AACV,EAAA,MAAM,CAAA,GAAI,IAAI,OAAA,EAAQ;AACtB,EAAA,KAAA,MAAW,CAAC,GAAG,CAAC,CAAA,IAAK,OAAO,OAAA,CAAQ,OAAA,IAAW,EAAE,CAAA,EAAG;AAClD,IAAA,IAAI,qBAAA,CAAsB,GAAA,CAAI,CAAA,CAAE,WAAA,EAAa,CAAA,EAAG;AAChD,IAAA,IAAI;AACF,MAAA,CAAA,CAAE,MAAA,CAAO,GAAG,CAAC,CAAA;AAAA,IACf,CAAA,CAAA,MAAQ;AAAA,IAER;AAAA,EACF;AAGA,EAAA,MAAM,CAAA,GAAI,OAAO,SAAA,CAAU,MAAM,KAAK,MAAA,IAAU,GAAA,IAAO,MAAA,IAAU,GAAA,GAAM,MAAA,GAAS,GAAA;AAChF,EAAA,IAAI,gBAAA,CAAiB,GAAA,CAAI,CAAC,CAAA,EAAG;AAC3B,IAAA,IAAI,gBAAgB,cAAA,EAAgB,KAAK,KAAK,MAAA,EAAO,CAAE,MAAM,MAAM;AAAA,IAAC,CAAC,CAAA;AACrE,IAAA,OAAO,IAAI,SAAS,IAAA,EAAM,EAAE,QAAQ,CAAA,EAAG,OAAA,EAAS,GAAG,CAAA;AAAA,EACrD;AACA,EAAA,OAAO,IAAI,SAAS,IAAA,EAAyB,EAAE,QAAQ,CAAA,EAAG,OAAA,EAAS,GAAG,CAAA;AACxE;ACrkBA,eAAe,KAAA,CAAM,UAAkB,GAAA,EAAoC;AACzE,EAAA,IAAI;AACF,IAAA,OAAO,MAAM,aAAA,CAAc,QAAA,EAAU,EAAE,KAAK,CAAA;AAAA,EAC9C,SAAS,GAAA,EAAK;AACZ,IAAA,IAAI,GAAA,YAAe,YAAA,IAAgB,GAAA,CAAI,IAAA,KAAS,2BAAA,EAA6B;AAC3E,MAAA,MAAM,aAAA,CAAc,iBAAA,EAAmB,EAAE,KAAA,EAAO,KAAK,CAAA;AAAA,IACvD;AACA,IAAA,MAAM,OAAA,GAAU,GAAA,YAAe,YAAA,IAAgB,GAAA,CAAI,IAAA,KAAS,eAAA;AAC5D,IAAA,MAAM,IAAI,iBAAA;AAAA,MACR,eAAA;AAAA,MACA,OAAA,GAAU,wEAAA,GAA2E,MAAA,CAAO,GAAG,CAAA;AAAA,MAC/F,EAAE,OAAO,GAAA;AAAI,KACf;AAAA,EACF;AACF;AAIA,eAAsB,YAAA,CACpB,QAAA,EACA,IAAA,GAAyB,EAAC,EACN;AACpB,EAAA,MAAM,KAAA,GAAQ,MAAM,KAAA,CAAM,QAAA,EAAU,KAAK,GAAA,IAAO,IAAA,CAAK,KAAK,CAAA;AAC1D,EAAA,OAAO;AAAA,IACL,aAAa,KAAA,CAAM,WAAA;AAAA,IACnB,eAAe,KAAA,CAAM,aAAA;AAAA,IACrB,SAAA,EAAW,IAAI,IAAA,CAAK,KAAA,CAAM,MAAM,GAAI;AAAA,GACtC;AACF;AAkCA,SAAS,iBAAA,GAA4B;AACnC,EAAA,MAAM,IAAA,GAAQ,WAAgD,QAAA,EAAU,IAAA;AACxE,EAAA,OAAO,IAAA,GAAO,CAAA,QAAA,EAAW,IAAI,CAAA,CAAA,GAAK,SAAA;AACpC;AAQA,eAAsB,aAAA,CACpB,QAAA,EACA,IAAA,GAA6B,EAAC,EACL;AACzB,EAAA,MAAM,GAAA,GAAM,IAAA,CAAK,GAAA,IAAO,IAAA,CAAK,GAAA;AAC7B,EAAA,MAAM,KAAA,GAAQ,MAAM,KAAA,CAAM,QAAA,EAAU,KAAK,CAAA;AACzC,EAAA,MAAM,UAAA,GAAa,IAAA,CAAK,UAAA,IAAc,iBAAA,EAAkB;AAExD,EAAA,IAAI,OAAA;AACJ,EAAA,IAAI;AAGF,IAAA,MAAM,EAAE,KAAA,EAAO,IAAA,KAAS,MAAM,iBAAA,CAAkB,MAAM,MAAM,CAAA;AAC5D,IAAA,OAAA,GAAU,MAAM,WAAA,CAAY;AAAA,MAC1B,eAAe,KAAA,CAAM,aAAA;AAAA,MACrB,KAAA;AAAA,MACA,IAAA;AAAA,MACA,iBAAiB,KAAA,CAAM,eAAA;AAAA,MACvB,kBAAkB,KAAA,CAAM,gBAAA;AAAA,MACxB,UAAA;AAAA,MACA,SAAA,EAAW,IAAA,CAAK,SAAA,IAAa,gBAAA,EAAiB;AAAA,MAC9C,GAAI,KAAK,aAAA,KAAkB,KAAA,CAAA,GAAY,EAAE,aAAA,EAAe,IAAA,CAAK,aAAA,EAAc,GAAI,EAAC;AAAA,MAChF,GAAI,KAAK,kBAAA,KAAuB,KAAA,CAAA,GAAY,EAAE,kBAAA,EAAoB,IAAA,CAAK,kBAAA,EAAmB,GAAI,EAAC;AAAA,MAC/F,GAAI,KAAK,iBAAA,KAAsB,KAAA,CAAA,GAAY,EAAE,iBAAA,EAAmB,IAAA,CAAK,iBAAA,EAAkB,GAAI;AAAC,KAC7F,CAAA;AAAA,EACH,SAAS,GAAA,EAAK;AACZ,IAAA,MAAM,IAAI,iBAAA,CAAkB,gBAAA,EAAkB,CAAA,2BAAA,EAA8B,KAAA,CAAM,WAAW,CAAA,EAAA,EAAK,MAAA,CAAO,GAAG,CAAC,CAAA,CAAA,EAAI;AAAA,MAC/G,KAAA,EAAO;AAAA,KACR,CAAA;AAAA,EACH;AACA,EAAA,MAAM,EAAE,IAAA,EAAM,OAAA,EAAS,QAAA,EAAS,GAAI,OAAA;AAIpC,EAAA,IAAI,OAAA,CAAQ,eAAA,KAAoB,KAAA,CAAM,WAAA,EAAa;AACjD,IAAA,IAAA,CAAK,MAAM,sBAAsB,CAAA;AACjC,IAAA,MAAM,IAAI,iBAAA;AAAA,MACR,gBAAA;AAAA,MACA,CAAA,mBAAA,EAAsB,OAAA,CAAQ,eAAe,CAAA,4BAAA,EAA+B,MAAM,WAAW,CAAA;AAAA,KAC/F;AAAA,EACF;AACA,EAAA,IAAI,QAAA,CAAS,SAAS,UAAA,EAAY;AAChC,IAAA,IAAA,CAAK,MAAM,UAAU,CAAA;AACrB,IAAA,MAAM,cAAc,aAAa,CAAA;AAAA,EACnC;AACA,EAAA,IAAI,QAAA,GAA0B,MAAM,cAAA,CAAe,OAAO,CAAA;AAE1D,EAAA,IAAA,CAAK,MAAM,eAAe,CAAA;AAE1B,EAAA,MAAM,KAAA,GAAQ,QAAA,CAAS,IAAA,KAAS,OAAA,GAAU,SAAS,KAAA,GAAQ,IAAA;AAC3D,EAAA,MAAM,MAAA,GAAuB;AAAA,IAC3B,aAAa,KAAA,CAAM,WAAA;AAAA,IACnB,IAAA,EAAM,mBAAA,CAAoB,KAAA,EAAO,KAAA,CAAM,WAAW,CAAA;AAAA,IAClD,GAAI,OAAO,KAAA,GAAQ,EAAE,OAAO,KAAA,CAAM,KAAA,KAAU,EAAC;AAAA,IAC7C,GAAI,KAAA,EAAO,MAAA,EAAQ,QAAA,GAAW,EAAE,UAAU,KAAA,CAAM,MAAA,CAAO,QAAA,EAAS,GAAI,EAAC;AAAA,IACrE,eAAe,KAAA,CAAM;AAAA,GACvB;AAEA,EAAA,OAAO;AAAA,IACL,MAAA;AAAA,IACA,MAAM,OAAA,GAAU;AACd,MAAA,MAAM,IAAA,GAAO,QAAA;AACb,MAAA,IAAI,SAAS,IAAA,EAAM,MAAM,IAAI,iBAAA,CAAkB,aAAa,iDAAiD,CAAA;AAC7G,MAAA,QAAA,GAAW,IAAA;AACX,MAAA,MAAM,SAAS,IAAI,IAAA,CAAK,GAAA,EAAK,EAAE,WAAA,EAAY;AAC3C,MAAA,MAAM,UAAA,GAA6B;AAAA,QACjC,QAAA,EAAUC,YAAAA;AAAA,QACV,IAAI,KAAA,CAAM,WAAA;AAAA,QACV,aAAa,KAAA,CAAM,WAAA;AAAA,QACnB,MAAM,MAAA,CAAO,IAAA;AAAA,QACb,UAAA;AAAA,QACA,iBAAiB,KAAA,CAAM,eAAA;AAAA,QACvB,kBAAkB,KAAA,CAAM,gBAAA;AAAA,QACxB,eAAe,KAAA,CAAM,aAAA;AAAA,QACrB,QAAA,EAAU,MAAM,iBAAA,CAAkB,IAAI,CAAA;AAAA,QACtC,SAAA,EAAW,MAAA;AAAA,QACX,QAAA,EAAU;AAAA,OACZ;AACA,MAAA,MAAM,IAAA,CAAK,KAAA,EAAO,GAAA,CAAI,UAAU,CAAA;AAChC,MAAA,OAAO,UAAA;AAAA,IACT,CAAA;AAAA,IACA,MAAA,GAAS;AACP,MAAA,QAAA,GAAW,IAAA;AAAA,IACb;AAAA,GACF;AACF;;;AC5IO,SAAS,2BAAA,CAA4B,OAAA,GAA4B,EAAC,EAAoB;AAC3F,EAAA,MAAM,IAAA,GAAO,IAAI,GAAA,CAAI,OAAA,CAAQ,GAAA,CAAI,CAAA,CAAA,KAAK,CAAC,CAAA,CAAE,EAAA,EAAI,CAAC,CAAC,CAAC,CAAA;AAChD,EAAA,OAAO;AAAA,IACL,MAAM,IAAI,EAAA,EAAI;AACZ,MAAA,OAAO,IAAA,CAAK,IAAI,EAAE,CAAA;AAAA,IACpB,CAAA;AAAA,IACA,MAAM,IAAI,UAAA,EAAY;AACpB,MAAA,IAAA,CAAK,GAAA,CAAI,UAAA,CAAW,EAAA,EAAI,UAAU,CAAA;AAAA,IACpC,CAAA;AAAA,IACA,MAAM,OAAO,EAAA,EAAI;AACf,MAAA,OAAO,IAAA,CAAK,OAAO,EAAE,CAAA;AAAA,IACvB,CAAA;AAAA,IACA,MAAM,IAAA,GAAO;AACX,MAAA,OAAO,CAAC,GAAG,IAAA,CAAK,MAAA,EAAQ,CAAA;AAAA,IAC1B;AAAA,GACF;AACF;AAiBO,SAAS,8BAAA,CACd,IAAA,GAAwC,EAAC,EACxB;AACjB,EAAA,MAAM,MAAA,GAAS,KAAK,MAAA,IAAU,iBAAA;AAC9B,EAAA,MAAM,SAAA,GAAY,KAAK,SAAA,IAAa,aAAA;AACpC,EAAA,IAAI,SAAA,GAAyC,IAAA;AAE7C,EAAA,MAAM,OAAO,MAA4B;AACvC,IAAA,IAAI,WAAW,OAAO,SAAA;AACtB,IAAA,MAAM,OAAA,GAAU,IAAA,CAAK,SAAA,IAAa,UAAA,CAAW,SAAA;AAC7C,IAAA,IAAI,CAAC,SAAS,OAAO,OAAA,CAAQ,OAAO,IAAI,KAAA,CAAM,4CAA4C,CAAC,CAAA;AAC3F,IAAA,SAAA,GAAY,IAAI,OAAA,CAAqB,CAAC,OAAA,EAAS,MAAA,KAAW;AACxD,MAAA,MAAM,GAAA,GAAM,OAAA,CAAQ,IAAA,CAAK,MAAA,EAAQ,CAAC,CAAA;AAClC,MAAA,GAAA,CAAI,kBAAkB,MAAM;AAC1B,QAAA,IAAI,CAAC,GAAA,CAAI,MAAA,CAAO,gBAAA,CAAiB,QAAA,CAAS,SAAS,CAAA,EAAG;AACpD,UAAA,GAAA,CAAI,OAAO,iBAAA,CAAkB,SAAA,EAAW,EAAE,OAAA,EAAS,MAAM,CAAA;AAAA,QAC3D;AAAA,MACF,CAAA;AACA,MAAA,GAAA,CAAI,SAAA,GAAY,MAAM,OAAA,CAAQ,GAAA,CAAI,MAAM,CAAA;AACxC,MAAA,GAAA,CAAI,OAAA,GAAU,MAAM,MAAA,CAAO,GAAA,CAAI,SAAS,IAAI,KAAA,CAAM,uBAAuB,CAAC,CAAA;AAAA,IAC5E,CAAC,CAAA;AACD,IAAA,SAAA,CAAU,MAAM,MAAM;AACpB,MAAA,SAAA,GAAY,IAAA;AAAA,IACd,CAAC,CAAA;AACD,IAAA,OAAO,SAAA;AAAA,EACT,CAAA;AAEA,EAAA,MAAM,GAAA,GAAM,OACV,IAAA,EACA,EAAA,KACe;AACf,IAAA,MAAM,EAAA,GAAK,MAAM,IAAA,EAAK;AACtB,IAAA,OAAO,IAAI,OAAA,CAAW,CAAC,OAAA,EAAS,MAAA,KAAW;AACzC,MAAA,MAAM,EAAA,GAAK,EAAA,CAAG,WAAA,CAAY,SAAA,EAAW,IAAI,CAAA;AACzC,MAAA,MAAM,GAAA,GAAM,EAAA,CAAG,EAAA,CAAG,WAAA,CAAY,SAAS,CAAC,CAAA;AACxC,MAAA,EAAA,CAAG,UAAA,GAAa,MAAM,OAAA,CAAQ,GAAA,CAAI,MAAM,CAAA;AACxC,MAAA,EAAA,CAAG,OAAA,GAAU,MAAM,MAAA,CAAO,EAAA,CAAG,KAAA,IAAS,IAAI,KAAA,IAAS,IAAI,KAAA,CAAM,0BAA0B,CAAC,CAAA;AACxF,MAAA,EAAA,CAAG,OAAA,GAAU,MAAM,MAAA,CAAO,EAAA,CAAG,SAAS,IAAI,KAAA,CAAM,+BAA+B,CAAC,CAAA;AAAA,IAClF,CAAC,CAAA;AAAA,EACH,CAAA;AAEA,EAAA,OAAO;AAAA,IACL,MAAM,IAAI,EAAA,EAAI;AACZ,MAAA,OAAQ,MAAM,IAAgC,UAAA,EAAY,CAAA,CAAA,KAAK,EAAE,GAAA,CAAI,EAAE,CAAC,CAAA,IAAM,MAAA;AAAA,IAChF,CAAA;AAAA,IACA,MAAM,IAAI,UAAA,EAAY;AACpB,MAAA,MAAM,IAAI,WAAA,EAAa,CAAA,CAAA,KAAK,CAAA,CAAE,GAAA,CAAI,UAAU,CAAC,CAAA;AAAA,IAC/C,CAAA;AAAA,IACA,MAAM,OAAO,EAAA,EAAI;AACf,MAAA,MAAM,QAAA,GAAW,MAAM,GAAA,CAAY,UAAA,EAAY,OAAK,CAAA,CAAE,KAAA,CAAM,EAAE,CAAC,CAAA;AAC/D,MAAA,IAAI,QAAA,KAAa,GAAG,OAAO,KAAA;AAC3B,MAAA,MAAM,IAAI,WAAA,EAAa,CAAA,CAAA,KAAK,CAAA,CAAE,MAAA,CAAO,EAAE,CAAC,CAAA;AACxC,MAAA,OAAO,IAAA;AAAA,IACT,CAAA;AAAA,IACA,MAAM,IAAA,GAAO;AACX,MAAA,OAAO,GAAA,CAAsB,UAAA,EAAY,CAAA,CAAA,KAAK,CAAA,CAAE,QAAQ,CAAA;AAAA,IAC1D;AAAA,GACF;AACF","file":"index.mjs","sourcesContent":["/**\n * The one error type this package throws, with a stable machine code so a UI\n * can branch on it (e.g. show \"scan a new pairing QR\" for `revoked`).\n */\n\nexport type TunnelClientErrorCode =\n /** The daemon told us (authenticated, inside the E2E channel) that this\n * pairing was revoked. Terminal: pair again from a new offer. */\n | \"revoked\"\n /** The offer or stored credential predates pairing protocol v2 (or the\n * daemon says so). Terminal: upgrade agentproto and pair again. */\n | \"protocol_outdated\"\n /** The daemon could not be reached (rendezvous dial, handshake or greeting\n * failed, or no connection came up within the wait). Retried with backoff. */\n | \"offline\"\n /** The live connection dropped while this request was in flight. */\n | \"disconnected\"\n /** `client.close()` was called. */\n | \"closed\"\n /** The offer URL is malformed or expired. */\n | \"invalid_offer\"\n /** The pairing handshake over the offer failed (bad daemon signature, spent\n * offer, fingerprint mismatch, timeout…). */\n | \"pairing_failed\"\n /** `confirm()` after `cancel()` (or a second `confirm()`). */\n | \"cancelled\"\n /** The daemon's upstream failed mid-stream (surfaced on the body stream). */\n | \"stream_error\"\n\nexport class TunnelClientError extends Error {\n readonly code: TunnelClientErrorCode\n constructor(code: TunnelClientErrorCode, message: string, options?: { cause?: unknown }) {\n super(message, options)\n this.name = \"TunnelClientError\"\n this.code = code\n }\n}\n\n/** The actionable message for a revoked pairing. */\nexport function revokedError(daemonName: string): TunnelClientError {\n return new TunnelClientError(\n \"revoked\",\n `this device was unpaired from ${daemonName}; scan a new pairing QR`,\n )\n}\n\n/** The actionable message for an offer / credential from before pair/v2. */\nexport function outdatedError(what: string, options?: { cause?: unknown }): TunnelClientError {\n return new TunnelClientError(\n \"protocol_outdated\",\n `${what} uses the retired pair/v1 protocol; upgrade agentproto on the daemon ` +\n \"and scan a new pairing QR (`agentproto pair offer --qr`)\",\n options,\n )\n}\n\nexport function errMsg(err: unknown): string {\n return err instanceof Error ? err.message : String(err)\n}\n","/**\n * One E2E channel to the daemon through the rendezvous: dial the broker, run\n * the `pair/v1` client handshake, and read the daemon's greeting.\n *\n * This is the Node client's `acceptOffer` / `openPairChannel` sequence\n * (`packages/cli/src/util/pair-transport.ts`) — same upgrade URL, same pair/v2\n * hello (static keys pinned, the client name, and the AUTH token sealed to the\n * daemon's key), same verification — built only from the browser-safe\n * entries, so the daemon can't tell the two clients apart. The ROUTE token is\n * the only thing on the broker URL; the auth token never leaves the sealed\n * hello.\n */\n\nimport {\n clientHandshakeOverSink,\n wrapWebSocket,\n type E2eFrameSink,\n type ErrorFrame,\n type FrameSink,\n type HelloFrame,\n type TunnelFrame,\n type WebSocketLike,\n} from \"@agentproto/acp/tunnel/browser\"\nimport {\n decodePairingReply,\n encodePairingMessage,\n startClientHandshake,\n type PairingSession,\n} from \"@agentproto/secrets/pairing/browser\"\nimport { TunnelClientError } from \"./errors.js\"\n\n/** The tunnel `error` code the daemon answers a revoked pairing with\n * (`PAIRING_REVOKED_CODE` in `@agentproto/runtime`'s pairing registry). */\nexport const PAIRING_REVOKED_CODE = \"pairing_revoked\"\n/** The tunnel `error` code (and `PairingError` code) for a pre-v2 pairing. */\nexport const PAIRING_PROTOCOL_OUTDATED_CODE = \"pairing_protocol_outdated\"\n\n/** A WHATWG `WebSocket` constructor (the global one by default). */\nexport type WebSocketConstructor = new (url: string) => WebSocket\n\nexport interface ChannelTimeouts {\n /** Rendezvous dial ceiling. Default 15s (as the CLI). */\n dialTimeoutMs?: number\n /** Handshake ceiling. Default 15s (as the CLI). */\n handshakeTimeoutMs?: number\n /** How long to wait for the daemon's first tunnel frame. Default 10s. */\n greetingTimeoutMs?: number\n}\n\nexport const DEFAULT_DIAL_TIMEOUT_MS = 15_000\nexport const DEFAULT_HANDSHAKE_TIMEOUT_MS = 15_000\nexport const DEFAULT_GREETING_TIMEOUT_MS = 10_000\n\nfunction rendezvousClientUrl(base: string, token: string): string {\n const sep = base.includes(\"?\") ? \"&\" : \"?\"\n return `${base}${sep}side=client&t=${encodeURIComponent(token)}`\n}\n\n/** Open a WebSocket to the broker and adapt it to a `FrameSink`. */\nexport function dialRendezvous(\n rendezvousUrl: string,\n token: string,\n WebSocketImpl: WebSocketConstructor,\n timeoutMs: number,\n): Promise<FrameSink> {\n return new Promise((resolve, reject) => {\n let ws: WebSocket\n try {\n ws = new WebSocketImpl(rendezvousClientUrl(rendezvousUrl, token))\n } catch (err) {\n reject(err)\n return\n }\n let settled = false\n const finish = (fn: () => void): void => {\n if (settled) return\n settled = true\n clearTimeout(timer)\n ws.removeEventListener(\"open\", onOpen)\n ws.removeEventListener(\"error\", onFail)\n ws.removeEventListener(\"close\", onFail)\n fn()\n }\n const onOpen = (): void =>\n finish(() => {\n // The broker can refuse on arrival (e.g. token in use) in the same\n // tick as the upgrade; a socket that is already closing is a failed\n // dial, not a sink that would silently eat the handshake.\n if (ws.readyState !== 1) reject(new Error(\"rendezvous closed the connection on arrival\"))\n else resolve(wrapWebSocket(ws as unknown as WebSocketLike))\n })\n const onFail = (): void => finish(() => reject(new Error(\"rendezvous dial failed\")))\n const timer = setTimeout(\n () =>\n finish(() => {\n try {\n ws.close()\n } catch {\n /* ignore */\n }\n reject(new Error(`rendezvous dial timed out after ${timeoutMs}ms`))\n }),\n timeoutMs,\n )\n ws.addEventListener(\"open\", onOpen)\n ws.addEventListener(\"error\", onFail)\n ws.addEventListener(\"close\", onFail)\n })\n}\n\nexport interface OpenChannelParams extends ChannelTimeouts {\n rendezvousUrl: string\n /** The ROUTE token: the only value that goes on the broker URL. From the\n * offer secret (first contact) or the pair root + epoch (reconnect). */\n route: string\n /** The AUTH token: sealed into the hello, never on a URL. */\n auth: string\n daemonX25519Pub: string\n daemonEd25519Pub: string\n clientName: string\n WebSocket: WebSocketConstructor\n}\n\nexport type Greeting =\n | { kind: \"hello\"; hello: HelloFrame }\n | { kind: \"revoked\"; frame: ErrorFrame }\n | { kind: \"outdated\"; frame: ErrorFrame }\n\nexport interface OpenedChannel {\n sink: E2eFrameSink\n session: PairingSession\n /** The daemon's first frame, `hello` — or its `pairing_revoked` refusal. */\n greeting: Greeting\n /** Detach the greeting reader and route every later frame to `handler`.\n * Frames that arrived after the greeting and before this call are replayed\n * first, in order. */\n route(handler: (frame: TunnelFrame) => void): void\n}\n\n/**\n * Dial, handshake, and read the greeting. Rejects (closing the socket) on any\n * failure; a `pairing_revoked` greeting resolves — the caller decides what it\n * means. The daemon signature is verified against the pinned Ed25519 key by\n * the handshake itself, so a greeting is authenticated.\n */\nexport async function openChannel(params: OpenChannelParams): Promise<OpenedChannel> {\n const raw = await dialRendezvous(\n params.rendezvousUrl,\n params.route,\n params.WebSocket,\n params.dialTimeoutMs ?? DEFAULT_DIAL_TIMEOUT_MS,\n )\n let sink: E2eFrameSink\n let session: PairingSession | null = null\n try {\n const started = await startClientHandshake({\n daemonX25519Pub: params.daemonX25519Pub,\n daemonEd25519Pub: params.daemonEd25519Pub,\n authToken: params.auth,\n clientName: params.clientName,\n })\n sink = await clientHandshakeOverSink(\n raw,\n encodePairingMessage(started.hello),\n async reply => {\n session = await started.complete(decodePairingReply(reply))\n return session\n },\n { timeoutMs: params.handshakeTimeoutMs ?? DEFAULT_HANDSHAKE_TIMEOUT_MS },\n )\n } catch (err) {\n raw.close(\"handshake failed\")\n throw err\n }\n if (!session) {\n sink.close(\"handshake failed\")\n throw new Error(\"handshake did not derive a session\")\n }\n\n // One subscription for the channel's whole life (wrapE2E replays early\n // frames to its FIRST subscriber only): the greeting is read here, the rest\n // is buffered until the caller routes it.\n let router: ((frame: TunnelFrame) => void) | null = null\n const backlog: TunnelFrame[] = []\n let onGreeting: ((frame: TunnelFrame) => void) | null = null\n sink.onFrame(frame => {\n if (onGreeting) {\n const cb = onGreeting\n onGreeting = null\n cb(frame)\n return\n }\n if (router) router(frame)\n else backlog.push(frame)\n })\n\n const timeoutMs = params.greetingTimeoutMs ?? DEFAULT_GREETING_TIMEOUT_MS\n let greeting: Greeting\n try {\n greeting = await new Promise<Greeting>((resolve, reject) => {\n const timer = setTimeout(() => reject(new Error(\"no greeting from the daemon\")), timeoutMs)\n const offClose = sink.onClose(reason => {\n clearTimeout(timer)\n reject(new Error(`channel closed before the daemon greeted: ${reason ?? \"closed\"}`))\n })\n onGreeting = frame => {\n clearTimeout(timer)\n offClose()\n if (frame.t === \"hello\") resolve({ kind: \"hello\", hello: frame })\n else if (frame.t === \"error\" && frame.code === PAIRING_REVOKED_CODE)\n resolve({ kind: \"revoked\", frame })\n else if (frame.t === \"error\" && frame.code === PAIRING_PROTOCOL_OUTDATED_CODE)\n resolve({ kind: \"outdated\", frame })\n else reject(new Error(`unexpected first frame from the daemon: \"${frame.t}\"`))\n }\n })\n } catch (err) {\n sink.close(\"no greeting\")\n throw err\n }\n\n return {\n sink,\n session,\n greeting,\n route(handler) {\n router = handler\n for (const f of backlog.splice(0)) handler(f)\n },\n }\n}\n\n/** Human-friendly daemon name from its hello: the `label`, else the host part\n * of `daemon.platform` (`<os>/<hostname>`), else the fallback. */\nexport function daemonNameFromHello(hello: HelloFrame | null, fallback: string): string {\n if (hello?.label) return hello.label\n const platform = hello?.daemon?.platform\n const host = platform?.includes(\"/\") ? platform.slice(platform.indexOf(\"/\") + 1) : undefined\n return host || fallback\n}\n\nexport function defaultWebSocket(): WebSocketConstructor {\n const ctor = (globalThis as { WebSocket?: WebSocketConstructor }).WebSocket\n if (!ctor) {\n throw new TunnelClientError(\"offline\", \"no WebSocket implementation in this context (pass opts.WebSocket)\")\n }\n return ctor\n}\n","/**\n * `connect(credential)` — a long-lived, self-healing tunnel to a paired\n * daemon, with a WHATWG `fetch` on top.\n *\n * Connection: the CLI's `openPairChannel` sequence (epoch routing token for\n * today, then yesterday's to bridge clock skew; a fresh handshake each time),\n * kept up with jittered, capped exponential backoff. A live channel is watched\n * with ping/pong so a half-open socket is noticed.\n *\n * State (for a UI): `connecting` → `open`; on failure or drop → `offline`\n * (while waiting to retry) → `connecting` …; `revoked`, `outdated` and\n * `closed` are terminal. `revoked` is only ever entered on the daemon's\n * authenticated `pairing_revoked` frame — never on anything the broker could\n * fake — and stops all retries. `outdated` means the credential predates\n * pair/v2 (it is never dialed) or the daemon said so, authenticated, the same\n * way.\n *\n * Tokens (pair/v2): each attempt derives the epoch ROUTE — the only value on\n * the broker URL — and the epoch AUTH, which is sealed into the hello and\n * never leaves it.\n *\n * Requests: `http_request` frames multiplexed over the one channel by `reqId`.\n * The response resolves at the daemon's `http_response` (buffered) or\n * `http_response_head` (streamed: SSE / NDJSON), whose body is then a\n * `ReadableStream` fed chunk by chunk as `http_response_chunk` frames arrive.\n * Aborting (the request's signal, or cancelling the body) sends\n * `http_cancel`. In-flight requests fail with `disconnected` when the channel\n * drops; new ones wait for the (re)connection, up to `requestWaitMs`.\n */\n\nimport {\n MAX_FRAME_PAYLOAD_BYTES,\n decodeData,\n encodeData,\n splitPayload,\n type E2eFrameSink,\n type HelloFrame,\n type TunnelFrame,\n} from \"@agentproto/acp/tunnel/browser\"\nimport { currentEpoch, deriveEpochTokens, PAIR_VERSION } from \"@agentproto/secrets/pairing/browser\"\nimport {\n defaultWebSocket,\n openChannel,\n PAIRING_REVOKED_CODE,\n type ChannelTimeouts,\n type WebSocketConstructor,\n} from \"./channel.js\"\nimport type { CredentialStore, PairCredential } from \"./credential.js\"\nimport { errMsg, outdatedError, revokedError, TunnelClientError } from \"./errors.js\"\n\nexport type ConnectionState = \"connecting\" | \"open\" | \"offline\" | \"revoked\" | \"outdated\" | \"closed\"\n\nexport interface ConnectOptions extends ChannelTimeouts {\n /** WebSocket constructor. Default: the global `WebSocket`. */\n WebSocket?: WebSocketConstructor\n /** When set, `lastSeen` is refreshed there after each (re)connect\n * (best-effort, as the CLI does). */\n store?: CredentialStore\n /** First retry delay. Default 500ms. */\n reconnectMinMs?: number\n /** Retry delay ceiling. Default 30s. */\n reconnectMaxMs?: number\n /** How long a request waits for a connection before failing `offline`.\n * Default 20s. */\n requestWaitMs?: number\n /** Ping interval on a live channel. Default 25s; `0` disables. */\n keepAliveMs?: number\n /** A ping unanswered this long drops the channel (and reconnects).\n * Default 10s. */\n pongTimeoutMs?: number\n /** Map a request URL to the daemon path (path + query, must start with `/`).\n * Default: `url.pathname + url.search`. A service worker uses this to strip\n * its scope prefix. */\n mapPath?: (url: URL) => string\n /** Clock (ms). Default `Date.now`. */\n now?: () => number\n /** Random source for backoff jitter, in [0, 1). Default `Math.random`. */\n random?: () => number\n}\n\nexport interface StateChange {\n state: ConnectionState\n /** Why we're `offline` / `revoked` / `outdated` / `closed` (the last failure). */\n error?: TunnelClientError\n}\n\nexport interface TunnelClient {\n /** The pairing this client serves. */\n readonly credential: PairCredential\n readonly state: ConnectionState\n /** The daemon's hello on the current (or last) channel. */\n readonly hello: HelloFrame | null\n /** The most recent connection failure, if any. */\n readonly lastError: TunnelClientError | null\n /** Subscribe to state changes. Returns an unsubscribe function. */\n onStateChange(listener: (change: StateChange) => void): () => void\n /** Resolves once connected; rejects with `revoked` / `protocol_outdated` /\n * `closed`, or `offline`\n * when no connection came up within `requestWaitMs`. */\n ready(): Promise<void>\n /** A WHATWG `fetch` through the daemon. Relative URLs are fine: only the\n * path + query (see `mapPath`) is sent. Rejects with `TunnelClientError`\n * (`offline` / `disconnected` / `revoked` / `protocol_outdated` / `closed`)\n * where `fetch` would\n * reject with a network error, or with the signal's reason on abort. */\n fetch(input: RequestInfo | URL, init?: RequestInit): Promise<Response>\n /** Skip the current backoff wait and retry now (e.g. on `online`). */\n reconnect(): void\n /** Close the channel and stop reconnecting. Pending requests fail `closed`.\n * The state becomes `closed`, except that a terminal `revoked` / `outdated`\n * is kept (with its `lastError`). */\n close(): void\n}\n\nconst NULL_BODY_STATUS = new Set([101, 103, 204, 205, 304])\n/** Response headers that describe the daemon↔upstream hop, not this body. */\nconst DROP_RESPONSE_HEADERS = new Set([\"connection\", \"transfer-encoding\", \"content-encoding\", \"content-length\", \"keep-alive\"])\nconst BASE = \"http://tunnel.invalid\"\n\ninterface Pending {\n /** Before the head: settle the `fetch` promise. */\n resolve(res: Response): void\n reject(err: unknown): void\n /** After a streamed head: the body's controller. */\n controller: ReadableStreamDefaultController<Uint8Array> | null\n settled: boolean\n detach(): void\n}\n\ninterface Live {\n sink: E2eFrameSink\n pending: Map<string, Pending>\n}\n\n/**\n * Connect to a paired daemon. Returns immediately; the client connects in the\n * background (watch `state` / `onStateChange`, or `await client.ready()`).\n * One client per credential: the daemon keeps one standing channel per epoch\n * slot, so share this instance rather than connecting twice.\n */\nexport function connect(credential: PairCredential, opts: ConnectOptions = {}): TunnelClient {\n const now = opts.now ?? Date.now\n const random = opts.random ?? Math.random\n const WebSocketImpl = opts.WebSocket ?? defaultWebSocket()\n const minMs = opts.reconnectMinMs ?? 500\n const maxMs = opts.reconnectMaxMs ?? 30_000\n const requestWaitMs = opts.requestWaitMs ?? 20_000\n const keepAliveMs = opts.keepAliveMs ?? 25_000\n const pongTimeoutMs = opts.pongTimeoutMs ?? 10_000\n const mapPath = opts.mapPath ?? ((url: URL) => `${url.pathname}${url.search}`)\n const reqPrefix = Math.floor(random() * 0x100000000).toString(36)\n\n let state: ConnectionState = \"connecting\"\n let lastError: TunnelClientError | null = null\n let hello: HelloFrame | null = null\n let live: Live | null = null\n let stopped = false\n let seq = 0\n const listeners = new Set<(change: StateChange) => void>()\n /** Wakes the backoff sleep early (reconnect() / close()). */\n let wake: (() => void) | null = null\n\n const notify = (change: StateChange): void => {\n for (const l of [...listeners]) {\n try {\n l(change)\n } catch {\n /* a listener must not break the client */\n }\n }\n }\n\n const setState = (next: ConnectionState, error?: TunnelClientError): void => {\n if (error) lastError = error\n if (next === state && !error) return\n state = next\n notify(error ? { state, error } : { state })\n }\n\n const failPending = (l: Live, err: TunnelClientError): void => {\n for (const [, p] of l.pending) {\n p.detach()\n if (!p.settled) {\n p.settled = true\n p.reject(err)\n } else if (p.controller) {\n try {\n p.controller.error(err)\n } catch {\n /* already closed */\n }\n }\n }\n l.pending.clear()\n }\n\n // ── connection loop ──────────────────────────────────────────────\n\n const sleep = (ms: number): Promise<void> =>\n new Promise(resolve => {\n const timer = setTimeout(done, ms)\n function done(): void {\n clearTimeout(timer)\n wake = null\n resolve()\n }\n wake = done\n })\n\n /** One attempt: today's epoch token, then yesterday's. */\n async function establish(): Promise<{ sink: E2eFrameSink; hello: HelloFrame; route: (h: (f: TunnelFrame) => void) => void }> {\n const epoch = currentEpoch(now())\n let lastErr: unknown\n for (const e of [epoch, epoch - 1]) {\n if (stopped) break\n try {\n const { route, auth } = await deriveEpochTokens(credential.pairRoot, e)\n const ch = await openChannel({\n rendezvousUrl: credential.rendezvousUrl,\n route,\n auth,\n daemonX25519Pub: credential.daemonX25519Pub,\n daemonEd25519Pub: credential.daemonEd25519Pub,\n clientName: credential.clientName,\n WebSocket: WebSocketImpl,\n ...(opts.dialTimeoutMs !== undefined ? { dialTimeoutMs: opts.dialTimeoutMs } : {}),\n ...(opts.handshakeTimeoutMs !== undefined ? { handshakeTimeoutMs: opts.handshakeTimeoutMs } : {}),\n ...(opts.greetingTimeoutMs !== undefined ? { greetingTimeoutMs: opts.greetingTimeoutMs } : {}),\n })\n if (ch.greeting.kind === \"revoked\") {\n ch.sink.close(\"revoked\")\n throw revokedError(credential.name)\n }\n if (ch.greeting.kind === \"outdated\") {\n ch.sink.close(\"outdated\")\n throw outdatedError(`this device's pairing with ${credential.name}`)\n }\n return { sink: ch.sink, hello: ch.greeting.hello, route: ch.route }\n } catch (err) {\n if (err instanceof TunnelClientError && (err.code === \"revoked\" || err.code === \"protocol_outdated\")) throw err\n lastErr = err\n }\n }\n throw new TunnelClientError(\n \"offline\",\n `could not reach ${credential.name} via ${credential.rendezvousUrl}: ${errMsg(lastErr)}`,\n { cause: lastErr },\n )\n }\n\n /** Serve one live channel until it closes. Resolves with the revocation\n * error if the daemon revoked us mid-channel. */\n function serve(ch: Awaited<ReturnType<typeof establish>>): Promise<TunnelClientError | null> {\n const l: Live = { sink: ch.sink, pending: new Map() }\n live = l\n hello = ch.hello\n let revoked: TunnelClientError | null = null\n let pingTimer: ReturnType<typeof setInterval> | null = null\n let pongTimer: ReturnType<typeof setTimeout> | null = null\n let pingSeq = 0\n\n return new Promise(resolve => {\n ch.route(frame => {\n switch (frame.t) {\n case \"http_response\":\n case \"http_response_head\":\n case \"http_response_chunk\":\n onHttpFrame(l, frame)\n return\n case \"pong\":\n if (pongTimer) clearTimeout(pongTimer)\n pongTimer = null\n return\n case \"ping\":\n l.sink.send({ t: \"pong\", nonce: frame.nonce })\n return\n case \"error\":\n if (frame.code === PAIRING_REVOKED_CODE) {\n revoked = revokedError(credential.name)\n l.sink.close(\"revoked\")\n }\n return\n default:\n return\n }\n })\n if (keepAliveMs > 0) {\n pingTimer = setInterval(() => {\n if (pongTimer) return\n l.sink.send({ t: \"ping\", nonce: `ka-${++pingSeq}` })\n pongTimer = setTimeout(() => l.sink.close(\"keepalive timeout\"), pongTimeoutMs)\n }, keepAliveMs)\n }\n l.sink.onClose(() => {\n if (pingTimer) clearInterval(pingTimer)\n if (pongTimer) clearTimeout(pongTimer)\n if (live === l) live = null\n failPending(\n l,\n revoked ??\n (stopped\n ? new TunnelClientError(\"closed\", \"the tunnel client was closed\")\n : new TunnelClientError(\"disconnected\", `lost the connection to ${credential.name}`)),\n )\n resolve(revoked)\n })\n if (!l.sink.isOpen) {\n // Closed between the greeting and now: onClose already fired.\n failPending(l, new TunnelClientError(\"disconnected\", `lost the connection to ${credential.name}`))\n resolve(revoked)\n }\n })\n }\n\n async function run(): Promise<void> {\n let attempt = 0\n while (!stopped) {\n setState(\"connecting\")\n let ch: Awaited<ReturnType<typeof establish>>\n try {\n ch = await establish()\n } catch (err) {\n if (stopped) return\n const e = err instanceof TunnelClientError ? err : new TunnelClientError(\"offline\", errMsg(err), { cause: err })\n if (e.code === \"revoked\") {\n setState(\"revoked\", e)\n return\n }\n if (e.code === \"protocol_outdated\") {\n setState(\"outdated\", e)\n return\n }\n setState(\"offline\", e)\n await sleep(backoff(attempt++))\n continue\n }\n if (stopped) {\n ch.sink.close(\"client closed\")\n return\n }\n attempt = 0\n const closed = serve(ch)\n setState(\"open\")\n if (opts.store) {\n void opts.store.put({ ...credential, lastSeen: new Date(now()).toISOString() }).catch(() => {})\n }\n const revoked = await closed\n if (stopped) return\n if (revoked) {\n setState(\"revoked\", revoked)\n return\n }\n // Let the daemon re-park on the token before we come back.\n setState(\"offline\", new TunnelClientError(\"disconnected\", `lost the connection to ${credential.name}`))\n await sleep(backoff(attempt++))\n }\n }\n\n /** Jittered (\"equal jitter\") capped exponential backoff. */\n function backoff(n: number): number {\n const cap = Math.min(maxMs, minMs * 2 ** Math.min(n, 30))\n return cap / 2 + random() * (cap / 2)\n }\n\n // ── requests ─────────────────────────────────────────────────────\n\n function onHttpFrame(\n l: Live,\n frame: Extract<TunnelFrame, { t: \"http_response\" | \"http_response_head\" | \"http_response_chunk\" }>,\n ): void {\n const p = l.pending.get(frame.reqId)\n if (!p) return // cancelled / unknown — drop\n if (frame.t === \"http_response\") {\n l.pending.delete(frame.reqId)\n p.detach()\n if (p.settled) return\n p.settled = true\n let body: Uint8Array | null = frame.body ? decodeData(frame.body) : null\n if (!body?.length && frame.error) {\n body = new TextEncoder().encode(JSON.stringify({ error: frame.error.code, message: frame.error.message }))\n }\n p.resolve(makeResponse(frame.status, frame.headers, body))\n return\n }\n if (frame.t === \"http_response_head\") {\n if (p.settled) return\n p.settled = true\n const stream = new ReadableStream<Uint8Array>({\n start: c => {\n p.controller = c\n },\n cancel: () => {\n // The consumer gave up on the body (EventSource closed, reader\n // cancelled): stop the daemon's upstream too.\n if (l.pending.get(frame.reqId) === p) {\n l.pending.delete(frame.reqId)\n p.detach()\n l.sink.send({ t: \"http_cancel\", reqId: frame.reqId })\n }\n },\n })\n p.resolve(makeResponse(frame.status, frame.headers, stream))\n return\n }\n // http_response_chunk\n const c = p.controller\n if (!c) return\n try {\n if (frame.data) c.enqueue(decodeData(frame.data))\n if (frame.error) {\n l.pending.delete(frame.reqId)\n p.detach()\n c.error(new TunnelClientError(\"stream_error\", `${frame.error.code}: ${frame.error.message}`))\n } else if (frame.end) {\n l.pending.delete(frame.reqId)\n p.detach()\n c.close()\n }\n } catch {\n /* the consumer cancelled; the cancel hook already cleaned up */\n }\n }\n\n function waitForLive(signal: AbortSignal): Promise<Live> {\n if (state === \"open\" && live) return Promise.resolve(live)\n if (state === \"revoked\") return Promise.reject(lastError ?? revokedError(credential.name))\n if (state === \"outdated\") return Promise.reject(lastError ?? outdatedError(`this device's pairing with ${credential.name}`))\n if (state === \"closed\") return Promise.reject(new TunnelClientError(\"closed\", \"the tunnel client was closed\"))\n return new Promise((resolve, reject) => {\n const done = (fn: () => void): void => {\n clearTimeout(timer)\n off()\n signal.removeEventListener(\"abort\", onAbort)\n fn()\n }\n const timer = setTimeout(\n () =>\n done(() =>\n reject(\n new TunnelClientError(\n \"offline\",\n `${credential.name} is unreachable (no connection within ${requestWaitMs}ms)` +\n (lastError ? `: ${lastError.message}` : \"\"),\n lastError ? { cause: lastError } : undefined,\n ),\n ),\n ),\n requestWaitMs,\n )\n const onAbort = (): void => done(() => reject(signal.reason))\n signal.addEventListener(\"abort\", onAbort)\n const off = onStateChangeImpl(({ state: s, error }) => {\n if (s === \"open\" && live) {\n const l = live\n done(() => resolve(l))\n } else if (s === \"revoked\" || s === \"outdated\" || s === \"closed\") {\n done(() =>\n reject(\n error ??\n new TunnelClientError(s === \"outdated\" ? \"protocol_outdated\" : s, `the tunnel client is ${s}`),\n ),\n )\n }\n })\n })\n }\n\n async function tunnelFetch(input: RequestInfo | URL, init?: RequestInit): Promise<Response> {\n const request =\n input instanceof Request\n ? init\n ? new Request(input, init)\n : input\n : new Request(new URL(String(input), BASE), init)\n const signal = request.signal\n if (signal.aborted) throw signal.reason\n const method = request.method.toUpperCase()\n const body =\n method === \"GET\" || method === \"HEAD\" ? null : new Uint8Array(await request.arrayBuffer())\n const headers: Record<string, string> = {}\n request.headers.forEach((value, key) => {\n headers[key] = value\n })\n const path = mapPath(new URL(request.url))\n if (!path.startsWith(\"/\")) throw new TypeError(`tunnel path must start with \"/\" (got \"${path}\")`)\n\n const l = await waitForLive(signal)\n if (signal.aborted) throw signal.reason\n // Closed in the gap since it was handed to us: the close sweep may already\n // have run, so a request registered now would never be failed.\n if (!l.sink.isOpen) {\n throw new TunnelClientError(\"disconnected\", `lost the connection to ${credential.name}`)\n }\n const reqId = `${reqPrefix}-${(++seq).toString(36)}`\n\n return new Promise<Response>((resolve, reject) => {\n const onAbort = (): void => {\n const p = l.pending.get(reqId)\n if (!p) return\n l.pending.delete(reqId)\n p.detach()\n l.sink.send({ t: \"http_cancel\", reqId })\n if (!p.settled) {\n p.settled = true\n reject(signal.reason)\n } else {\n try {\n p.controller?.error(signal.reason)\n } catch {\n /* already closed */\n }\n }\n }\n const pending: Pending = {\n resolve,\n reject,\n controller: null,\n settled: false,\n detach: () => signal.removeEventListener(\"abort\", onAbort),\n }\n l.pending.set(reqId, pending)\n signal.addEventListener(\"abort\", onAbort)\n const base = {\n t: \"http_request\" as const,\n reqId,\n method,\n path,\n ...(Object.keys(headers).length ? { headers } : {}),\n }\n if (body && body.length > MAX_FRAME_PAYLOAD_BYTES && hello?.capabilities.httpRequestChunks === true) {\n // One frame this size would exceed the rendezvous' message cap once\n // E2E-wrapped (and kill the channel): stream it in bounded chunks.\n l.sink.send({ ...base, bodyChunked: true })\n const pieces = splitPayload(body)\n pieces.forEach((piece, i) => {\n l.sink.send({\n t: \"http_request_chunk\",\n reqId,\n data: encodeData(piece),\n ...(i === pieces.length - 1 ? { end: true } : {}),\n })\n })\n } else {\n l.sink.send({ ...base, ...(body && body.length ? { body: encodeData(body) } : {}) })\n }\n })\n }\n\n // ── public surface ───────────────────────────────────────────────\n\n function onStateChangeImpl(listener: (change: StateChange) => void): () => void {\n listeners.add(listener)\n return () => listeners.delete(listener)\n }\n\n // A credential from before pair/v2 is never dialed: the daemon won't serve\n // it, and a v2 hello can't even reach its re-pair notice.\n if (credential.protocol !== PAIR_VERSION) {\n setState(\"outdated\", outdatedError(`this device's pairing with ${credential.name}`))\n // That happened inside connect(), before anyone could subscribe: replay it\n // to the listeners attached in the same tick, so onStateChange fires.\n queueMicrotask(() => {\n if (state === \"outdated\" && lastError) notify({ state, error: lastError })\n })\n } else void run().catch(err => {\n setState(\"offline\", new TunnelClientError(\"offline\", errMsg(err), { cause: err }))\n })\n\n return {\n credential,\n get state() {\n return state\n },\n get hello() {\n return hello\n },\n get lastError() {\n return lastError\n },\n onStateChange: onStateChangeImpl,\n ready() {\n return waitForLive(new AbortController().signal).then(() => undefined)\n },\n fetch: tunnelFetch,\n reconnect() {\n wake?.()\n },\n close() {\n if (stopped) return\n stopped = true\n wake?.()\n const l = live\n live = null\n if (l) {\n failPending(l, new TunnelClientError(\"closed\", \"the tunnel client was closed\"))\n l.sink.close(\"client closed\")\n }\n // `revoked` / `outdated` are terminal verdicts a UI must keep showing\n // (with lastError): closing the client doesn't turn them into \"closed\".\n if (state !== \"revoked\" && state !== \"outdated\") setState(\"closed\")\n },\n }\n}\n\nfunction makeResponse(\n status: number,\n headers: Readonly<Record<string, string>> | undefined,\n body: Uint8Array | ReadableStream<Uint8Array> | null,\n): Response {\n const h = new Headers()\n for (const [k, v] of Object.entries(headers ?? {})) {\n if (DROP_RESPONSE_HEADERS.has(k.toLowerCase())) continue\n try {\n h.append(k, v)\n } catch {\n /* a header the platform refuses to set on a synthetic Response */\n }\n }\n // Response() only takes 200–599; anything else from the daemon is a bad\n // gateway from the page's point of view.\n const s = Number.isInteger(status) && status >= 200 && status <= 599 ? status : 502\n if (NULL_BODY_STATUS.has(s)) {\n if (body instanceof ReadableStream) void body.cancel().catch(() => {})\n return new Response(null, { status: s, headers: h })\n }\n return new Response(body as BodyInit | null, { status: s, headers: h })\n}\n","/**\n * First contact: turn an offer (the `pair offer --qr` link, or the plain\n * `agentproto://pair?…` URL) into a stored credential.\n *\n * Two steps so a UI can ask the human before persisting anything:\n *\n * 1. `inspectOffer(url)` — no network: parse + validate the offer and return\n * the daemon fingerprint it pins and when it expires.\n * 2. `pairFromOffer(url)` — run the handshake through the offer's rendezvous\n * (this spends the one-time offer; the daemon records the pairing now,\n * exactly as for `agentproto pair accept`), read the daemon's hello for its\n * name, close the channel, and hand back `{ daemon, confirm, cancel }`.\n * `confirm()` builds the credential (pair root as a non-extractable\n * `CryptoKey`) and stores it; `cancel()` drops it. Cancelling does not undo\n * the daemon's record — remove that with `agentproto pair revoke`.\n */\n\nimport {\n derivePairRoot,\n deriveOfferTokens,\n importPairRootKey,\n parseOfferUrl,\n PAIR_VERSION,\n PairingError,\n type PairingOffer,\n} from \"@agentproto/secrets/pairing/browser\"\nimport {\n daemonNameFromHello,\n defaultWebSocket,\n openChannel,\n type ChannelTimeouts,\n type WebSocketConstructor,\n} from \"./channel.js\"\nimport type { CredentialStore, PairCredential } from \"./credential.js\"\nimport { errMsg, outdatedError, TunnelClientError } from \"./errors.js\"\n\nexport interface OfferInfo {\n /** Daemon identity fingerprint (32 hex) the offer pins — show it to the user. */\n fingerprint: string\n /** The rendezvous the handshake will go through. */\n rendezvousUrl: string\n /** Offer expiry. */\n expiresAt: Date\n}\n\nasync function parse(offerUrl: string, now: number): Promise<PairingOffer> {\n try {\n return await parseOfferUrl(offerUrl, { now })\n } catch (err) {\n if (err instanceof PairingError && err.code === \"pairing_protocol_outdated\") {\n throw outdatedError(\"this pairing QR\", { cause: err })\n }\n const expired = err instanceof PairingError && err.code === \"offer_expired\"\n throw new TunnelClientError(\n \"invalid_offer\",\n expired ? \"this pairing offer has expired; run `agentproto pair offer --qr` again\" : errMsg(err),\n { cause: err },\n )\n }\n}\n\n/** Parse and validate an offer without touching the network. Accepts the web\n * form (`https://…/pair#…`) and the `agentproto://pair?…` form. */\nexport async function inspectOffer(\n offerUrl: string,\n opts: { now?: number } = {},\n): Promise<OfferInfo> {\n const offer = await parse(offerUrl, opts.now ?? Date.now())\n return {\n fingerprint: offer.fingerprint,\n rendezvousUrl: offer.rendezvousUrl,\n expiresAt: new Date(offer.exp * 1000),\n }\n}\n\nexport interface PairFromOfferOptions extends ChannelTimeouts {\n /** How this device is listed on the daemon (`agentproto pair ls`).\n * Default `browser@<location.host>` (or `browser`). */\n clientName?: string\n /** Where `confirm()` stores the credential. Omit to only get it back. */\n store?: CredentialStore\n /** WebSocket constructor. Default: the global `WebSocket`. */\n WebSocket?: WebSocketConstructor\n /** Clock (ms). Default `Date.now`. */\n now?: () => number\n}\n\nexport interface PairedDaemon {\n /** Daemon identity fingerprint — verified by the handshake. */\n fingerprint: string\n /** Display name (hello label, else host name, else the fingerprint). */\n name: string\n /** The daemon's `serve --label`, if any. */\n label?: string\n /** `<os>/<hostname>` from the daemon's hello (diagnostic). */\n platform?: string\n rendezvousUrl: string\n}\n\nexport interface PendingPairing {\n daemon: PairedDaemon\n /** Build the credential and (with `opts.store`) persist it. */\n confirm(): Promise<PairCredential>\n /** Discard the pairing on this side. */\n cancel(): void\n}\n\nfunction defaultClientName(): string {\n const host = (globalThis as { location?: { host?: string } }).location?.host\n return host ? `browser@${host}` : \"browser\"\n}\n\n/**\n * Run the `pair/v1` handshake for an offer. See the module doc for the\n * two-step flow. Throws `TunnelClientError` — `invalid_offer` for a\n * malformed/expired offer, `pairing_failed` for everything the handshake can\n * hit (unreachable daemon, spent offer, bad signature, fingerprint mismatch).\n */\nexport async function pairFromOffer(\n offerUrl: string,\n opts: PairFromOfferOptions = {},\n): Promise<PendingPairing> {\n const now = opts.now ?? Date.now\n const offer = await parse(offerUrl, now())\n const clientName = opts.clientName ?? defaultClientName()\n\n let channel: Awaited<ReturnType<typeof openChannel>>\n try {\n // The offer secret never goes on the wire: the broker gets its route, the\n // daemon (sealed) its auth.\n const { route, auth } = await deriveOfferTokens(offer.secret)\n channel = await openChannel({\n rendezvousUrl: offer.rendezvousUrl,\n route,\n auth,\n daemonX25519Pub: offer.daemonX25519Pub,\n daemonEd25519Pub: offer.daemonEd25519Pub,\n clientName,\n WebSocket: opts.WebSocket ?? defaultWebSocket(),\n ...(opts.dialTimeoutMs !== undefined ? { dialTimeoutMs: opts.dialTimeoutMs } : {}),\n ...(opts.handshakeTimeoutMs !== undefined ? { handshakeTimeoutMs: opts.handshakeTimeoutMs } : {}),\n ...(opts.greetingTimeoutMs !== undefined ? { greetingTimeoutMs: opts.greetingTimeoutMs } : {}),\n })\n } catch (err) {\n throw new TunnelClientError(\"pairing_failed\", `could not pair with daemon ${offer.fingerprint}: ${errMsg(err)}`, {\n cause: err,\n })\n }\n const { sink, session, greeting } = channel\n\n // Defence in depth, as the CLI: the daemon we authenticated must be the one\n // the offer named (parseOfferUrl already checked id == fingerprint(pk)).\n if (session.peerFingerprint !== offer.fingerprint) {\n sink.close(\"fingerprint mismatch\")\n throw new TunnelClientError(\n \"pairing_failed\",\n `daemon fingerprint ${session.peerFingerprint} does not match the offer's ${offer.fingerprint}`,\n )\n }\n if (greeting.kind === \"outdated\") {\n sink.close(\"outdated\")\n throw outdatedError(\"this daemon\")\n }\n let pairRoot: string | null = await derivePairRoot(session)\n // The first-contact channel is one-shot, as with `pair accept`.\n sink.close(\"pair complete\")\n\n const hello = greeting.kind === \"hello\" ? greeting.hello : null\n const daemon: PairedDaemon = {\n fingerprint: offer.fingerprint,\n name: daemonNameFromHello(hello, offer.fingerprint),\n ...(hello?.label ? { label: hello.label } : {}),\n ...(hello?.daemon?.platform ? { platform: hello.daemon.platform } : {}),\n rendezvousUrl: offer.rendezvousUrl,\n }\n\n return {\n daemon,\n async confirm() {\n const root = pairRoot\n if (root === null) throw new TunnelClientError(\"cancelled\", \"this pairing was already confirmed or cancelled\")\n pairRoot = null\n const nowIso = new Date(now()).toISOString()\n const credential: PairCredential = {\n protocol: PAIR_VERSION,\n id: offer.fingerprint,\n fingerprint: offer.fingerprint,\n name: daemon.name,\n clientName,\n daemonX25519Pub: offer.daemonX25519Pub,\n daemonEd25519Pub: offer.daemonEd25519Pub,\n rendezvousUrl: offer.rendezvousUrl,\n pairRoot: await importPairRootKey(root),\n createdAt: nowIso,\n lastSeen: nowIso,\n }\n await opts.store?.put(credential)\n return credential\n },\n cancel() {\n pairRoot = null\n },\n }\n}\n","/**\n * The stored pairing credential and where it lives.\n *\n * `PairCredential` carries what the Node CLI persists per pairing\n * (`~/.agentproto/pair-credentials.json`, `ClientPairing` in\n * `packages/cli/src/util/client-pairings.ts`) — the pinned daemon keys, the\n * rendezvous URL, the pair root, timestamps — so a reconnect is byte-for-byte\n * the one the CLI makes. Two differences, both client-local:\n *\n * - `pairRoot` is normally a **non-extractable** WebCrypto HKDF `CryptoKey`\n * (`importPairRootKey`): script can derive the epoch routing tokens with\n * it but can't read the secret back out. IndexedDB stores it as-is\n * (structured clone). A base64 string is accepted too (e.g. a credential\n * imported from the CLI's file).\n * - The CLI keeps one `name` that is both the user's label and the handshake\n * `clientName`; here `name` is the daemon's display name and `clientName`\n * the label this device announced to the daemon (what `pair ls` shows).\n *\n * No localStorage anywhere: `createIndexedDbCredentialStore` for browsers and\n * service workers, `createMemoryCredentialStore` for tests.\n */\n\nexport interface PairCredential {\n /** Pairing protocol the credential was made under (`PAIR_VERSION`, 2). A\n * credential without it predates pair/v2: `connect` refuses it with\n * `protocol_outdated` instead of dialing (the daemon would never serve it). */\n protocol?: number\n /** Store key: the daemon fingerprint (one credential per daemon, as the CLI\n * keys its pairings). */\n id: string\n /** Daemon identity fingerprint (32 hex): the pin. */\n fingerprint: string\n /** Daemon display name: its tunnel `hello` label, else its host name, else\n * the fingerprint. */\n name: string\n /** The label this device sent in the handshake (the daemon's `pair ls` name). */\n clientName: string\n /** Daemon static X25519 public key (base64 SPKI DER), pinned. */\n daemonX25519Pub: string\n /** Daemon static Ed25519 public key (base64 SPKI DER), pinned: verifies the\n * daemon's transcript signature on every (re)connect. */\n daemonEd25519Pub: string\n /** Rendezvous endpoint to reconnect through. */\n rendezvousUrl: string\n /** Long-term shared secret the epoch routing tokens derive from: a\n * non-extractable HKDF `CryptoKey`, or base64. */\n pairRoot: CryptoKey | string\n /** ISO-8601 when this pairing was made. */\n createdAt: string\n /** ISO-8601 of the most recent (re)connect. */\n lastSeen: string\n}\n\nexport interface CredentialStore {\n get(id: string): Promise<PairCredential | undefined>\n /** Insert or replace (keyed by `id`). */\n put(credential: PairCredential): Promise<void>\n /** Returns whether something was removed. */\n delete(id: string): Promise<boolean>\n list(): Promise<PairCredential[]>\n}\n\n/** In-memory store (tests, or a page that must not persist). */\nexport function createMemoryCredentialStore(initial: PairCredential[] = []): CredentialStore {\n const byId = new Map(initial.map(c => [c.id, c]))\n return {\n async get(id) {\n return byId.get(id)\n },\n async put(credential) {\n byId.set(credential.id, credential)\n },\n async delete(id) {\n return byId.delete(id)\n },\n async list() {\n return [...byId.values()]\n },\n }\n}\n\nexport interface IndexedDbCredentialStoreOptions {\n /** Database name. Default `agentproto-pair`. */\n dbName?: string\n /** Object store name. Default `credentials`. */\n storeName?: string\n /** The IndexedDB factory. Default `globalThis.indexedDB` (window or worker). */\n indexedDB?: IDBFactory\n}\n\n/**\n * IndexedDB-backed store. Works in a window and in a service worker (both\n * expose `indexedDB`); credentials are scoped to the origin like all IndexedDB\n * data. The `CryptoKey` pair root is stored by structured clone, so it stays\n * non-extractable at rest and after reload.\n */\nexport function createIndexedDbCredentialStore(\n opts: IndexedDbCredentialStoreOptions = {},\n): CredentialStore {\n const dbName = opts.dbName ?? \"agentproto-pair\"\n const storeName = opts.storeName ?? \"credentials\"\n let dbPromise: Promise<IDBDatabase> | null = null\n\n const open = (): Promise<IDBDatabase> => {\n if (dbPromise) return dbPromise\n const factory = opts.indexedDB ?? globalThis.indexedDB\n if (!factory) return Promise.reject(new Error(\"IndexedDB is not available in this context\"))\n dbPromise = new Promise<IDBDatabase>((resolve, reject) => {\n const req = factory.open(dbName, 1)\n req.onupgradeneeded = () => {\n if (!req.result.objectStoreNames.contains(storeName)) {\n req.result.createObjectStore(storeName, { keyPath: \"id\" })\n }\n }\n req.onsuccess = () => resolve(req.result)\n req.onerror = () => reject(req.error ?? new Error(\"IndexedDB open failed\"))\n })\n dbPromise.catch(() => {\n dbPromise = null\n })\n return dbPromise\n }\n\n const run = async <T>(\n mode: IDBTransactionMode,\n op: (store: IDBObjectStore) => IDBRequest<T>,\n ): Promise<T> => {\n const db = await open()\n return new Promise<T>((resolve, reject) => {\n const tx = db.transaction(storeName, mode)\n const req = op(tx.objectStore(storeName))\n tx.oncomplete = () => resolve(req.result)\n tx.onerror = () => reject(tx.error ?? req.error ?? new Error(\"IndexedDB request failed\"))\n tx.onabort = () => reject(tx.error ?? new Error(\"IndexedDB transaction aborted\"))\n })\n }\n\n return {\n async get(id) {\n return (await run<PairCredential | undefined>(\"readonly\", s => s.get(id))) ?? undefined\n },\n async put(credential) {\n await run(\"readwrite\", s => s.put(credential))\n },\n async delete(id) {\n const existing = await run<number>(\"readonly\", s => s.count(id))\n if (existing === 0) return false\n await run(\"readwrite\", s => s.delete(id))\n return true\n },\n async list() {\n return run<PairCredential[]>(\"readonly\", s => s.getAll())\n },\n }\n}\n"]}
package/package.json ADDED
@@ -0,0 +1,69 @@
1
+ {
2
+ "name": "@agentproto/pair-client",
3
+ "version": "0.2.0",
4
+ "description": "@agentproto/pair-client — browser-safe client for agentproto E2E daemon pairing. Pair from an offer QR, keep the credential in IndexedDB, and reach the daemon with a WHATWG fetch (streamed bodies, SSE) multiplexed over one rendezvous WebSocket, with reconnect and a typed revocation error.",
5
+ "keywords": [
6
+ "agentproto",
7
+ "pairing",
8
+ "e2e",
9
+ "rendezvous",
10
+ "tunnel",
11
+ "browser",
12
+ "service-worker"
13
+ ],
14
+ "homepage": "https://agentproto.sh",
15
+ "repository": {
16
+ "type": "git",
17
+ "url": "https://github.com/agentproto/ts",
18
+ "directory": "packages/pair-client"
19
+ },
20
+ "bugs": {
21
+ "url": "https://github.com/agentproto/ts/issues"
22
+ },
23
+ "license": "Apache-2.0",
24
+ "type": "module",
25
+ "main": "dist/index.mjs",
26
+ "module": "dist/index.mjs",
27
+ "types": "dist/index.d.ts",
28
+ "exports": {
29
+ ".": {
30
+ "types": "./dist/index.d.ts",
31
+ "import": "./dist/index.mjs",
32
+ "default": "./dist/index.mjs"
33
+ },
34
+ "./package.json": "./package.json"
35
+ },
36
+ "files": [
37
+ "dist",
38
+ "README.md",
39
+ "LICENSE"
40
+ ],
41
+ "publishConfig": {
42
+ "access": "public"
43
+ },
44
+ "sideEffects": false,
45
+ "dependencies": {
46
+ "@agentproto/acp": "0.9.0",
47
+ "@agentproto/secrets": "1.0.0"
48
+ },
49
+ "devDependencies": {
50
+ "@types/node": "^25.9.5",
51
+ "@types/ws": "^8.18.1",
52
+ "esbuild": "^0.28.2",
53
+ "tsup": "^8.5.1",
54
+ "typescript": "^5.9.3",
55
+ "vitest": "^3.2.7",
56
+ "ws": "^8.21.3",
57
+ "@agentproto/rendezvous": "0.2.3",
58
+ "@agentproto/tooling": "0.1.0",
59
+ "@agentproto/runtime": "4.0.0"
60
+ },
61
+ "scripts": {
62
+ "dev": "tsup --watch",
63
+ "build": "tsup",
64
+ "clean": "rm -rf dist",
65
+ "check-types": "tsc --noEmit",
66
+ "test": "vitest run",
67
+ "test:watch": "vitest"
68
+ }
69
+ }