@pelican-identity/auth-core 1.2.9 → 1.2.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,cAAc,eAAe,CAAC;AAE9B,OAAO,EAAE,qBAAqB,EAAE,MAAM,iBAAiB,CAAC;AAGxD,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACnD,OAAO,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AACxD,OAAO,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAClD,cAAc,qBAAqB,CAAC;AACpC,OAAO,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC"}
1
+ {"version":3,"sources":["../src/utilities/crypto.ts","../src/utilities/storage.ts","../src/utilities/stateMachine.ts","../src/utilities/transport.ts","../src/constants.ts","../src/engine/engine.ts"],"names":["nacl","encodeBase64","decodeBase64","QRCode"],"mappings":";;;;;;;;;;;;AAQO,IAAM,gBAAN,MAAoB;AAAA,EACzB,oBAAA,GAA+B;AAC7B,IAAA,MAAM,GAAA,GAAMA,qBAAA,CAAK,WAAA,CAAY,EAAE,CAAA;AAC/B,IAAA,OAAOC,2BAAa,GAAG,CAAA;AAAA,EACzB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,gBAAA,CAAiB;AAAA,IACf,SAAA;AAAA,IACA;AAAA,GACF,EAGqB;AACnB,IAAA,MAAM,GAAA,GAAMC,2BAAa,SAAS,CAAA;AAClC,IAAA,MAAM,KAAA,GAAQF,qBAAA,CAAK,WAAA,CAAY,EAAE,CAAA;AAEjC,IAAA,MAAM,YAAA,GAAe,IAAI,WAAA,EAAY,CAAE,OAAO,SAAS,CAAA;AAEvD,IAAA,MAAM,UAAA,GAAaA,qBAAA,CAAK,SAAA,CAAU,YAAA,EAAc,OAAO,GAAG,CAAA;AAE1D,IAAA,OAAO;AAAA,MACL,MAAA,EAAQC,2BAAa,UAAU,CAAA;AAAA,MAC/B,KAAA,EAAOA,2BAAa,KAAK;AAAA,KAC3B;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,gBAAA,CAAiB;AAAA,IACf,SAAA;AAAA,IACA;AAAA,GACF,EAGkB;AAChB,IAAA,IAAI;AACF,MAAA,MAAM,GAAA,GAAMC,2BAAa,SAAS,CAAA;AAClC,MAAA,MAAM,eAAA,GAAkBA,0BAAA,CAAa,SAAA,CAAU,MAAM,CAAA;AACrD,MAAA,MAAM,UAAA,GAAaA,0BAAA,CAAa,SAAA,CAAU,KAAK,CAAA;AAE/C,MAAA,MAAM,YAAYF,qBAAA,CAAK,SAAA,CAAU,IAAA,CAAK,eAAA,EAAiB,YAAY,GAAG,CAAA;AAEtE,MAAA,IAAI,CAAC,SAAA,EAAW;AACd,QAAA,MAAM,IAAI,MAAM,mDAAmD,CAAA;AAAA,MACrE;AAEA,MAAA,MAAM,OAAA,GAAU,IAAI,WAAA,EAAY,CAAE,OAAO,SAAS,CAAA;AAClD,MAAA,OAAO,OAAA;AAAA,IACT,SAAS,KAAA,EAAO;AACd,MAAA,OAAA,CAAQ,KAAA,CAAM,qBAAqB,KAAK,CAAA;AACxC,MAAA,OAAO,IAAA;AAAA,IACT;AAAA,EACF;AACF;AAEA,IAAO,cAAA,GAAQ,aAAA;;;AC/Df,IAAM,cAAN,MAAkB;AAAA,EAAlB,WAAA,GAAA;AACE,IAAA,IAAA,CAAiB,MAAA,GAAS,eAAA;AAC1B,IAAA,IAAA,CAAiB,UAAA,GAAa,IAAI,EAAA,GAAK,GAAA;AACvC;AAAA,IAAA,IAAA,CAAQ,WAAA,uBACF,GAAA,EAAI;AAAA,EAAA;AAAA;AAAA;AAAA;AAAA,EAKV,GAAA,CAAI,GAAA,EAAa,KAAA,EAAY,OAAA,GAA0B,EAAC,EAAS;AAC/D,IAAA,MAAM,EAAE,KAAA,GAAQ,IAAA,CAAK,UAAA,EAAY,iBAAA,GAAoB,MAAK,GAAI,OAAA;AAE9D,IAAA,MAAM,SAAA,GAAY,IAAA,CAAK,GAAA,EAAI,GAAI,KAAA;AAC/B,IAAA,MAAM,IAAA,GAAO,EAAE,KAAA,EAAO,SAAA,EAAU;AAGhC,IAAA,IAAI,iBAAA,EAAmB;AACrB,MAAA,IAAI;AACF,QAAA,cAAA,CAAe,OAAA,CAAQ,CAAA,EAAG,IAAA,CAAK,MAAM,CAAA,EAAG,GAAG,CAAA,CAAA,EAAI,IAAA,CAAK,SAAA,CAAU,IAAI,CAAC,CAAA;AAAA,MACrE,SAAS,KAAA,EAAO;AACd,QAAA,OAAA,CAAQ,IAAA,CAAK,6CAA6C,KAAK,CAAA;AAC/D,QAAA,IAAA,CAAK,SAAA,CAAU,KAAK,IAAI,CAAA;AAAA,MAC1B;AAAA,IACF,CAAA,MAAO;AACL,MAAA,IAAA,CAAK,SAAA,CAAU,KAAK,IAAI,CAAA;AAAA,IAC1B;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,IAAI,GAAA,EAAyB;AAE3B,IAAA,IAAI;AACF,MAAA,MAAM,MAAA,GAAS,eAAe,OAAA,CAAQ,CAAA,EAAG,KAAK,MAAM,CAAA,EAAG,GAAG,CAAA,CAAE,CAAA;AAC5D,MAAA,IAAI,MAAA,EAAQ;AACV,QAAA,MAAM,IAAA,GAAO,IAAA,CAAK,KAAA,CAAM,MAAM,CAAA;AAG9B,QAAA,IAAI,IAAA,CAAK,GAAA,EAAI,GAAI,IAAA,CAAK,SAAA,EAAW;AAC/B,UAAA,IAAA,CAAK,OAAO,GAAG,CAAA;AACf,UAAA,OAAO,IAAA;AAAA,QACT;AAEA,QAAA,OAAO,IAAA,CAAK,KAAA;AAAA,MACd;AAAA,IACF,SAAS,KAAA,EAAO;AAAA,IAEhB;AAGA,IAAA,OAAO,IAAA,CAAK,UAAU,GAAG,CAAA;AAAA,EAC3B;AAAA;AAAA;AAAA;AAAA,EAKA,OAAO,GAAA,EAAmB;AACxB,IAAA,IAAI;AACF,MAAA,cAAA,CAAe,WAAW,CAAA,EAAG,IAAA,CAAK,MAAM,CAAA,EAAG,GAAG,CAAA,CAAE,CAAA;AAAA,IAClD,SAAS,KAAA,EAAO;AAAA,IAEhB;AACA,IAAA,IAAA,CAAK,WAAA,CAAY,OAAO,GAAG,CAAA;AAAA,EAC7B;AAAA;AAAA;AAAA;AAAA,EAKA,KAAA,GAAc;AAEZ,IAAA,IAAI;AACF,MAAA,MAAA,CAAO,IAAA,CAAK,cAAc,CAAA,CAAE,OAAA,CAAQ,CAAC,GAAA,KAAQ;AAC3C,QAAA,IAAI,GAAA,CAAI,UAAA,CAAW,IAAA,CAAK,MAAM,CAAA,EAAG;AAC/B,UAAA,cAAA,CAAe,WAAW,GAAG,CAAA;AAAA,QAC/B;AAAA,MACF,CAAC,CAAA;AAAA,IACH,SAAS,KAAA,EAAO;AAAA,IAEhB;AAGA,IAAA,IAAA,CAAK,YAAY,KAAA,EAAM;AAAA,EACzB;AAAA;AAAA;AAAA;AAAA,EAMQ,SAAA,CACN,KACA,IAAA,EACM;AACN,IAAA,IAAA,CAAK,WAAA,CAAY,GAAA,CAAI,GAAA,EAAK,IAAI,CAAA;AAG9B,IAAA,MAAM,GAAA,GAAM,IAAA,CAAK,SAAA,GAAY,IAAA,CAAK,GAAA,EAAI;AACtC,IAAA,UAAA,CAAW,MAAM;AACf,MAAA,IAAA,CAAK,WAAA,CAAY,OAAO,GAAG,CAAA;AAAA,IAC7B,GAAG,GAAG,CAAA;AAAA,EACR;AAAA,EAEQ,UAAU,GAAA,EAAyB;AACzC,IAAA,MAAM,IAAA,GAAO,IAAA,CAAK,WAAA,CAAY,GAAA,CAAI,GAAG,CAAA;AACrC,IAAA,IAAI,CAAC,MAAM,OAAO,IAAA;AAElB,IAAA,IAAI,IAAA,CAAK,GAAA,EAAI,GAAI,IAAA,CAAK,SAAA,EAAW;AAC/B,MAAA,IAAA,CAAK,WAAA,CAAY,OAAO,GAAG,CAAA;AAC3B,MAAA,OAAO,IAAA;AAAA,IACT;AAEA,IAAA,OAAO,IAAA,CAAK,KAAA;AAAA,EACd;AACF,CAAA;AAGA,IAAM,OAAA,GAAU,IAAI,WAAA,EAAY;AAWzB,IAAM,gBAAA,GAAmB,CAC9B,SAAA,EACA,UAAA,EACA,KAAA,KACS;AACT,EAAA,OAAA,CAAQ,GAAA,CAAI,WAAW,EAAE,SAAA,EAAW,YAAW,EAAG,EAAE,OAAO,CAAA;AAC7D;AAEO,IAAM,iBAAiB,MAA0B;AACtD,EAAA,OAAO,OAAA,CAAQ,IAAI,SAAS,CAAA;AAC9B;AAEO,IAAM,mBAAmB,MAAY;AAC1C,EAAA,OAAA,CAAQ,OAAO,SAAS,CAAA;AAC1B;AAEO,IAAM,mBAAmB,MAAY;AAC1C,EAAA,OAAA,CAAQ,KAAA,EAAM;AAChB;;;AC1JO,IAAM,eAAN,MAAmB;AAAA,EAAnB,WAAA,GAAA;AACL,IAAA,IAAA,CAAQ,KAAA,GAA0B,MAAA;AAClC,IAAA,IAAA,CAAQ,SAAA,uBAAgB,GAAA,EAAmC;AAAA,EAAA;AAAA,EAE3D,IAAI,OAAA,GAAU;AACZ,IAAA,OAAO,IAAA,CAAK,KAAA;AAAA,EACd;AAAA,EAEA,WAAW,IAAA,EAAwB;AACjC,IAAA,IAAA,CAAK,KAAA,GAAQ,IAAA;AACb,IAAA,IAAA,CAAK,UAAU,OAAA,CAAQ,CAAC,CAAA,KAAM,CAAA,CAAE,IAAI,CAAC,CAAA;AAAA,EACvC;AAAA,EAEA,UAAU,EAAA,EAAmC;AAC3C,IAAA,IAAA,CAAK,SAAA,CAAU,IAAI,EAAE,CAAA;AACrB,IAAA,OAAO,MAAM,IAAA,CAAK,SAAA,CAAU,MAAA,CAAO,EAAE,CAAA;AAAA,EACvC;AACF;;;ACNO,IAAM,YAAN,MAAgB;AAAA,EAUrB,YAAY,QAAA,EAA6B;AAPzC,IAAA,IAAA,CAAQ,iBAAA,GAAoB,CAAA;AAC5B,IAAA,IAAA,CAAQ,oBAAA,GAAuB,CAAA;AAC/B;AAAA,IAAA,IAAA,CAAQ,kBAAA,GAAqB,KAAA;AAG7B,IAAA,IAAA,CAAQ,cAAA,GAAiB,KAAA;AAGvB,IAAA,IAAA,CAAK,QAAA,GAAW,QAAA;AAAA,EAClB;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,QAAQ,GAAA,EAAa;AACnB,IAAA,IAAA,CAAK,GAAA,GAAM,GAAA;AACX,IAAA,IAAA,CAAK,kBAAA,GAAqB,KAAA;AAG1B,IAAA,IAAI,KAAK,MAAA,EAAQ;AACf,MAAA,IAAA,CAAK,OAAO,OAAA,GAAU,IAAA;AACtB,MAAA,IAAA,CAAK,OAAO,OAAA,GAAU,IAAA;AACtB,MAAA,IAAA,CAAK,OAAO,SAAA,GAAY,IAAA;AACxB,MAAA,IAAA,CAAK,OAAO,MAAA,GAAS,IAAA;AAErB,MAAA,IACE,IAAA,CAAK,OAAO,UAAA,KAAe,SAAA,CAAU,QACrC,IAAA,CAAK,MAAA,CAAO,UAAA,KAAe,SAAA,CAAU,UAAA,EACrC;AACA,QAAA,IAAA,CAAK,OAAO,KAAA,EAAM;AAAA,MACpB;AAAA,IACF;AAEA,IAAA,IAAA,CAAK,MAAA,GAAS,IAAI,SAAA,CAAU,GAAG,CAAA;AAE/B,IAAA,IAAA,CAAK,MAAA,CAAO,SAAS,MAAM;AACzB,MAAA,IAAA,CAAK,iBAAA,GAAoB,CAAA;AACzB,MAAA,IAAA,CAAK,cAAA,GAAiB,KAAA;AACtB,MAAA,IAAA,CAAK,SAAS,MAAA,IAAS;AAAA,IACzB,CAAA;AAEA,IAAA,IAAA,CAAK,MAAA,CAAO,SAAA,GAAY,CAAC,CAAA,KAAoB;AAC3C,MAAA,IAAI;AACF,QAAA,MAAM,IAAA,GAAO,IAAA,CAAK,KAAA,CAAM,CAAA,CAAE,IAAI,CAAA;AAC9B,QAAA,IAAA,CAAK,QAAA,CAAS,YAAY,IAAI,CAAA;AAAA,MAChC,SAAS,GAAA,EAAK;AACZ,QAAA,OAAA,CAAQ,KAAA,CAAM,qCAAqC,GAAG,CAAA;AAAA,MACxD;AAAA,IACF,CAAA;AAEA,IAAA,IAAA,CAAK,MAAA,CAAO,OAAA,GAAU,CAAC,CAAA,KAAa;AAElC,MAAA,IAAI,CAAC,IAAA,CAAK,cAAA,IAAkB,CAAC,KAAK,kBAAA,EAAoB;AACpD,QAAA,IAAA,CAAK,QAAA,CAAS,UAAU,CAAC,CAAA;AAAA,MAC3B;AAAA,IACF,CAAA;AAEA,IAAA,IAAA,CAAK,MAAA,CAAO,OAAA,GAAU,CAAC,CAAA,KAAkB;AAEvC,MAAA,IAAI,KAAK,gBAAA,EAAkB;AACzB,QAAA,YAAA,CAAa,KAAK,gBAAgB,CAAA;AAClC,QAAA,IAAA,CAAK,gBAAA,GAAmB,MAAA;AAAA,MAC1B;AAGA,MAAA,IAAI,CAAC,KAAK,cAAA,EAAgB;AACxB,QAAA,IAAA,CAAK,QAAA,CAAS,UAAU,CAAC,CAAA;AAAA,MAC3B;AAMA,MAAA,IACE,CAAC,KAAK,kBAAA,IACN,CAAC,KAAK,cAAA,IACN,IAAA,CAAK,iBAAA,GAAoB,IAAA,CAAK,oBAAA,EAC9B;AACA,QAAA,IAAA,CAAK,gBAAA,EAAiB;AAAA,MACxB;AAAA,IACF,CAAA;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKQ,gBAAA,GAAmB;AACzB,IAAA,IAAI,IAAA,CAAK,iBAAA,IAAqB,IAAA,CAAK,oBAAA,EAAsB;AACvD,MAAA,OAAA,CAAQ,KAAK,0CAA0C,CAAA;AACvD,MAAA;AAAA,IACF;AAEA,IAAA,IAAA,CAAK,cAAA,GAAiB,IAAA;AACtB,IAAA,IAAA,CAAK,iBAAA,EAAA;AAGL,IAAA,MAAM,KAAA,GAAQ,IAAA,CAAK,GAAA,CAAI,IAAA,CAAK,GAAA,CAAI,CAAA,EAAG,IAAA,CAAK,iBAAA,GAAoB,CAAC,CAAA,GAAI,GAAA,EAAK,GAAI,CAAA;AAE1E,IAAA,OAAA,CAAQ,GAAA;AAAA,MACN,mCAAmC,IAAA,CAAK,iBAAiB,IAAI,IAAA,CAAK,oBAAoB,QAAQ,KAAK,CAAA,KAAA;AAAA,KACrG;AAEA,IAAA,IAAA,CAAK,gBAAA,GAAmB,MAAA,CAAO,UAAA,CAAW,MAAM;AAC9C,MAAA,IAAI,IAAA,CAAK,GAAA,IAAO,CAAC,IAAA,CAAK,kBAAA,EAAoB;AACxC,QAAA,IAAA,CAAK,OAAA,CAAQ,KAAK,GAAG,CAAA;AAAA,MACvB;AAAA,IACF,GAAG,KAAK,CAAA;AAAA,EACV;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,KAAK,OAAA,EAAyB;AAC5B,IAAA,IAAI,IAAA,CAAK,MAAA,EAAQ,UAAA,KAAe,SAAA,CAAU,IAAA,EAAM;AAC9C,MAAA,IAAI;AACF,QAAA,IAAA,CAAK,MAAA,CAAO,IAAA,CAAK,IAAA,CAAK,SAAA,CAAU,OAAO,CAAC,CAAA;AAAA,MAC1C,SAAS,GAAA,EAAK;AACZ,QAAA,OAAA,CAAQ,KAAA,CAAM,qCAAqC,GAAG,CAAA;AAAA,MACxD;AAAA,IACF,CAAA,MAAO;AACL,MAAA,OAAA,CAAQ,IAAA;AAAA,QACN,uCAAA;AAAA,QACA,KAAK,MAAA,EAAQ;AAAA,OACf;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,KAAA,GAAQ;AACN,IAAA,IAAA,CAAK,kBAAA,GAAqB,IAAA;AAC1B,IAAA,IAAA,CAAK,cAAA,GAAiB,KAAA;AAGtB,IAAA,IAAI,KAAK,gBAAA,EAAkB;AACzB,MAAA,YAAA,CAAa,KAAK,gBAAgB,CAAA;AAClC,MAAA,IAAA,CAAK,gBAAA,GAAmB,MAAA;AAAA,IAC1B;AAGA,IAAA,IAAI,KAAK,MAAA,EAAQ;AAEf,MAAA,IAAA,CAAK,OAAO,OAAA,GAAU,IAAA;AACtB,MAAA,IAAA,CAAK,OAAO,OAAA,GAAU,IAAA;AACtB,MAAA,IAAA,CAAK,OAAO,SAAA,GAAY,IAAA;AACxB,MAAA,IAAA,CAAK,OAAO,MAAA,GAAS,IAAA;AAErB,MAAA,IACE,IAAA,CAAK,OAAO,UAAA,KAAe,SAAA,CAAU,QACrC,IAAA,CAAK,MAAA,CAAO,UAAA,KAAe,SAAA,CAAU,UAAA,EACrC;AACA,QAAA,IAAA,CAAK,OAAO,KAAA,EAAM;AAAA,MACpB;AAEA,MAAA,IAAA,CAAK,MAAA,GAAS,MAAA;AAAA,IAChB;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,IAAI,UAAA,GAAiC;AACnC,IAAA,OAAO,KAAK,MAAA,EAAQ,UAAA;AAAA,EACtB;AAAA;AAAA;AAAA;AAAA,EAKA,IAAI,MAAA,GAAkB;AACpB,IAAA,OAAO,IAAA,CAAK,MAAA,EAAQ,UAAA,KAAe,SAAA,CAAU,IAAA;AAAA,EAC/C;AACF;;;AC/LO,IAAM,OAAA,GAAU;;;AC0BhB,IAAM,wBAAN,MAA4B;AAAA,EAkBjC,YAAY,MAAA,EAA2B;AAjBvC,IAAA,IAAA,CAAiB,MAAA,GAAS,IAAI,cAAA,EAAc;AAC5C,IAAA,IAAA,CAAiB,YAAA,GAAe,IAAI,YAAA,EAAa;AAGjD,IAAA,IAAA,CAAQ,SAAA,GAAY,EAAA;AACpB,IAAA,IAAA,CAAQ,UAAA,GAA4B,IAAA;AAIpC,IAAA,IAAA,CAAQ,YAAA,GAAe,IAAA;AAEvB,IAAA,IAAA,CAAQ,YAEJ,EAAC;AAKH,IAAA,IAAI,CAAC,MAAA,CAAO,SAAA,EAAW,MAAM,IAAI,MAAM,mBAAmB,CAAA;AAC1D,IAAA,IAAI,CAAC,MAAA,CAAO,SAAA,EAAW,MAAM,IAAI,MAAM,mBAAmB,CAAA;AAC1D,IAAA,IAAI,CAAC,MAAA,CAAO,QAAA,EAAU,MAAM,IAAI,MAAM,kBAAkB,CAAA;AAExD,IAAA,IAAA,CAAK,MAAA,GAAS;AAAA,MACZ,cAAA,EAAgB,KAAA;AAAA,MAChB,WAAA,EAAa,KAAA;AAAA,MACb,GAAG;AAAA,KACL;AAEA,IAAA,IAAA,CAAK,YAAA,CAAa,UAAU,CAAC,CAAA,KAAM,KAAK,IAAA,CAAK,OAAA,EAAS,CAAC,CAAC,CAAA;AACxD,IAAA,IAAA,CAAK,wBAAA,EAAyB;AAAA,EAChC;AAAA;AAAA,EAIA,EAAA,CACE,OACA,EAAA,EACA;AAhEJ,IAAA,IAAA,EAAA;AAiEI,IAAA,CAAA,EAAA,GAAA,IAAA,CAAK,SAAA,EAAL,KAAA,CAAA,KAAA,EAAA,CAAA,KAAA,CAAA,mBAA0B,IAAI,GAAA,EAAI,CAAA;AAClC,IAAA,IAAA,CAAK,SAAA,CAAU,KAAK,CAAA,CAAG,GAAA,CAAI,EAAE,CAAA;AAC7B,IAAA,OAAO,MAAM,IAAA,CAAK,SAAA,CAAU,KAAK,CAAA,CAAG,OAAO,EAAE,CAAA;AAAA,EAC/C;AAAA,EAEA,MAAM,KAAA,GAAQ;AACZ,IAAA,IAAI,IAAA,CAAK,YAAA,CAAa,OAAA,KAAY,MAAA,EAAQ;AAE1C,IAAA,IAAA,CAAK,YAAA,EAAa;AAClB,IAAA,gBAAA,EAAiB;AACjB,IAAA,IAAA,CAAK,YAAA,CAAa,WAAW,cAAc,CAAA;AAE3C,IAAA,IAAI;AAEF,MAAA,IAAA,CAAK,UAAA,GAAa,IAAA,CAAK,MAAA,CAAO,oBAAA,EAAqB;AACnD,MAAA,IAAA,CAAK,SAAA,GAAY,MAAA,CAAO,UAAA,EAAW,GAAI,OAAO,UAAA,EAAW;AAGzD,MAAA,IAAA,CAAK,YAAA,GAAe,KAAK,kBAAA,EAAmB;AAE5C,MAAA,IAAI,KAAK,YAAA,EAAc;AACrB,QAAA,MAAM,KAAK,kBAAA,EAAmB;AAAA,MAChC,CAAA,MAAO;AACL,QAAA,MAAM,KAAK,iBAAA,EAAkB;AAAA,MAC/B;AAAA,IACF,SAAS,GAAA,EAAK;AACZ,MAAA,IAAA,CAAK,KAAK,GAAA,YAAe,KAAA,GAAQ,MAAM,IAAI,KAAA,CAAM,cAAc,CAAC,CAAA;AAAA,IAClE;AAAA,EACF;AAAA,EAEA,IAAA,GAAO;AACL,IAAA,IAAA,CAAK,UAAU,KAAK,CAAA;AAAA,EACtB;AAAA,EAEA,OAAA,GAAU;AACR,IAAA,IAAA,CAAK,wBAAA,EAAyB;AAC9B,IAAA,IAAA,CAAK,gBAAA,EAAiB;AACtB,IAAA,IAAA,CAAK,WAAW,KAAA,EAAM;AACtB,IAAA,IAAA,CAAK,SAAA,GAAY,MAAA;AACjB,IAAA,IAAA,CAAK,YAAY,EAAC;AAAA,EACpB;AAAA;AAAA,EAIQ,kBAAA,GAA8B;AAIpC,IAAA,OACE,KAAK,MAAA,CAAO,WAAA,IACZ,CAAC,sBAAA,CAAuB,IAAA,CAAK,UAAU,SAAS,CAAA;AAAA,EAEpD;AAAA;AAAA,EAIA,MAAc,kBAAA,GAAqB;AACjC,IAAA,MAAM,KAAA,GAAQ,MAAM,IAAA,CAAK,aAAA,EAAc;AAEvC,IAAA,IAAA,CAAK,SAAA,GAAY,IAAI,SAAA,CAAU;AAAA,MAC7B,QAAQ,MAAM;AACZ,QAAA,IAAA,CAAK,UAAW,IAAA,CAAK;AAAA,UACnB,IAAA,EAAM,UAAA;AAAA,UACN,WAAW,IAAA,CAAK,SAAA;AAAA,UAChB,GAAG,IAAA,CAAK;AAAA,SACT,CAAA;AACD,QAAA,IAAA,CAAK,YAAA,CAAa,WAAW,eAAe,CAAA;AAAA,MAC9C,CAAA;AAAA,MACA,SAAA,EAAW,CAAC,GAAA,KAAwB,IAAA,CAAK,uBAAuB,GAAG,CAAA;AAAA,MACnE,OAAA,EAAS,CAAC,GAAA,KAAQ;AAChB,QAAA,OAAA,CAAQ,KAAA,CAAM,oBAAoB,GAAG,CAAA;AACrC,QAAA,IAAA,CAAK,IAAA,CAAK,IAAI,KAAA,CAAM,6BAA6B,CAAC,CAAA;AAAA,MACpD;AAAA,KACD,CAAA;AAED,IAAA,IAAA,CAAK,SAAA,CAAU,QAAQ,KAAK,CAAA;AAC5B,IAAA,MAAM,KAAK,UAAA,EAAW;AAAA,EACxB;AAAA,EAEQ,uBAAuB,GAAA,EAAqB;AAClD,IAAA,QAAQ,IAAI,IAAA;AAAM,MAChB,KAAK,QAAA;AACH,QAAA,IAAA,CAAK,YAAA,CAAa,WAAW,QAAQ,CAAA;AACrC,QAAA,IAAA,CAAK,UAAW,IAAA,CAAK;AAAA,UACnB,IAAA,EAAM,cAAA;AAAA,UACN,WAAW,IAAA,CAAK,SAAA;AAAA,UAChB,GAAG,IAAA,CAAK,MAAA;AAAA,UACR,GAAA,EAAK,OAAO,QAAA,CAAS;AAAA,SACtB,CAAA;AACD,QAAA;AAAA,MAEF,KAAK,oBAAA;AACH,QAAA,IAAA,CAAK,kBAAkB,GAAG,CAAA;AAC1B,QAAA;AAAA,MAEF,KAAK,kBAAA;AACH,QAAA,IAAA,CAAK,IAAA,CAAK,IAAI,KAAA,CAAM,oCAAoC,CAAC,CAAA;AACzD,QAAA,IAAA,CAAK,mBAAA,EAAoB;AACzB,QAAA;AAAA,MAEF,KAAK,WAAA;AACH,QAAA,IAAA,CAAK,UAAU,IAAI,CAAA;AACnB,QAAA,IAAA,CAAK,mBAAA,EAAoB;AACzB,QAAA;AAAA;AACJ,EACF;AAAA,EAEQ,kBAAkB,GAAA,EAAqB;AAC7C,IAAA,IAAI,CAAC,KAAK,UAAA,IAAc,CAAC,IAAI,MAAA,IAAU,CAAC,IAAI,KAAA,EAAO;AACjD,MAAA,IAAA,CAAK,IAAA,CAAK,IAAI,KAAA,CAAM,gCAAgC,CAAC,CAAA;AACrD,MAAA,IAAA,CAAK,mBAAA,EAAoB;AACzB,MAAA;AAAA,IACF;AAEA,IAAA,IAAI;AACF,MAAA,MAAM,SAAA,GAAY,IAAA,CAAK,MAAA,CAAO,gBAAA,CAAiB;AAAA,QAC7C,WAAW,EAAE,MAAA,EAAQ,IAAI,MAAA,EAAQ,KAAA,EAAO,IAAI,KAAA,EAAM;AAAA,QAClD,WAAW,IAAA,CAAK;AAAA,OACjB,CAAA;AAED,MAAA,IAAI,CAAC,SAAA,EAAW;AACd,QAAA,IAAA,CAAK,IAAA,CAAK,IAAI,KAAA,CAAM,6BAA6B,CAAC,CAAA;AAClD,QAAA,IAAA,CAAK,mBAAA,EAAoB;AACzB,QAAA;AAAA,MACF;AAEA,MAAA,MAAM,MAAA,GAAyB,IAAA,CAAK,KAAA,CAAM,SAAS,CAAA;AAEnD,MAAA,IAAA,CAAK,IAAA,CAAK,WAAW,MAAM,CAAA;AAC3B,MAAA,IAAA,CAAK,YAAA,CAAa,WAAW,eAAe,CAAA;AAG5C,MAAA,IAAA,CAAK,WAAW,IAAA,CAAK;AAAA,QACnB,IAAA,EAAM,SAAA;AAAA,QACN,WAAW,IAAA,CAAK;AAAA,OACjB,CAAA;AAAA,IACH,CAAA,CAAA,MAAQ;AACN,MAAA,IAAA,CAAK,IAAA,CAAK,IAAI,KAAA,CAAM,uCAAuC,CAAC,CAAA;AAC5D,MAAA,IAAA,CAAK,mBAAA,EAAoB;AAAA,IAC3B;AAAA,EACF;AAAA;AAAA,EAIA,MAAc,iBAAA,GAAoB;AAChC,IAAA,MAAM,KAAK,aAAA,EAAc;AAEzB,IAAA,IAAI,KAAK,UAAA,EAAY;AACnB,MAAA,gBAAA,CAAiB,IAAA,CAAK,SAAA,EAAW,IAAA,CAAK,UAAA,EAAY,KAAK,GAAM,CAAA;AAAA,IAC/D;AAGA,IAAA,MAAM,KAAK,YAAA,EAAa;AAGxB,IAAA,IAAA,CAAK,YAAA,CAAa,WAAW,eAAe,CAAA;AAAA,EAG9C;AAAA,EAEQ,gBAAA,GAAmB;AACzB,IAAA,IAAI,KAAK,kBAAA,EAAoB;AAC3B,MAAA,YAAA,CAAa,KAAK,kBAAkB,CAAA;AACpC,MAAA,IAAA,CAAK,kBAAA,GAAqB,MAAA;AAAA,IAC5B;AAAA,EACF;AAAA,EAEA,MAAc,YAAA,GAAe;AAC3B,IAAA,MAAM,SAAS,cAAA,EAAe;AAC9B,IAAA,IAAI,CAAC,MAAA,EAAQ;AAEb,IAAA,IAAA,CAAK,YAAA,CAAa,WAAW,eAAe,CAAA;AAC5C,IAAA,IAAI;AACF,MAAA,MAAM,MAAM,MAAM,KAAA;AAAA,QAChB,CAAA,EAAG,OAAO,CAAA,oBAAA,EAAuB,MAAA,CAAO,SAAS,CAAA;AAAA,OACnD;AAGA,MAAA,IAAI,CAAC,IAAI,EAAA,EAAI;AAEb,MAAA,MAAM,IAAA,GAAO,MAAM,GAAA,CAAI,IAAA,EAAK;AAC5B,MAAA,MAAM,SAAA,GAAY,IAAA,CAAK,MAAA,CAAO,gBAAA,CAAiB;AAAA,QAC7C,WAAW,EAAE,MAAA,EAAQ,KAAK,MAAA,EAAQ,KAAA,EAAO,KAAK,KAAA,EAAM;AAAA,QACpD,WAAW,MAAA,CAAO;AAAA,OACnB,CAAA;AAED,MAAA,IAAI,CAAC,SAAA,EAAW;AACd,QAAA,OAAA,CAAQ,KAAK,2BAA2B,CAAA;AACxC,QAAA;AAAA,MACF;AAEA,MAAA,MAAM,MAAA,GAAyB,IAAA,CAAK,KAAA,CAAM,SAAS,CAAA;AAGnD,MAAA,IAAA,CAAK,gBAAA,EAAiB;AACtB,MAAA,gBAAA,EAAiB;AAEjB,MAAA,IAAA,CAAK,IAAA,CAAK,WAAW,MAAM,CAAA;AAC3B,MAAA,IAAA,CAAK,YAAA,CAAa,WAAW,eAAe,CAAA;AAG5C,MAAA,IAAI,IAAA,CAAK,OAAO,cAAA,EAAgB;AAC9B,QAAA,UAAA,CAAW,MAAM;AACf,UAAA,IAAA,CAAK,YAAA,CAAa,WAAW,WAAW,CAAA;AACxC,UAAA,IAAA,CAAK,KAAA,EAAM;AAAA,QACb,GAAG,IAAI,CAAA;AAAA,MACT,CAAA,MAAO;AACL,QAAA,IAAA,CAAK,YAAA,CAAa,WAAW,WAAW,CAAA;AAAA,MAC1C;AAAA,IACF,SAAS,GAAA,EAAK;AAEZ,MAAA,OAAA,CAAQ,KAAA,CAAM,yBAAyB,GAAG,CAAA;AAAA,IAC5C;AAAA,EACF;AAAA;AAAA,EAIA,MAAc,UAAA,GAAa;AACzB,IAAA,MAAM,OAAA,GAAU;AAAA,MACd,WAAW,IAAA,CAAK,SAAA;AAAA,MAChB,YAAY,IAAA,CAAK,UAAA;AAAA,MACjB,SAAA,EAAW,KAAK,MAAA,CAAO,SAAA;AAAA,MACvB,QAAA,EAAU,KAAK,MAAA,CAAO,QAAA;AAAA,MACtB,SAAA,EAAW,KAAK,MAAA,CAAO,SAAA;AAAA,MACvB,GAAA,EAAK,OAAO,QAAA,CAAS;AAAA,KACvB;AAEA,IAAA,MAAM,KAAK,MAAMG,uBAAA,CAAO,UAAU,IAAA,CAAK,SAAA,CAAU,OAAO,CAAA,EAAG;AAAA,MACzD,IAAA,EAAM,WAAA;AAAA,MACN,KAAA,EAAO,CAAA;AAAA,MACP,KAAA,EAAO,EAAE,KAAA,EAAO,SAAA,EAAW,MAAM,WAAA;AAAY,KAC9C,CAAA;AAED,IAAA,IAAA,CAAK,IAAA,CAAK,MAAM,EAAE,CAAA;AAAA,EACpB;AAAA,EAEA,MAAc,YAAA,GAAe;AAC3B,IAAA,MAAM,WAAW,CAAA,wCAAA,EAA2C,kBAAA;AAAA,MAC1D,IAAA,CAAK;AAAA,KACN,CAAA,YAAA,EAAe,kBAAA;AAAA,MACd,IAAA,CAAK;AAAA,KACN,CAAA,WAAA,EAAc,kBAAA,CAAmB,IAAA,CAAK,MAAA,CAAO,SAAS,CAAC,CAAA,UAAA,EACtD,IAAA,CAAK,MAAA,CAAO,QACd,CAAA,WAAA,EAAc,kBAAA;AAAA,MACZ,KAAK,MAAA,CAAO;AAAA,KACb,CAAA,KAAA,EAAQ,kBAAA,CAAmB,MAAA,CAAO,QAAA,CAAS,IAAI,CAAC,CAAA,CAAA;AAEjD,IAAA,IAAA,CAAK,IAAA,CAAK,YAAY,QAAQ,CAAA;AAAA,EAChC;AAAA;AAAA,EAIQ,wBAAA,GAA2B;AACjC,IAAA,IAAA,CAAK,oBAAoB,YAAY;AACnC,MAAA,IAAI,QAAA,CAAS,oBAAoB,SAAA,EAAW;AAG5C,MAAA,IAAI,KAAK,YAAA,EAAc;AAGvB,MAAA,MAAM,KAAK,YAAA,EAAa;AAAA,IAC1B,CAAA;AAEA,IAAA,QAAA,CAAS,gBAAA,CAAiB,kBAAA,EAAoB,IAAA,CAAK,iBAAiB,CAAA;AAAA,EACtE;AAAA,EAEQ,wBAAA,GAA2B;AACjC,IAAA,IAAI,KAAK,iBAAA,EAAmB;AAC1B,MAAA,QAAA,CAAS,mBAAA,CAAoB,kBAAA,EAAoB,IAAA,CAAK,iBAAiB,CAAA;AACvE,MAAA,IAAA,CAAK,iBAAA,GAAoB,MAAA;AAAA,IAC3B;AAAA,EACF;AAAA;AAAA,EAIA,MAAc,aAAA,GAAiC;AAC7C,IAAA,MAAM,EAAE,SAAA,EAAW,SAAA,EAAW,QAAA,KAAa,IAAA,CAAK,MAAA;AAChD,IAAA,MAAM,MAAM,MAAM,KAAA;AAAA,MAChB,GAAG,OAAO,CAAA,kBAAA,EAAqB,SAAS,CAAA,WAAA,EAAc,QAAQ,eAAe,SAAS,CAAA;AAAA,KACxF;AAEA,IAAA,IAAI,CAAC,IAAI,EAAA,EAAI;AACX,MAAA,MAAM,KAAA,GAAQ,MAAM,GAAA,CAAI,IAAA,EAAK;AAC7B,MAAA,MAAM,IAAI,MAAM,KAAK,CAAA;AAAA,IACvB;AAEA,IAAA,MAAM,IAAA,GAAO,MAAM,GAAA,CAAI,IAAA,EAAK;AAC5B,IAAA,OAAO,IAAA,CAAK,SAAA;AAAA,EACd;AAAA,EAEQ,UAAU,OAAA,EAAkB;AAElC,IAAA,IAAA,CAAK,gBAAA,EAAiB;AAGtB,IAAA,IAAI,KAAK,SAAA,EAAW;AAClB,MAAA,IAAI,CAAC,OAAA,EAAS;AACZ,QAAA,IAAA,CAAK,UAAU,IAAA,CAAK;AAAA,UAClB,IAAA,EAAM,mBAAA;AAAA,UACN,WAAW,IAAA,CAAK,SAAA;AAAA,UAChB,SAAA,EAAW,KAAK,MAAA,CAAO,SAAA;AAAA,UACvB,SAAA,EAAW,KAAK,MAAA,CAAO,SAAA;AAAA,UACvB,QAAA,EAAU,KAAK,MAAA,CAAO;AAAA,SACvB,CAAA;AAAA,MACH;AACA,MAAA,IAAA,CAAK,UAAU,KAAA,EAAM;AACrB,MAAA,IAAA,CAAK,SAAA,GAAY,MAAA;AAAA,IACnB;AAEA,IAAA,gBAAA,EAAiB;AACjB,IAAA,IAAA,CAAK,YAAA,EAAa;AAElB,IAAA,IAAI,CAAC,IAAA,CAAK,MAAA,CAAO,cAAA,EAAgB;AAC/B,MAAA,IAAA,CAAK,wBAAA,EAAyB;AAAA,IAChC;AAEA,IAAA,IAAA,CAAK,YAAA,CAAa,UAAA,CAAW,OAAA,GAAU,WAAA,GAAc,MAAM,CAAA;AAAA,EAC7D;AAAA,EAEQ,mBAAA,GAAsB;AAC5B,IAAA,IAAI,CAAC,IAAA,CAAK,MAAA,CAAO,cAAA,EAAgB;AAEjC,IAAA,IAAA,CAAK,gBAAA,EAAiB;AACtB,IAAA,IAAA,CAAK,WAAW,KAAA,EAAM;AACtB,IAAA,IAAA,CAAK,SAAA,GAAY,MAAA;AACjB,IAAA,IAAA,CAAK,YAAA,CAAa,WAAW,MAAM,CAAA;AAEnC,IAAA,UAAA,CAAW,MAAM;AACf,MAAA,IAAA,CAAK,KAAA,EAAM;AAAA,IACb,GAAG,GAAG,CAAA;AAAA,EACR;AAAA,EAEQ,YAAA,GAAe;AACrB,IAAA,IAAA,CAAK,SAAA,GAAY,EAAA;AACjB,IAAA,IAAA,CAAK,UAAA,GAAa,IAAA;AAAA,EACpB;AAAA,EAEQ,IAAA,CACN,OACA,OAAA,EACA;AACA,IAAA,IAAA,CAAK,SAAA,CAAU,KAAK,CAAA,EAAG,OAAA,CAAQ,CAAC,EAAA,KAAO,EAAA,CAAG,OAAO,CAAC,CAAA;AAAA,EACpD;AAAA,EAEQ,KAAK,GAAA,EAAY;AACvB,IAAA,IAAA,CAAK,IAAA,CAAK,SAAS,GAAG,CAAA;AACtB,IAAA,IAAA,CAAK,YAAA,CAAa,WAAW,OAAO,CAAA;AAAA,EACtC;AACF","file":"index.js","sourcesContent":["import nacl from \"tweetnacl\";\nimport { decodeBase64, encodeBase64 } from \"tweetnacl-util\";\n\ninterface EncryptedMessage {\n cipher: string; // Base64 encoded\n nonce: string; // Base64 encoded\n}\n\nexport class CryptoService {\n generateSymmetricKey(): string {\n const key = nacl.randomBytes(32);\n return encodeBase64(key);\n }\n\n /**\n * Encrypt with symmetric key (secret-key encryption)\n * Use this when both parties share the same secret key\n * @param plaintext - Message to encrypt\n * @param keyString - Symmetric key (base64)\n * @returns Encrypted message with nonce\n */\n encryptSymmetric({\n plaintext,\n keyString,\n }: {\n plaintext: string;\n keyString: string;\n }): EncryptedMessage {\n const key = decodeBase64(keyString);\n const nonce = nacl.randomBytes(24);\n\n const messageBytes = new TextEncoder().encode(plaintext);\n\n const ciphertext = nacl.secretbox(messageBytes, nonce, key);\n\n return {\n cipher: encodeBase64(ciphertext),\n nonce: encodeBase64(nonce),\n };\n }\n\n /**\n * Decrypt with symmetric key\n * @param encrypted - Encrypted message with nonce\n * @param keyString - Symmetric key (base64)\n * @returns Decrypted plaintext\n */\n decryptSymmetric({\n encrypted,\n keyString,\n }: {\n encrypted: EncryptedMessage;\n keyString: string;\n }): string | null {\n try {\n const key = decodeBase64(keyString);\n const ciphertextBytes = decodeBase64(encrypted.cipher);\n const nonceBytes = decodeBase64(encrypted.nonce);\n\n const decrypted = nacl.secretbox.open(ciphertextBytes, nonceBytes, key);\n\n if (!decrypted) {\n throw new Error(\"Decryption failed - invalid key or corrupted data\");\n }\n\n const decoded = new TextDecoder().decode(decrypted);\n return decoded;\n } catch (error) {\n console.error(\"Decryption failed\", error);\n return null;\n }\n }\n}\n\nexport default CryptoService;\nexport type { EncryptedMessage };\n","// hybridStorage.ts\n/**\n * Hybrid storage: Try sessionStorage first, fallback to memory\n * Best of both worlds - survives page refresh but auto-cleans\n */\n\ninterface StorageOptions {\n ttlMs?: number;\n useSessionStorage?: boolean;\n}\n\nclass AuthStorage {\n private readonly prefix = \"pelican_auth_\";\n private readonly defaultTTL = 5 * 60 * 1000; // 5 minutes\n private memoryCache: Map<string, { value: any; expiresAt: number }> =\n new Map();\n\n /**\n * Store auth session with automatic cleanup\n */\n set(key: string, value: any, options: StorageOptions = {}): void {\n const { ttlMs = this.defaultTTL, useSessionStorage = true } = options;\n\n const expiresAt = Date.now() + ttlMs;\n const data = { value, expiresAt };\n\n // Try sessionStorage first\n if (useSessionStorage) {\n try {\n sessionStorage.setItem(`${this.prefix}${key}`, JSON.stringify(data));\n } catch (error) {\n console.warn(\"SessionStorage unavailable, using memory:\", error);\n this.setMemory(key, data);\n }\n } else {\n this.setMemory(key, data);\n }\n }\n\n /**\n * Get stored value if not expired\n */\n get(key: string): any | null {\n // Try sessionStorage first\n try {\n const stored = sessionStorage.getItem(`${this.prefix}${key}`);\n if (stored) {\n const data = JSON.parse(stored);\n\n // Check expiration\n if (Date.now() > data.expiresAt) {\n this.remove(key);\n return null;\n }\n\n return data.value;\n }\n } catch (error) {\n // Fallback to memory\n }\n\n // Try memory cache\n return this.getMemory(key);\n }\n\n /**\n * Remove specific key\n */\n remove(key: string): void {\n try {\n sessionStorage.removeItem(`${this.prefix}${key}`);\n } catch (error) {\n // Ignore\n }\n this.memoryCache.delete(key);\n }\n\n /**\n * Clear all auth data\n */\n clear(): void {\n // Clear sessionStorage\n try {\n Object.keys(sessionStorage).forEach((key) => {\n if (key.startsWith(this.prefix)) {\n sessionStorage.removeItem(key);\n }\n });\n } catch (error) {\n // Ignore\n }\n\n // Clear memory\n this.memoryCache.clear();\n }\n\n // ========================================\n // Memory cache helpers\n // ========================================\n\n private setMemory(\n key: string,\n data: { value: any; expiresAt: number }\n ): void {\n this.memoryCache.set(key, data);\n\n // Schedule cleanup\n const ttl = data.expiresAt - Date.now();\n setTimeout(() => {\n this.memoryCache.delete(key);\n }, ttl);\n }\n\n private getMemory(key: string): any | null {\n const data = this.memoryCache.get(key);\n if (!data) return null;\n\n if (Date.now() > data.expiresAt) {\n this.memoryCache.delete(key);\n return null;\n }\n\n return data.value;\n }\n}\n\n// Singleton instance\nconst storage = new AuthStorage();\n\n// ========================================\n// Convenience functions for auth flow\n// ========================================\n\nexport interface AuthSession {\n sessionId: string;\n sessionKey: string;\n}\n\nexport const storeAuthSession = (\n sessionId: string,\n sessionKey: string,\n ttlMs?: number\n): void => {\n storage.set(\"session\", { sessionId, sessionKey }, { ttlMs });\n};\n\nexport const getAuthSession = (): AuthSession | null => {\n return storage.get(\"session\");\n};\n\nexport const clearAuthSession = (): void => {\n storage.remove(\"session\");\n};\n\nexport const clearAllAuthData = (): void => {\n storage.clear();\n};\n\nexport default storage;\n","import type { PelicanAuthState } from \"../types/types\";\n\nexport class StateMachine {\n private state: PelicanAuthState = \"idle\";\n private listeners = new Set<(s: PelicanAuthState) => void>();\n\n get current() {\n return this.state;\n }\n\n transition(next: PelicanAuthState) {\n this.state = next;\n this.listeners.forEach((l) => l(next));\n }\n\n subscribe(fn: (s: PelicanAuthState) => void) {\n this.listeners.add(fn);\n return () => this.listeners.delete(fn);\n }\n}\n","import { ISocketMessage } from \"../types/types\";\n\ntype TransportHandlers = {\n onOpen?: () => void;\n onMessage?: (msg: ISocketMessage) => void;\n onError?: (err: Event) => void;\n onClose?: (ev: CloseEvent) => void;\n};\n\n/**\n * WebSocket Transport with automatic reconnection\n * Handles connection lifecycle and message passing\n */\nexport class Transport {\n private socket?: WebSocket;\n private handlers: TransportHandlers;\n private reconnectAttempts = 0;\n private maxReconnectAttempts = 3; // Reduced from 5 for mobile\n private isExplicitlyClosed = false;\n private url?: string;\n private reconnectTimeout?: number;\n private isReconnecting = false;\n\n constructor(handlers: TransportHandlers) {\n this.handlers = handlers;\n }\n\n /**\n * Establish WebSocket connection\n * @param url - WebSocket URL\n */\n connect(url: string) {\n this.url = url;\n this.isExplicitlyClosed = false;\n\n // Clean up any existing socket\n if (this.socket) {\n this.socket.onclose = null;\n this.socket.onerror = null;\n this.socket.onmessage = null;\n this.socket.onopen = null;\n\n if (\n this.socket.readyState === WebSocket.OPEN ||\n this.socket.readyState === WebSocket.CONNECTING\n ) {\n this.socket.close();\n }\n }\n\n this.socket = new WebSocket(url);\n\n this.socket.onopen = () => {\n this.reconnectAttempts = 0;\n this.isReconnecting = false;\n this.handlers.onOpen?.();\n };\n\n this.socket.onmessage = (e: MessageEvent) => {\n try {\n const data = JSON.parse(e.data);\n this.handlers.onMessage?.(data);\n } catch (err) {\n console.error(\"Failed to parse WebSocket message\", err);\n }\n };\n\n this.socket.onerror = (e: Event) => {\n // Only emit error if not reconnecting and not explicitly closed\n if (!this.isReconnecting && !this.isExplicitlyClosed) {\n this.handlers.onError?.(e);\n }\n };\n\n this.socket.onclose = (e: CloseEvent) => {\n // Clear any pending reconnect timeout\n if (this.reconnectTimeout) {\n clearTimeout(this.reconnectTimeout);\n this.reconnectTimeout = undefined;\n }\n\n // Emit close event\n if (!this.isReconnecting) {\n this.handlers.onClose?.(e);\n }\n\n // Only reconnect if:\n // 1. Not explicitly closed by user\n // 2. Not already reconnecting\n // 3. Haven't exceeded max attempts\n if (\n !this.isExplicitlyClosed &&\n !this.isReconnecting &&\n this.reconnectAttempts < this.maxReconnectAttempts\n ) {\n this.attemptReconnect();\n }\n };\n }\n\n /**\n * Attempt to reconnect with exponential backoff\n */\n private attemptReconnect() {\n if (this.reconnectAttempts >= this.maxReconnectAttempts) {\n console.warn(\"Max WebSocket reconnect attempts reached\");\n return;\n }\n\n this.isReconnecting = true;\n this.reconnectAttempts++;\n\n // Exponential backoff: 500ms, 1s, 2s\n const delay = Math.min(Math.pow(2, this.reconnectAttempts - 1) * 500, 2000);\n\n console.log(\n `Reconnecting WebSocket (attempt ${this.reconnectAttempts}/${this.maxReconnectAttempts}) in ${delay}ms...`\n );\n\n this.reconnectTimeout = window.setTimeout(() => {\n if (this.url && !this.isExplicitlyClosed) {\n this.connect(this.url);\n }\n }, delay);\n }\n\n /**\n * Send a message through the WebSocket\n * Queues message if connection is not open\n */\n send(payload: ISocketMessage) {\n if (this.socket?.readyState === WebSocket.OPEN) {\n try {\n this.socket.send(JSON.stringify(payload));\n } catch (err) {\n console.error(\"Failed to send WebSocket message:\", err);\n }\n } else {\n console.warn(\n \"WebSocket not open, message not sent:\",\n this.socket?.readyState\n );\n }\n }\n\n /**\n * Close the WebSocket connection\n * Prevents automatic reconnection\n */\n close() {\n this.isExplicitlyClosed = true;\n this.isReconnecting = false;\n\n // Clear reconnect timeout\n if (this.reconnectTimeout) {\n clearTimeout(this.reconnectTimeout);\n this.reconnectTimeout = undefined;\n }\n\n // Close socket\n if (this.socket) {\n // Remove event listeners to prevent callbacks\n this.socket.onclose = null;\n this.socket.onerror = null;\n this.socket.onmessage = null;\n this.socket.onopen = null;\n\n if (\n this.socket.readyState === WebSocket.OPEN ||\n this.socket.readyState === WebSocket.CONNECTING\n ) {\n this.socket.close();\n }\n\n this.socket = undefined;\n }\n }\n\n /**\n * Get current connection state\n */\n get readyState(): number | undefined {\n return this.socket?.readyState;\n }\n\n /**\n * Check if connection is open\n */\n get isOpen(): boolean {\n return this.socket?.readyState === WebSocket.OPEN;\n }\n}\n","export const BASEURL = \"http://192.168.1.9:8080\";\n\n// export const BASEURL = \"https://identityapi.pelicanidentity.com\";\n","import CryptoService from \"../utilities/crypto\";\nimport QRCode from \"qrcode\";\nimport {\n PelicanAuthConfig,\n PelicanAuthEventMap,\n ISocketMessage,\n IdentityResult,\n} from \"../types/types\";\nimport {\n storeAuthSession,\n getAuthSession,\n clearAuthSession,\n} from \"../utilities/storage\";\nimport { StateMachine } from \"../utilities/stateMachine\";\nimport { Transport } from \"../utilities/transport\";\n\nimport { BASEURL } from \"../constants\";\n\ntype Listener<T> = (payload: T) => void;\n\n/**\n * PelicanAuth SDK\n *\n * Uses WebSocket for QR code flow (desktop)\n * Uses visibility recovery for deep link flow (mobile)\n */\nexport class PelicanAuthentication {\n private readonly crypto = new CryptoService();\n private readonly stateMachine = new StateMachine();\n\n private transport?: Transport;\n private sessionId = \"\";\n private sessionKey: string | null = null;\n\n private visibilityHandler?: () => void;\n private backupCheckTimeout?: number;\n private useWebSocket = true;\n\n private listeners: {\n [K in keyof PelicanAuthEventMap]?: Set<Listener<any>>;\n } = {};\n\n private readonly config: Required<PelicanAuthConfig>;\n\n constructor(config: PelicanAuthConfig) {\n if (!config.publicKey) throw new Error(\"Missing publicKey\");\n if (!config.projectId) throw new Error(\"Missing projectId\");\n if (!config.authType) throw new Error(\"Missing authType\");\n\n this.config = {\n continuousMode: false,\n forceQRCode: false,\n ...config,\n };\n\n this.stateMachine.subscribe((s) => this.emit(\"state\", s));\n this.attachVisibilityRecovery();\n }\n\n /* -------------------- Public API -------------------- */\n\n on<K extends keyof PelicanAuthEventMap>(\n event: K,\n cb: Listener<PelicanAuthEventMap[K]>\n ) {\n this.listeners[event] ??= new Set();\n this.listeners[event]!.add(cb);\n return () => this.listeners[event]!.delete(cb);\n }\n\n async start() {\n if (this.stateMachine.current !== \"idle\") return;\n\n this.resetSession();\n clearAuthSession();\n this.stateMachine.transition(\"initializing\");\n\n try {\n // Generate session credentials\n this.sessionKey = this.crypto.generateSymmetricKey();\n this.sessionId = crypto.randomUUID() + crypto.randomUUID();\n\n // Decide: WebSocket (QR) or Deep Link\n this.useWebSocket = this.shouldUseWebSocket();\n\n if (this.useWebSocket) {\n await this.startWebSocketFlow();\n } else {\n await this.startDeepLinkFlow();\n }\n } catch (err) {\n this.fail(err instanceof Error ? err : new Error(\"Start failed\"));\n }\n }\n\n stop() {\n this.terminate(false);\n }\n\n destroy() {\n this.detachVisibilityRecovery();\n this.clearBackupCheck();\n this.transport?.close();\n this.transport = undefined;\n this.listeners = {};\n }\n\n /* -------------------- Flow Selection -------------------- */\n\n private shouldUseWebSocket(): boolean {\n // Use WebSocket for:\n // 1. Desktop (QR code)\n // 2. Mobile when forceQRCode is true\n return (\n this.config.forceQRCode ||\n !/Android|iPhone|iPad/i.test(navigator.userAgent)\n );\n }\n\n /* -------------------- WebSocket Flow (QR Code) -------------------- */\n\n private async startWebSocketFlow() {\n const relay = await this.fetchRelayUrl();\n\n this.transport = new Transport({\n onOpen: () => {\n this.transport!.send({\n type: \"register\",\n sessionID: this.sessionId,\n ...this.config,\n });\n this.stateMachine.transition(\"awaiting-pair\");\n },\n onMessage: (msg: ISocketMessage) => this.handleWebSocketMessage(msg),\n onError: (err) => {\n console.error(\"WebSocket error:\", err);\n this.fail(new Error(\"WebSocket connection failed\"));\n },\n });\n\n this.transport.connect(relay);\n await this.emitQRCode();\n }\n\n private handleWebSocketMessage(msg: ISocketMessage) {\n switch (msg.type) {\n case \"paired\":\n this.stateMachine.transition(\"paired\");\n this.transport!.send({\n type: \"authenticate\",\n sessionID: this.sessionId,\n ...this.config,\n url: window.location.href,\n });\n return;\n\n case \"phone-auth-success\":\n this.handleAuthSuccess(msg);\n return;\n\n case \"phone-terminated\":\n this.fail(new Error(\"Authentication cancelled on device\"));\n this.restartIfContinuous();\n return;\n\n case \"confirmed\":\n this.terminate(true);\n this.restartIfContinuous();\n return;\n }\n }\n\n private handleAuthSuccess(msg: ISocketMessage) {\n if (!this.sessionKey || !msg.cipher || !msg.nonce) {\n this.fail(new Error(\"Invalid authentication payload\"));\n this.restartIfContinuous();\n return;\n }\n\n try {\n const decrypted = this.crypto.decryptSymmetric({\n encrypted: { cipher: msg.cipher, nonce: msg.nonce },\n keyString: this.sessionKey,\n });\n\n if (!decrypted) {\n this.fail(new Error(\"Invalid authentication data\"));\n this.restartIfContinuous();\n return;\n }\n\n const result: IdentityResult = JSON.parse(decrypted);\n\n this.emit(\"success\", result);\n this.stateMachine.transition(\"authenticated\");\n\n // Confirm receipt\n this.transport?.send({\n type: \"confirm\",\n sessionID: this.sessionId,\n });\n } catch {\n this.fail(new Error(\"Failed to decrypt authentication data\"));\n this.restartIfContinuous();\n }\n }\n\n /* -------------------- Deep Link Flow (Mobile) -------------------- */\n\n private async startDeepLinkFlow() {\n await this.fetchRelayUrl();\n // Store session for later recovery\n if (this.sessionKey) {\n storeAuthSession(this.sessionId, this.sessionKey, 10 * 60_000); // 10 min TTL\n }\n\n // Emit deep link\n await this.emitDeepLink();\n\n // Move to awaiting state\n this.stateMachine.transition(\"awaiting-pair\");\n\n // Backup check in case user returns quickly (within 3 seconds)\n }\n\n private clearBackupCheck() {\n if (this.backupCheckTimeout) {\n clearTimeout(this.backupCheckTimeout);\n this.backupCheckTimeout = undefined;\n }\n }\n\n private async checkSession() {\n const cached = getAuthSession();\n if (!cached) return;\n\n this.stateMachine.transition(\"awaiting-auth\");\n try {\n const res = await fetch(\n `${BASEURL}/session?session_id=${cached.sessionId}`\n );\n\n // Session not ready yet\n if (!res.ok) return;\n\n const data = await res.json();\n const decrypted = this.crypto.decryptSymmetric({\n encrypted: { cipher: data.cipher, nonce: data.nonce },\n keyString: cached.sessionKey,\n });\n\n if (!decrypted) {\n console.warn(\"Failed to decrypt session\");\n return;\n }\n\n const result: IdentityResult = JSON.parse(decrypted);\n\n // Success!\n this.clearBackupCheck();\n clearAuthSession();\n\n this.emit(\"success\", result);\n this.stateMachine.transition(\"authenticated\");\n\n // In continuous mode, restart after delay\n if (this.config.continuousMode) {\n setTimeout(() => {\n this.stateMachine.transition(\"confirmed\");\n this.start();\n }, 1500);\n } else {\n this.stateMachine.transition(\"confirmed\");\n }\n } catch (err) {\n // Silently fail - user will retry or visibility change will trigger check\n console.debug(\"Session check failed:\", err);\n }\n }\n\n /* -------------------- Entry Point Generation -------------------- */\n\n private async emitQRCode() {\n const payload = {\n sessionID: this.sessionId,\n sessionKey: this.sessionKey,\n publicKey: this.config.publicKey,\n authType: this.config.authType,\n projectId: this.config.projectId,\n url: window.location.href,\n };\n\n const qr = await QRCode.toDataURL(JSON.stringify(payload), {\n type: \"image/png\",\n scale: 3,\n color: { light: \"#ffffff\", dark: \"#424242ff\" },\n });\n\n this.emit(\"qr\", qr);\n }\n\n private async emitDeepLink() {\n const deeplink = `pelicanvault://auth/deep-link?sessionID=${encodeURIComponent(\n this.sessionId\n )}&sessionKey=${encodeURIComponent(\n this.sessionKey!\n )}&publicKey=${encodeURIComponent(this.config.publicKey)}&authType=${\n this.config.authType\n }&projectId=${encodeURIComponent(\n this.config.projectId\n )}&url=${encodeURIComponent(window.location.href)}`;\n\n this.emit(\"deeplink\", deeplink);\n }\n\n /* -------------------- Visibility Recovery -------------------- */\n\n private attachVisibilityRecovery() {\n this.visibilityHandler = async () => {\n if (document.visibilityState !== \"visible\") return;\n\n // Only check for deep link flow\n if (this.useWebSocket) return;\n\n // Check session when page becomes visible\n await this.checkSession();\n };\n\n document.addEventListener(\"visibilitychange\", this.visibilityHandler);\n }\n\n private detachVisibilityRecovery() {\n if (this.visibilityHandler) {\n document.removeEventListener(\"visibilitychange\", this.visibilityHandler);\n this.visibilityHandler = undefined;\n }\n }\n\n /* -------------------- Helpers -------------------- */\n\n private async fetchRelayUrl(): Promise<string> {\n const { publicKey, projectId, authType } = this.config;\n const res = await fetch(\n `${BASEURL}/relay?public_key=${publicKey}&auth_type=${authType}&project_id=${projectId}`\n );\n\n if (!res.ok) {\n const error = await res.text();\n throw new Error(error);\n }\n\n const json = await res.json();\n return json.relay_url;\n }\n\n private terminate(success: boolean) {\n // Clear backup check\n this.clearBackupCheck();\n\n // Close WebSocket if active\n if (this.transport) {\n if (!success) {\n this.transport.send({\n type: \"client-terminated\",\n sessionID: this.sessionId,\n projectId: this.config.projectId,\n publicKey: this.config.publicKey,\n authType: this.config.authType,\n });\n }\n this.transport.close();\n this.transport = undefined;\n }\n\n clearAuthSession();\n this.resetSession();\n\n if (!this.config.continuousMode) {\n this.detachVisibilityRecovery();\n }\n\n this.stateMachine.transition(success ? \"confirmed\" : \"idle\");\n }\n\n private restartIfContinuous() {\n if (!this.config.continuousMode) return;\n\n this.clearBackupCheck();\n this.transport?.close();\n this.transport = undefined;\n this.stateMachine.transition(\"idle\");\n\n setTimeout(() => {\n this.start();\n }, 150);\n }\n\n private resetSession() {\n this.sessionId = \"\";\n this.sessionKey = null;\n }\n\n private emit<K extends keyof PelicanAuthEventMap>(\n event: K,\n payload: PelicanAuthEventMap[K]\n ) {\n this.listeners[event]?.forEach((cb) => cb(payload));\n }\n\n private fail(err: Error) {\n this.emit(\"error\", err);\n this.stateMachine.transition(\"error\");\n }\n}\n"]}
package/dist/index.mjs CHANGED
@@ -181,16 +181,32 @@ var StateMachine = class {
181
181
  var Transport = class {
182
182
  constructor(handlers) {
183
183
  this.reconnectAttempts = 0;
184
- this.maxReconnectAttempts = 5;
184
+ this.maxReconnectAttempts = 3;
185
+ // Reduced from 5 for mobile
185
186
  this.isExplicitlyClosed = false;
187
+ this.isReconnecting = false;
186
188
  this.handlers = handlers;
187
189
  }
190
+ /**
191
+ * Establish WebSocket connection
192
+ * @param url - WebSocket URL
193
+ */
188
194
  connect(url) {
189
195
  this.url = url;
190
196
  this.isExplicitlyClosed = false;
197
+ if (this.socket) {
198
+ this.socket.onclose = null;
199
+ this.socket.onerror = null;
200
+ this.socket.onmessage = null;
201
+ this.socket.onopen = null;
202
+ if (this.socket.readyState === WebSocket.OPEN || this.socket.readyState === WebSocket.CONNECTING) {
203
+ this.socket.close();
204
+ }
205
+ }
191
206
  this.socket = new WebSocket(url);
192
207
  this.socket.onopen = () => {
193
208
  this.reconnectAttempts = 0;
209
+ this.isReconnecting = false;
194
210
  this.handlers.onOpen?.();
195
211
  };
196
212
  this.socket.onmessage = (e) => {
@@ -198,43 +214,103 @@ var Transport = class {
198
214
  const data = JSON.parse(e.data);
199
215
  this.handlers.onMessage?.(data);
200
216
  } catch (err) {
201
- console.error("Failed to parse message", err);
217
+ console.error("Failed to parse WebSocket message", err);
202
218
  }
203
219
  };
204
220
  this.socket.onerror = (e) => {
205
- this.handlers.onError?.(e);
221
+ if (!this.isReconnecting && !this.isExplicitlyClosed) {
222
+ this.handlers.onError?.(e);
223
+ }
206
224
  };
207
225
  this.socket.onclose = (e) => {
208
- this.handlers.onClose?.(e);
209
- if (!this.isExplicitlyClosed) {
226
+ if (this.reconnectTimeout) {
227
+ clearTimeout(this.reconnectTimeout);
228
+ this.reconnectTimeout = void 0;
229
+ }
230
+ if (!this.isReconnecting) {
231
+ this.handlers.onClose?.(e);
232
+ }
233
+ if (!this.isExplicitlyClosed && !this.isReconnecting && this.reconnectAttempts < this.maxReconnectAttempts) {
210
234
  this.attemptReconnect();
211
235
  }
212
236
  };
213
237
  }
238
+ /**
239
+ * Attempt to reconnect with exponential backoff
240
+ */
214
241
  attemptReconnect() {
215
242
  if (this.reconnectAttempts >= this.maxReconnectAttempts) {
216
- console.error("\u274C Max reconnect attempts reached");
243
+ console.warn("Max WebSocket reconnect attempts reached");
217
244
  return;
218
245
  }
246
+ this.isReconnecting = true;
219
247
  this.reconnectAttempts++;
220
- const delay = Math.pow(2, this.reconnectAttempts) * 500;
221
- setTimeout(() => {
222
- if (this.url) this.connect(this.url);
248
+ const delay = Math.min(Math.pow(2, this.reconnectAttempts - 1) * 500, 2e3);
249
+ console.log(
250
+ `Reconnecting WebSocket (attempt ${this.reconnectAttempts}/${this.maxReconnectAttempts}) in ${delay}ms...`
251
+ );
252
+ this.reconnectTimeout = window.setTimeout(() => {
253
+ if (this.url && !this.isExplicitlyClosed) {
254
+ this.connect(this.url);
255
+ }
223
256
  }, delay);
224
257
  }
258
+ /**
259
+ * Send a message through the WebSocket
260
+ * Queues message if connection is not open
261
+ */
225
262
  send(payload) {
226
263
  if (this.socket?.readyState === WebSocket.OPEN) {
227
- this.socket.send(JSON.stringify(payload));
264
+ try {
265
+ this.socket.send(JSON.stringify(payload));
266
+ } catch (err) {
267
+ console.error("Failed to send WebSocket message:", err);
268
+ }
269
+ } else {
270
+ console.warn(
271
+ "WebSocket not open, message not sent:",
272
+ this.socket?.readyState
273
+ );
228
274
  }
229
275
  }
276
+ /**
277
+ * Close the WebSocket connection
278
+ * Prevents automatic reconnection
279
+ */
230
280
  close() {
231
281
  this.isExplicitlyClosed = true;
232
- this.socket?.close();
282
+ this.isReconnecting = false;
283
+ if (this.reconnectTimeout) {
284
+ clearTimeout(this.reconnectTimeout);
285
+ this.reconnectTimeout = void 0;
286
+ }
287
+ if (this.socket) {
288
+ this.socket.onclose = null;
289
+ this.socket.onerror = null;
290
+ this.socket.onmessage = null;
291
+ this.socket.onopen = null;
292
+ if (this.socket.readyState === WebSocket.OPEN || this.socket.readyState === WebSocket.CONNECTING) {
293
+ this.socket.close();
294
+ }
295
+ this.socket = void 0;
296
+ }
297
+ }
298
+ /**
299
+ * Get current connection state
300
+ */
301
+ get readyState() {
302
+ return this.socket?.readyState;
303
+ }
304
+ /**
305
+ * Check if connection is open
306
+ */
307
+ get isOpen() {
308
+ return this.socket?.readyState === WebSocket.OPEN;
233
309
  }
234
310
  };
235
311
 
236
312
  // src/constants.ts
237
- var BASEURL = "https://identityapi.pelicanidentity.com";
313
+ var BASEURL = "http://192.168.1.9:8080";
238
314
 
239
315
  // src/engine/engine.ts
240
316
  var PelicanAuthentication = class {
@@ -243,6 +319,7 @@ var PelicanAuthentication = class {
243
319
  this.stateMachine = new StateMachine();
244
320
  this.sessionId = "";
245
321
  this.sessionKey = null;
322
+ this.useWebSocket = true;
246
323
  this.listeners = {};
247
324
  if (!config.publicKey) throw new Error("Missing publicKey");
248
325
  if (!config.projectId) throw new Error("Missing projectId");
@@ -255,104 +332,67 @@ var PelicanAuthentication = class {
255
332
  this.stateMachine.subscribe((s) => this.emit("state", s));
256
333
  this.attachVisibilityRecovery();
257
334
  }
258
- /* -------------------- public API -------------------- */
259
- /**
260
- * Subscribe to SDK events (qr, deeplink, success, error, state)
261
- * @returns Unsubscribe function
262
- */
335
+ /* -------------------- Public API -------------------- */
263
336
  on(event, cb) {
264
337
  var _a;
265
338
  (_a = this.listeners)[event] ?? (_a[event] = /* @__PURE__ */ new Set());
266
339
  this.listeners[event].add(cb);
267
340
  return () => this.listeners[event].delete(cb);
268
341
  }
269
- /**
270
- * Initializes the authentication flow.
271
- * Fetches a relay, establishes a WebSocket, and generates the E2EE session key.
272
- */
273
342
  async start() {
274
343
  if (this.stateMachine.current !== "idle") return;
275
344
  this.resetSession();
276
345
  clearAuthSession();
277
346
  this.stateMachine.transition("initializing");
278
347
  try {
279
- const relay = await this.fetchRelayUrl();
280
348
  this.sessionKey = this.crypto.generateSymmetricKey();
281
349
  this.sessionId = crypto.randomUUID() + crypto.randomUUID();
282
- this.transport = new Transport({
283
- onOpen: () => {
284
- this.transport.send({
285
- type: "register",
286
- sessionID: this.sessionId,
287
- ...this.config
288
- });
289
- this.stateMachine.transition("awaiting-pair");
290
- },
291
- onMessage: (msg) => this.handleMessage(msg),
292
- onError: () => this.fail(new Error("WebSocket connection failed"))
293
- });
294
- this.transport.connect(relay);
295
- await this.emitEntryPoint();
350
+ this.useWebSocket = this.shouldUseWebSocket();
351
+ if (this.useWebSocket) {
352
+ await this.startWebSocketFlow();
353
+ } else {
354
+ await this.startDeepLinkFlow();
355
+ }
296
356
  } catch (err) {
297
357
  this.fail(err instanceof Error ? err : new Error("Start failed"));
298
358
  }
299
359
  }
300
- /**
301
- * Manually stops the authentication process and closes connections.
302
- */
303
360
  stop() {
304
361
  this.terminate(false);
305
362
  }
306
- /* -------------------- internals -------------------- */
307
- /** Fetches the WebSocket Relay URL from the backend */
308
- async fetchRelayUrl() {
309
- const { publicKey, projectId, authType } = this.config;
310
- const res = await fetch(
311
- `${BASEURL}/relay?public_key=${publicKey}&auth_type=${authType}&project_id=${projectId}`
312
- );
313
- if (!res.ok) {
314
- const error = await res.text();
315
- throw new Error(error);
316
- }
317
- const json = await res.json();
318
- return json.relay_url;
363
+ destroy() {
364
+ this.detachVisibilityRecovery();
365
+ this.clearBackupCheck();
366
+ this.transport?.close();
367
+ this.transport = void 0;
368
+ this.listeners = {};
319
369
  }
320
- /**
321
- * Decides whether to show a QR code (Desktop) or a Deep Link (Mobile).
322
- */
323
- async emitEntryPoint() {
324
- const payload = {
325
- sessionID: this.sessionId,
326
- sessionKey: this.sessionKey,
327
- publicKey: this.config.publicKey,
328
- authType: this.config.authType,
329
- projectId: this.config.projectId,
330
- url: window.location.href
331
- };
332
- const shouldUseQR = this.config.forceQRCode || !/Android|iPhone|iPad/i.test(navigator.userAgent);
333
- if (!shouldUseQR && this.sessionKey) {
334
- storeAuthSession(this.sessionId, this.sessionKey, 5 * 6e4);
335
- this.emit(
336
- "deeplink",
337
- `pelicanvault://auth/deep-link?sessionID=${encodeURIComponent(
338
- this.sessionId
339
- )}&sessionKey=${encodeURIComponent(
340
- this.sessionKey
341
- )}&publicKey=${encodeURIComponent(this.config.publicKey)}&authType=${this.config.authType}&projectId=${encodeURIComponent(
342
- this.config.projectId
343
- )}&url=${encodeURIComponent(window.location.href)}`
344
- );
345
- } else {
346
- const qr = await QRCode.toDataURL(JSON.stringify(payload), {
347
- type: "image/png",
348
- scale: 3,
349
- color: { light: "#ffffff", dark: "#424242ff" }
350
- });
351
- this.emit("qr", qr);
352
- }
370
+ /* -------------------- Flow Selection -------------------- */
371
+ shouldUseWebSocket() {
372
+ return this.config.forceQRCode || !/Android|iPhone|iPad/i.test(navigator.userAgent);
373
+ }
374
+ /* -------------------- WebSocket Flow (QR Code) -------------------- */
375
+ async startWebSocketFlow() {
376
+ const relay = await this.fetchRelayUrl();
377
+ this.transport = new Transport({
378
+ onOpen: () => {
379
+ this.transport.send({
380
+ type: "register",
381
+ sessionID: this.sessionId,
382
+ ...this.config
383
+ });
384
+ this.stateMachine.transition("awaiting-pair");
385
+ },
386
+ onMessage: (msg) => this.handleWebSocketMessage(msg),
387
+ onError: (err) => {
388
+ console.error("WebSocket error:", err);
389
+ this.fail(new Error("WebSocket connection failed"));
390
+ }
391
+ });
392
+ this.transport.connect(relay);
393
+ await this.emitQRCode();
353
394
  }
354
- /** Main WebSocket message router */
355
- handleMessage(msg) {
395
+ handleWebSocketMessage(msg) {
356
396
  switch (msg.type) {
357
397
  case "paired":
358
398
  this.stateMachine.transition("paired");
@@ -367,7 +407,7 @@ var PelicanAuthentication = class {
367
407
  this.handleAuthSuccess(msg);
368
408
  return;
369
409
  case "phone-terminated":
370
- this.fail(new Error("Authenticating device terminated the connection"));
410
+ this.fail(new Error("Authentication cancelled on device"));
371
411
  this.restartIfContinuous();
372
412
  return;
373
413
  case "confirmed":
@@ -376,9 +416,6 @@ var PelicanAuthentication = class {
376
416
  return;
377
417
  }
378
418
  }
379
- /**
380
- * Decrypts the identity payload received from the phone using the session key.
381
- */
382
419
  handleAuthSuccess(msg) {
383
420
  if (!this.sessionKey || !msg.cipher || !msg.nonce) {
384
421
  this.fail(new Error("Invalid authentication payload"));
@@ -407,40 +444,89 @@ var PelicanAuthentication = class {
407
444
  this.restartIfContinuous();
408
445
  }
409
446
  }
410
- /**
411
- * Logic to handle users returning to the browser tab after using the mobile app.
412
- * Checks the server for a completed session that might have finished while in background.
413
- */
414
- async getCachedEntry(cached) {
447
+ /* -------------------- Deep Link Flow (Mobile) -------------------- */
448
+ async startDeepLinkFlow() {
449
+ await this.fetchRelayUrl();
450
+ if (this.sessionKey) {
451
+ storeAuthSession(this.sessionId, this.sessionKey, 10 * 6e4);
452
+ }
453
+ await this.emitDeepLink();
454
+ this.stateMachine.transition("awaiting-pair");
455
+ }
456
+ clearBackupCheck() {
457
+ if (this.backupCheckTimeout) {
458
+ clearTimeout(this.backupCheckTimeout);
459
+ this.backupCheckTimeout = void 0;
460
+ }
461
+ }
462
+ async checkSession() {
463
+ const cached = getAuthSession();
464
+ if (!cached) return;
465
+ this.stateMachine.transition("awaiting-auth");
415
466
  try {
416
467
  const res = await fetch(
417
468
  `${BASEURL}/session?session_id=${cached.sessionId}`
418
469
  );
419
- if (!res.ok) throw new Error("Invalid session");
470
+ if (!res.ok) return;
420
471
  const data = await res.json();
421
472
  const decrypted = this.crypto.decryptSymmetric({
422
473
  encrypted: { cipher: data.cipher, nonce: data.nonce },
423
474
  keyString: cached.sessionKey
424
475
  });
425
476
  if (!decrypted) {
426
- this.fail(new Error("Invalid session data"));
427
- this.restartIfContinuous();
477
+ console.warn("Failed to decrypt session");
428
478
  return;
429
479
  }
430
480
  const result = JSON.parse(decrypted);
431
- this.emit("success", result);
481
+ this.clearBackupCheck();
432
482
  clearAuthSession();
433
- } catch {
434
- this.fail(new Error("Session recovery failed"));
435
- this.restartIfContinuous();
483
+ this.emit("success", result);
484
+ this.stateMachine.transition("authenticated");
485
+ if (this.config.continuousMode) {
486
+ setTimeout(() => {
487
+ this.stateMachine.transition("confirmed");
488
+ this.start();
489
+ }, 1500);
490
+ } else {
491
+ this.stateMachine.transition("confirmed");
492
+ }
493
+ } catch (err) {
494
+ console.debug("Session check failed:", err);
436
495
  }
437
496
  }
497
+ /* -------------------- Entry Point Generation -------------------- */
498
+ async emitQRCode() {
499
+ const payload = {
500
+ sessionID: this.sessionId,
501
+ sessionKey: this.sessionKey,
502
+ publicKey: this.config.publicKey,
503
+ authType: this.config.authType,
504
+ projectId: this.config.projectId,
505
+ url: window.location.href
506
+ };
507
+ const qr = await QRCode.toDataURL(JSON.stringify(payload), {
508
+ type: "image/png",
509
+ scale: 3,
510
+ color: { light: "#ffffff", dark: "#424242ff" }
511
+ });
512
+ this.emit("qr", qr);
513
+ }
514
+ async emitDeepLink() {
515
+ const deeplink = `pelicanvault://auth/deep-link?sessionID=${encodeURIComponent(
516
+ this.sessionId
517
+ )}&sessionKey=${encodeURIComponent(
518
+ this.sessionKey
519
+ )}&publicKey=${encodeURIComponent(this.config.publicKey)}&authType=${this.config.authType}&projectId=${encodeURIComponent(
520
+ this.config.projectId
521
+ )}&url=${encodeURIComponent(window.location.href)}`;
522
+ this.emit("deeplink", deeplink);
523
+ }
524
+ /* -------------------- Visibility Recovery -------------------- */
438
525
  attachVisibilityRecovery() {
439
526
  this.visibilityHandler = async () => {
440
527
  if (document.visibilityState !== "visible") return;
441
- const cached = getAuthSession();
442
- if (!cached) return;
443
- await this.getCachedEntry(cached);
528
+ if (this.useWebSocket) return;
529
+ await this.checkSession();
444
530
  };
445
531
  document.addEventListener("visibilitychange", this.visibilityHandler);
446
532
  }
@@ -450,18 +536,34 @@ var PelicanAuthentication = class {
450
536
  this.visibilityHandler = void 0;
451
537
  }
452
538
  }
453
- /** Cleans up the current session state */
539
+ /* -------------------- Helpers -------------------- */
540
+ async fetchRelayUrl() {
541
+ const { publicKey, projectId, authType } = this.config;
542
+ const res = await fetch(
543
+ `${BASEURL}/relay?public_key=${publicKey}&auth_type=${authType}&project_id=${projectId}`
544
+ );
545
+ if (!res.ok) {
546
+ const error = await res.text();
547
+ throw new Error(error);
548
+ }
549
+ const json = await res.json();
550
+ return json.relay_url;
551
+ }
454
552
  terminate(success) {
455
- if (!success) {
456
- this.transport?.send({
457
- type: "client-terminated",
458
- sessionID: this.sessionId,
459
- projectId: this.config.projectId,
460
- publicKey: this.config.publicKey,
461
- authType: this.config.authType
462
- });
553
+ this.clearBackupCheck();
554
+ if (this.transport) {
555
+ if (!success) {
556
+ this.transport.send({
557
+ type: "client-terminated",
558
+ sessionID: this.sessionId,
559
+ projectId: this.config.projectId,
560
+ publicKey: this.config.publicKey,
561
+ authType: this.config.authType
562
+ });
563
+ }
564
+ this.transport.close();
565
+ this.transport = void 0;
463
566
  }
464
- this.transport?.close();
465
567
  clearAuthSession();
466
568
  this.resetSession();
467
569
  if (!this.config.continuousMode) {
@@ -470,9 +572,11 @@ var PelicanAuthentication = class {
470
572
  this.stateMachine.transition(success ? "confirmed" : "idle");
471
573
  }
472
574
  restartIfContinuous() {
473
- this.stateMachine.transition("idle");
474
- this.transport?.close();
475
575
  if (!this.config.continuousMode) return;
576
+ this.clearBackupCheck();
577
+ this.transport?.close();
578
+ this.transport = void 0;
579
+ this.stateMachine.transition("idle");
476
580
  setTimeout(() => {
477
581
  this.start();
478
582
  }, 150);
@@ -481,12 +585,6 @@ var PelicanAuthentication = class {
481
585
  this.sessionId = "";
482
586
  this.sessionKey = null;
483
587
  }
484
- /** Completely destroys the instance and removes all listeners */
485
- destroy() {
486
- this.detachVisibilityRecovery();
487
- this.transport?.close();
488
- this.listeners = {};
489
- }
490
588
  emit(event, payload) {
491
589
  this.listeners[event]?.forEach((cb) => cb(payload));
492
590
  }