@pelican-identity/vanilla 1.0.37 → 1.0.38

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.min.js CHANGED
@@ -5,7 +5,7 @@ Make sure your charset is UTF-8`);i=(i>>>8&255)*192+(i&255),n.put(i,13);}};Bn.ex
5
5
  The chosen QR Code version cannot contain this amount of data.
6
6
  Minimum version required to store current data is: `+u+`.
7
7
  `);let g=to(e,i,c),y=qe.getSymbolSize(e),E=new Yi(y);return Ji(E,e),Zi(E),Qi(E,e),br(E,i,0),e>=7&&Gi(E,e),Xi(E,g),isNaN(a)&&(a=mr.getBestMask(E,br.bind(null,E,i))),mr.applyMask(a,E),br(E,i,a),{modules:E,version:e,errorCorrectionLevel:i,maskPattern:a,segments:c}}Dn.create=function(e,i){if(typeof e>"u"||e==="")throw new Error("No input text");let a=gr.M,c,u;return typeof i<"u"&&(a=gr.from(i.errorCorrectionLevel,gr.M),c=Oe.from(i.version),u=mr.from(i.maskPattern),i.toSJISFunc&&qe.setToSJISFunction(i.toSJISFunc)),ro(e,c,a,u)};});var vr=et(Vt=>{function On(n){if(typeof n=="number"&&(n=n.toString()),typeof n!="string")throw new Error("Color should be defined as hex string");let e=n.slice().replace("#","").split("");if(e.length<3||e.length===5||e.length>8)throw new Error("Invalid hex color: "+n);(e.length===3||e.length===4)&&(e=Array.prototype.concat.apply([],e.map(function(a){return [a,a]}))),e.length===6&&e.push("F","F");let i=parseInt(e.join(""),16);return {r:i>>24&255,g:i>>16&255,b:i>>8&255,a:i&255,hex:"#"+e.slice(0,6).join("")}}Vt.getOptions=function(e){e||(e={}),e.color||(e.color={});let i=typeof e.margin>"u"||e.margin===null||e.margin<0?4:e.margin,a=e.width&&e.width>=21?e.width:void 0,c=e.scale||4;return {width:a,scale:a?4:c,margin:i,color:{dark:On(e.color.dark||"#000000ff"),light:On(e.color.light||"#ffffffff")},type:e.type,rendererOpts:e.rendererOpts||{}}};Vt.getScale=function(e,i){return i.width&&i.width>=e+i.margin*2?i.width/(e+i.margin*2):i.scale};Vt.getImageWidth=function(e,i){let a=Vt.getScale(e,i);return Math.floor((e+i.margin*2)*a)};Vt.qrToImageData=function(e,i,a){let c=i.modules.size,u=i.modules.data,g=Vt.getScale(c,a),y=Math.floor((c+a.margin*2)*g),E=a.margin*g,z=[a.color.light,a.color.dark];for(let q=0;q<y;q++)for(let st=0;st<y;st++){let nt=(q*y+st)*4,bt=a.color.light;if(q>=E&&st>=E&&q<y-E&&st<y-E){let mt=Math.floor((q-E)/g),vt=Math.floor((st-E)/g);bt=z[u[mt*c+vt]?1:0];}e[nt++]=bt.r,e[nt++]=bt.g,e[nt++]=bt.b,e[nt]=bt.a;}};});var qn=et(Ke=>{var Er=vr();function no(n,e,i){n.clearRect(0,0,e.width,e.height),e.style||(e.style={}),e.height=i,e.width=i,e.style.height=i+"px",e.style.width=i+"px";}function io(){try{return document.createElement("canvas")}catch{throw new Error("You need to specify a canvas element")}}Ke.render=function(e,i,a){let c=a,u=i;typeof c>"u"&&(!i||!i.getContext)&&(c=i,i=void 0),i||(u=io()),c=Er.getOptions(c);let g=Er.getImageWidth(e.modules.size,c),y=u.getContext("2d"),E=y.createImageData(g,g);return Er.qrToImageData(E.data,e,c),no(y,u,g),y.putImageData(E,0,0),u};Ke.renderToDataURL=function(e,i,a){let c=a;typeof c>"u"&&(!i||!i.getContext)&&(c=i,i=void 0),c||(c={});let u=Ke.render(e,i,c),g=c.type||"image/png",y=c.rendererOpts||{};return u.toDataURL(g,y.quality)};});var Fn=et(Yn=>{var oo=vr();function Kn(n,e){let i=n.a/255,a=e+'="'+n.hex+'"';return i<1?a+" "+e+'-opacity="'+i.toFixed(2).slice(1)+'"':a}function Cr(n,e,i){let a=n+e;return typeof i<"u"&&(a+=" "+i),a}function so(n,e,i){let a="",c=0,u=false,g=0;for(let y=0;y<n.length;y++){let E=Math.floor(y%e),z=Math.floor(y/e);!E&&!u&&(u=true),n[y]?(g++,y>0&&E>0&&n[y-1]||(a+=u?Cr("M",E+i,.5+z+i):Cr("m",c,0),c=0,u=false),E+1<e&&n[y+1]||(a+=Cr("h",g),g=0)):c++;}return a}Yn.render=function(e,i,a){let c=oo.getOptions(i),u=e.modules.size,g=e.modules.data,y=u+c.margin*2,E=c.color.light.a?"<path "+Kn(c.color.light,"fill")+' d="M0 0h'+y+"v"+y+'H0z"/>':"",z="<path "+Kn(c.color.dark,"stroke")+' d="'+so(g,u,c.margin)+'"/>',q='viewBox="0 0 '+y+" "+y+'"',nt='<svg xmlns="http://www.w3.org/2000/svg" '+(c.width?'width="'+c.width+'" height="'+c.width+'" ':"")+q+' shape-rendering="crispEdges">'+E+z+`</svg>
8
- `;return typeof a=="function"&&a(null,nt),nt};});var Hn=et(ve=>{var fo=Vr(),Ar=zn(),$n=qn(),ao=Fn();function Sr(n,e,i,a,c){let u=[].slice.call(arguments,1),g=u.length,y=typeof u[g-1]=="function";if(!y&&!fo())throw new Error("Callback required as last argument");if(y){if(g<2)throw new Error("Too few arguments provided");g===2?(c=i,i=e,e=a=void 0):g===3&&(e.getContext&&typeof c>"u"?(c=a,a=void 0):(c=a,a=i,i=e,e=void 0));}else {if(g<1)throw new Error("Too few arguments provided");return g===1?(i=e,e=a=void 0):g===2&&!e.getContext&&(a=i,i=e,e=void 0),new Promise(function(E,z){try{let q=Ar.create(i,a);E(n(q,e,a));}catch(q){z(q);}})}try{let E=Ar.create(i,a);c(null,n(E,e,a));}catch(E){c(E);}}ve.create=Ar.create;ve.toCanvas=Sr.bind(null,$n.render);ve.toDataURL=Sr.bind(null,$n.renderToDataURL);ve.toString=Sr.bind(null,function(n,e,i){return ao.render(n,i)});});var Xn=et(Lt=>{var co=Yr(),Wt=$r(),lo=Hn();function Vn(n){return n&&n.__esModule?n:{default:n}}var Ye=Vn(co),uo=Vn(lo),Wn=class{generateSymmetricKey(){let n=Ye.default.randomBytes(32);return Wt.encodeBase64(n)}encryptSymmetric({plaintext:n,keyString:e}){let i=Wt.decodeBase64(e),a=Ye.default.randomBytes(24),c=new TextEncoder().encode(n),u=Ye.default.secretbox(c,a,i);return {cipher:Wt.encodeBase64(u),nonce:Wt.encodeBase64(a)}}decryptSymmetric({encrypted:n,keyString:e}){try{let i=Wt.decodeBase64(e),a=Wt.decodeBase64(n.cipher),c=Wt.decodeBase64(n.nonce),u=Ye.default.secretbox.open(a,c,i);if(!u)throw new Error("Decryption failed - invalid key or corrupted data");return new TextDecoder().decode(u)}catch(i){return console.error("Decryption failed",i),null}}},ho=Wn,xo=class{constructor(){this.prefix="pelican_auth_",this.defaultTTL=300*1e3,this.memoryCache=new Map;}set(n,e,i={}){let{ttlMs:a=this.defaultTTL,useSessionStorage:c=true}=i,u=Date.now()+a,g={value:e,expiresAt:u};if(c)try{sessionStorage.setItem(`${this.prefix}${n}`,JSON.stringify(g));}catch(y){console.warn("SessionStorage unavailable, using memory:",y),this.setMemory(n,g);}else this.setMemory(n,g);}get(n){try{let e=sessionStorage.getItem(`${this.prefix}${n}`);if(e){let i=JSON.parse(e);return Date.now()>i.expiresAt?(this.remove(n),null):i.value}}catch{}return this.getMemory(n)}remove(n){try{sessionStorage.removeItem(`${this.prefix}${n}`);}catch{}this.memoryCache.delete(n);}clear(){try{Object.keys(sessionStorage).forEach(n=>{n.startsWith(this.prefix)&&sessionStorage.removeItem(n);});}catch{}this.memoryCache.clear();}setMemory(n,e){this.memoryCache.set(n,e);let i=e.expiresAt-Date.now();setTimeout(()=>{this.memoryCache.delete(n);},i);}getMemory(n){let e=this.memoryCache.get(n);return e?Date.now()>e.expiresAt?(this.memoryCache.delete(n),null):e.value:null}},$e=new xo,Jn=(n,e,i)=>{$e.set("session",{sessionId:n,sessionKey:e},{ttlMs:i});},Zn=()=>$e.get("session"),Fe=()=>{$e.remove("session");},po=()=>{$e.clear();},Qn=class{constructor(){this.state="idle",this.listeners=new Set;}get current(){return this.state}transition(n){this.state=n,this.listeners.forEach(e=>e(n));}subscribe(n){return this.listeners.add(n),()=>this.listeners.delete(n)}},Gn=class{constructor(n){this.reconnectAttempts=0,this.maxReconnectAttempts=3,this.isExplicitlyClosed=false,this.isReconnecting=false,this.handlers=n;}connect(n){this.url=n,this.isExplicitlyClosed=false,this.socket&&(this.socket.onclose=null,this.socket.onerror=null,this.socket.onmessage=null,this.socket.onopen=null,(this.socket.readyState===WebSocket.OPEN||this.socket.readyState===WebSocket.CONNECTING)&&this.socket.close()),this.socket=new WebSocket(n),this.socket.onopen=()=>{this.reconnectAttempts=0,this.isReconnecting=false,this.handlers.onOpen?.();},this.socket.onmessage=e=>{try{let i=JSON.parse(e.data);this.handlers.onMessage?.(i);}catch(i){console.error("Failed to parse WebSocket message",i);}},this.socket.onerror=e=>{!this.isReconnecting&&!this.isExplicitlyClosed&&this.handlers.onError?.(e);},this.socket.onclose=e=>{this.reconnectTimeout&&(clearTimeout(this.reconnectTimeout),this.reconnectTimeout=void 0),this.isReconnecting||this.handlers.onClose?.(e),!this.isExplicitlyClosed&&!this.isReconnecting&&this.reconnectAttempts<this.maxReconnectAttempts&&this.attemptReconnect();};}attemptReconnect(){if(this.reconnectAttempts>=this.maxReconnectAttempts){console.warn("Max WebSocket reconnect attempts reached");return}this.isReconnecting=true,this.reconnectAttempts++;let n=Math.min(Math.pow(2,this.reconnectAttempts-1)*500,2e3);console.log(`Reconnecting WebSocket (attempt ${this.reconnectAttempts}/${this.maxReconnectAttempts}) in ${n}ms...`),this.reconnectTimeout=window.setTimeout(()=>{this.url&&!this.isExplicitlyClosed&&this.connect(this.url);},n);}send(n){if(this.socket?.readyState===WebSocket.OPEN)try{this.socket.send(JSON.stringify(n));}catch(e){console.error("Failed to send WebSocket message:",e);}else console.warn("WebSocket not open, message not sent:",this.socket?.readyState);}close(){this.isExplicitlyClosed=true,this.isReconnecting=false,this.reconnectTimeout&&(clearTimeout(this.reconnectTimeout),this.reconnectTimeout=void 0),this.socket&&(this.socket.onclose=null,this.socket.onerror=null,this.socket.onmessage=null,this.socket.onopen=null,(this.socket.readyState===WebSocket.OPEN||this.socket.readyState===WebSocket.CONNECTING)&&this.socket.close(),this.socket=void 0);}get readyState(){return this.socket?.readyState}get isOpen(){return this.socket?.readyState===WebSocket.OPEN}},_r="https://identityapi.pelicanidentity.com",go="https://apps.apple.com/us/app/pelican-vault/id6755097751",yo="https://play.google.com/store/apps/details?id=com.HeraculesDesignTechLtd.pelican",bo="https://pelicanidentity.com/pelican-vault",mo=class{constructor(n){if(this.crypto=new ho,this.stateMachine=new Qn,this.sessionId="",this.sessionKey=null,this.useWebSocket=true,this.deeplinkUrl=null,this.listeners={},!n.publicKey)throw new Error("Missing publicKey");if(!n.projectId)throw new Error("Missing projectId");if(!n.authType)throw new Error("Missing authType");this.config={continuousMode:false,forceQRCode:false,...n},this.stateMachine.subscribe(e=>this.emit("state",e));}on(n,e){var i;return (i=this.listeners)[n]??(i[n]=new Set),this.listeners[n].add(e),()=>this.listeners[n].delete(e)}async start(){if(this.config.authType!=="id-verification"&&this.config.authType!=="signup"&&this.config.authType!=="login"){this.fail(new Error("Invalid authType"));return}if(!this.config.projectId){this.fail(new Error("Missing projectId"));return}if(!this.config.publicKey){this.fail(new Error("Missing publicKey"));return}if(this.stateMachine.current==="idle"){this.resetSession(),Fe(),this.stateMachine.transition("initializing");try{this.sessionKey=this.crypto.generateSymmetricKey(),this.sessionId=crypto.randomUUID()+crypto.randomUUID(),this.useWebSocket=this.shouldUseWebSocket(),this.useWebSocket?await this.startWebSocketFlow():await this.startDeepLinkFlow();}catch(n){this.fail(n instanceof Error?n:new Error("Start failed"));}}}stop(){this.terminate(false);}openWebAuth(){if(!this.sessionKey||!this.sessionId){this.fail(new Error("No active session. Call start() before openWebAuth()."));return}let n=window.location.origin,i=`https://vault.pelicanidentity.com/auth?${new URLSearchParams({projectId:this.config.projectId,publicKey:this.config.publicKey,authType:this.config.authType,sessionId:this.sessionId,sessionKey:this.sessionKey,origin:n}).toString()}`,a=window.open(i,"pelican-auth","width=480,height=640,left=400,top=100,resizable=no,scrollbars=no")??window.open(i,"_blank");if(!a){this.fail(new Error("Unable to open authentication window. Please allow popups for this site and try again."));return}this.detachVisibilityRecovery(),this.transport?.close(),this.transport=void 0,a.focus(),this.stateMachine.transition("awaiting-pair");let c=()=>{window.removeEventListener("message",u),clearInterval(g);},u=y=>{if(y.origin!=="https://vault.pelicanidentity.com"||y.source!==a)return;let{type:E,payload:z}=y.data??{};if(E==="pelican-auth-success"){if(console.log("Web auth success"),c(),!z?.cipher||!z?.nonce){this.fail(new Error("Invalid web auth payload")),this.restartIfContinuous();return}try{let q=this.crypto.decryptSymmetric({encrypted:{cipher:z.cipher,nonce:z.nonce},keyString:this.sessionKey});if(!q){this.fail(new Error("Failed to decrypt web auth response")),this.restartIfContinuous();return}let st=JSON.parse(q);this.emit("success",st),this.stateMachine.transition("authenticated"),this.restartIfContinuous();}catch{this.fail(new Error("Failed to decrypt web auth response")),this.restartIfContinuous();}}E==="pelican-auth-cancelled"&&(c(),this.fail(new Error("Authentication cancelled")),this.restartIfContinuous()),E==="pelican-auth-error"&&(c(),this.fail(new Error(z?.message??"Web auth failed")),this.restartIfContinuous());};window.addEventListener("message",u);let g=setInterval(()=>{a.closed&&(c(),["authenticated","confirmed","error"].includes(this.stateMachine.current)||(this.fail(new Error("Authentication window closed")),this.restartIfContinuous()));},500);}destroy(){this.detachVisibilityRecovery(),this.clearBackupCheck(),this.transport?.close(),this.transport=void 0,this.listeners={};}useQrInstead(){this.useWebSocket=true,this.emit("deeplink",""),this.stateMachine.transition("initializing"),this.startWebSocketFlow();}useDeepLinkInstead(){this.useWebSocket=false,this.stateMachine.transition("initializing"),this.startDeepLinkFlow();}shouldUseWebSocket(){let n=navigator.userAgent,e=/(iPad|Android(?!.*Mobile))/i.test(n),a=/Android|webOS|iPhone|iPod|BlackBerry|IEMobile|Opera Mini/i.test(n)&&!e;return this.config.forceQRCode||!a}async startWebSocketFlow(){let{relayUrl:n,deeplinkUrl:e}=await this.fetchRelayUrl();this.transport=new Gn({onOpen:()=>{this.transport.send({type:"register",sessionID:this.sessionId,...this.config}),this.stateMachine.transition("awaiting-pair");},onMessage:i=>this.handleWebSocketMessage(i),onError:i=>{console.error("WebSocket error:",i),this.fail(new Error("WebSocket connection failed"));}}),this.transport.connect(n),await this.emitQRCode(e);}handleWebSocketMessage(n){switch(n.type){case "paired":this.stateMachine.transition("paired"),this.transport.send({type:"authenticate",sessionID:this.sessionId,...this.config,url:window.location.href});return;case "phone-auth-success":this.handleAuthSuccess(n);return;case "phone-terminated":this.fail(new Error("Authentication cancelled on device")),this.restartIfContinuous();return;case "confirmed":this.terminate(true),this.restartIfContinuous();return}}handleAuthSuccess(n){if(!this.sessionKey||!n.cipher||!n.nonce){this.fail(new Error("Invalid authentication payload")),this.restartIfContinuous();return}try{let e=this.crypto.decryptSymmetric({encrypted:{cipher:n.cipher,nonce:n.nonce},keyString:this.sessionKey});if(!e){this.fail(new Error("Invalid authentication data")),this.restartIfContinuous();return}let i=JSON.parse(e);this.emit("success",i),this.stateMachine.transition("authenticated"),this.transport?.send({type:"confirm",sessionID:this.sessionId});}catch{this.fail(new Error("Failed to decrypt authentication data")),this.restartIfContinuous();}}async startDeepLinkFlow(){let{deeplinkUrl:n}=await this.fetchRelayUrl();this.sessionKey&&Jn(this.sessionId,this.sessionKey,10*6e4),await this.emitDeepLink(n),this.deeplinkUrl=n,this.stateMachine.transition("awaiting-pair");}openDeepLink(){if(!this.deeplinkUrl){this.fail(new Error("Deep link not found"));return}let n=navigator.userAgent,e=bo;/iPad|iPhone|iPod/.test(n)?e=go:/android/i.test(n)&&(e=yo);let i=Date.now();window.location.href=this.deeplinkUrl,setTimeout(()=>{Date.now()-i<3500&&(window.location.href=e);},3e3);}clearBackupCheck(){this.backupCheckTimeout&&(clearTimeout(this.backupCheckTimeout),this.backupCheckTimeout=void 0);}async checkSession(){let n=Zn();if(!n){this.fail(new Error("Authentication session not found")),this.restartIfContinuous();return}this.stateMachine.transition("awaiting-auth");try{let e=await fetch(`${_r}/session?session_id=${n.sessionId}`);if(!e.ok){this.fail(new Error("Session not found")),this.restartIfContinuous();return}let i=await e.json(),a=this.crypto.decryptSymmetric({encrypted:{cipher:i.cipher,nonce:i.nonce},keyString:n.sessionKey});if(!a){console.warn("Failed to decrypt session"),this.fail(new Error("Failed to decrypt session")),this.restartIfContinuous();return}let c=JSON.parse(a);this.clearBackupCheck(),Fe(),this.emit("success",c),this.stateMachine.transition("authenticated"),this.config.continuousMode?setTimeout(()=>{this.stateMachine.transition("idle"),this.start();},1500):this.stateMachine.transition("idle");}catch(e){console.debug("Session check failed:",e),this.fail(new Error("Session check failed")),this.restartIfContinuous();return}}async emitQRCode(n){let e=`${n}?sessionID=${encodeURIComponent(this.sessionId)}&sessionKey=${encodeURIComponent(this.sessionKey)}&publicKey=${encodeURIComponent(this.config.publicKey)}&authType=${this.config.authType}&projectId=${encodeURIComponent(this.config.projectId)}`,i=await uo.default.toDataURL(e,{type:"image/png",scale:3,color:{light:"#ffffff",dark:"#424242ff"}});this.emit("qr",i);}async emitDeepLink(n){let e=`${n}?sessionID=${encodeURIComponent(this.sessionId)}&sessionKey=${encodeURIComponent(this.sessionKey)}&publicKey=${encodeURIComponent(this.config.publicKey)}&authType=${this.config.authType}&projectId=${encodeURIComponent(this.config.projectId)}`;this.emit("deeplink",e);}attachVisibilityRecovery(){let n=false;this.visibilityHandler=async()=>{document.visibilityState==="visible"&&(this.useWebSocket||n||(n=true,await this.checkSession()));},document.addEventListener("visibilitychange",this.visibilityHandler);}detachVisibilityRecovery(){this.visibilityHandler&&(document.removeEventListener("visibilitychange",this.visibilityHandler),this.visibilityHandler=void 0);}async fetchRelayUrl(){let{publicKey:n,projectId:e,authType:i}=this.config,a=await fetch(`${_r}/relay?public_key=${n}&auth_type=${i}&project_id=${e}`);if(!a.ok){let u=await a.text();throw new Error(u)}let c=await a.json();return {deeplinkUrl:c.deeplink_url,relayUrl:c.relay_url}}terminate(n){this.clearBackupCheck(),this.transport&&(n||this.transport.send({type:"client-terminated",sessionID:this.sessionId,projectId:this.config.projectId,publicKey:this.config.publicKey,authType:this.config.authType}),this.transport.close(),this.transport=void 0),Fe(),this.resetSession(),this.config.continuousMode||this.detachVisibilityRecovery(),this.stateMachine.transition(n?"confirmed":"idle");}restartIfContinuous(){this.config.continuousMode?(this.stateMachine.transition("idle"),this.clearBackupCheck(),this.transport?.close(),this.transport=void 0,setTimeout(()=>{this.start();},150)):this.stateMachine.transition("idle");}resetSession(){this.sessionId="",this.sessionKey=null;}emit(n,e){this.listeners[n]?.forEach(i=>i(e));}fail(n){this.emit("error",n),this.stateMachine.transition("error");}};Lt.BASEURL=_r;Lt.CryptoService=Wn;Lt.PelicanAuthentication=mo;Lt.StateMachine=Qn;Lt.Transport=Gn;Lt.clearAllAuthData=po;Lt.clearAuthSession=Fe;Lt.getAuthSession=Zn;Lt.storeAuthSession=Jn;});var ti=pi(Xn());function wo(){if(document.getElementById("pelican-auth-styles"))return;let n=document.createElement("style");n.id="pelican-auth-styles",n.textContent=`
8
+ `;return typeof a=="function"&&a(null,nt),nt};});var Hn=et(ve=>{var fo=Vr(),Ar=zn(),$n=qn(),ao=Fn();function Sr(n,e,i,a,c){let u=[].slice.call(arguments,1),g=u.length,y=typeof u[g-1]=="function";if(!y&&!fo())throw new Error("Callback required as last argument");if(y){if(g<2)throw new Error("Too few arguments provided");g===2?(c=i,i=e,e=a=void 0):g===3&&(e.getContext&&typeof c>"u"?(c=a,a=void 0):(c=a,a=i,i=e,e=void 0));}else {if(g<1)throw new Error("Too few arguments provided");return g===1?(i=e,e=a=void 0):g===2&&!e.getContext&&(a=i,i=e,e=void 0),new Promise(function(E,z){try{let q=Ar.create(i,a);E(n(q,e,a));}catch(q){z(q);}})}try{let E=Ar.create(i,a);c(null,n(E,e,a));}catch(E){c(E);}}ve.create=Ar.create;ve.toCanvas=Sr.bind(null,$n.render);ve.toDataURL=Sr.bind(null,$n.renderToDataURL);ve.toString=Sr.bind(null,function(n,e,i){return ao.render(n,i)});});var Xn=et(Lt=>{var co=Yr(),Wt=$r(),lo=Hn();function Vn(n){return n&&n.__esModule?n:{default:n}}var Ye=Vn(co),uo=Vn(lo),Wn=class{generateSymmetricKey(){let n=Ye.default.randomBytes(32);return Wt.encodeBase64(n)}encryptSymmetric({plaintext:n,keyString:e}){let i=Wt.decodeBase64(e),a=Ye.default.randomBytes(24),c=new TextEncoder().encode(n),u=Ye.default.secretbox(c,a,i);return {cipher:Wt.encodeBase64(u),nonce:Wt.encodeBase64(a)}}decryptSymmetric({encrypted:n,keyString:e}){try{let i=Wt.decodeBase64(e),a=Wt.decodeBase64(n.cipher),c=Wt.decodeBase64(n.nonce),u=Ye.default.secretbox.open(a,c,i);if(!u)throw new Error("Decryption failed - invalid key or corrupted data");return new TextDecoder().decode(u)}catch(i){return console.error("Decryption failed",i),null}}},ho=Wn,xo=class{constructor(){this.prefix="pelican_auth_",this.defaultTTL=300*1e3,this.memoryCache=new Map;}set(n,e,i={}){let{ttlMs:a=this.defaultTTL,useSessionStorage:c=true}=i,u=Date.now()+a,g={value:e,expiresAt:u};if(c)try{sessionStorage.setItem(`${this.prefix}${n}`,JSON.stringify(g));}catch(y){console.warn("SessionStorage unavailable, using memory:",y),this.setMemory(n,g);}else this.setMemory(n,g);}get(n){try{let e=sessionStorage.getItem(`${this.prefix}${n}`);if(e){let i=JSON.parse(e);return Date.now()>i.expiresAt?(this.remove(n),null):i.value}}catch{}return this.getMemory(n)}remove(n){try{sessionStorage.removeItem(`${this.prefix}${n}`);}catch{}this.memoryCache.delete(n);}clear(){try{Object.keys(sessionStorage).forEach(n=>{n.startsWith(this.prefix)&&sessionStorage.removeItem(n);});}catch{}this.memoryCache.clear();}setMemory(n,e){this.memoryCache.set(n,e);let i=e.expiresAt-Date.now();setTimeout(()=>{this.memoryCache.delete(n);},i);}getMemory(n){let e=this.memoryCache.get(n);return e?Date.now()>e.expiresAt?(this.memoryCache.delete(n),null):e.value:null}},$e=new xo,Jn=(n,e,i)=>{$e.set("session",{sessionId:n,sessionKey:e},{ttlMs:i});},Zn=()=>$e.get("session"),Fe=()=>{$e.remove("session");},po=()=>{$e.clear();},Qn=class{constructor(){this.state="idle",this.listeners=new Set;}get current(){return this.state}transition(n){this.state=n,this.listeners.forEach(e=>e(n));}subscribe(n){return this.listeners.add(n),()=>this.listeners.delete(n)}},Gn=class{constructor(n){this.reconnectAttempts=0,this.maxReconnectAttempts=3,this.isExplicitlyClosed=false,this.isReconnecting=false,this.handlers=n;}connect(n){this.url=n,this.isExplicitlyClosed=false,this.socket&&(this.socket.onclose=null,this.socket.onerror=null,this.socket.onmessage=null,this.socket.onopen=null,(this.socket.readyState===WebSocket.OPEN||this.socket.readyState===WebSocket.CONNECTING)&&this.socket.close()),this.socket=new WebSocket(n),this.socket.onopen=()=>{this.reconnectAttempts=0,this.isReconnecting=false,this.handlers.onOpen?.();},this.socket.onmessage=e=>{try{let i=JSON.parse(e.data);this.handlers.onMessage?.(i);}catch(i){console.error("Failed to parse WebSocket message",i);}},this.socket.onerror=e=>{!this.isReconnecting&&!this.isExplicitlyClosed&&this.handlers.onError?.(e);},this.socket.onclose=e=>{this.reconnectTimeout&&(clearTimeout(this.reconnectTimeout),this.reconnectTimeout=void 0),this.isReconnecting||this.handlers.onClose?.(e),!this.isExplicitlyClosed&&!this.isReconnecting&&this.reconnectAttempts<this.maxReconnectAttempts&&this.attemptReconnect();};}attemptReconnect(){if(this.reconnectAttempts>=this.maxReconnectAttempts){console.warn("Max WebSocket reconnect attempts reached");return}this.isReconnecting=true,this.reconnectAttempts++;let n=Math.min(Math.pow(2,this.reconnectAttempts-1)*500,2e3);console.log(`Reconnecting WebSocket (attempt ${this.reconnectAttempts}/${this.maxReconnectAttempts}) in ${n}ms...`),this.reconnectTimeout=window.setTimeout(()=>{this.url&&!this.isExplicitlyClosed&&this.connect(this.url);},n);}send(n){if(this.socket?.readyState===WebSocket.OPEN)try{this.socket.send(JSON.stringify(n));}catch(e){console.error("Failed to send WebSocket message:",e);}else console.warn("WebSocket not open, message not sent:",this.socket?.readyState);}close(){this.isExplicitlyClosed=true,this.isReconnecting=false,this.reconnectTimeout&&(clearTimeout(this.reconnectTimeout),this.reconnectTimeout=void 0),this.socket&&(this.socket.onclose=null,this.socket.onerror=null,this.socket.onmessage=null,this.socket.onopen=null,(this.socket.readyState===WebSocket.OPEN||this.socket.readyState===WebSocket.CONNECTING)&&this.socket.close(),this.socket=void 0);}get readyState(){return this.socket?.readyState}get isOpen(){return this.socket?.readyState===WebSocket.OPEN}},_r="https://identityapi.pelicanidentity.com",go="https://apps.apple.com/us/app/pelican-vault/id6755097751",yo="https://play.google.com/store/apps/details?id=com.HeraculesDesignTechLtd.pelican",bo="https://pelicanidentity.com/pelican-vault",mo=class{constructor(n){if(this.crypto=new ho,this.stateMachine=new Qn,this.sessionId="",this.sessionKey=null,this.useWebSocket=true,this.deeplinkUrl=null,this.listeners={},!n.publicKey)throw new Error("Missing publicKey");if(!n.projectId)throw new Error("Missing projectId");if(!n.authType)throw new Error("Missing authType");this.config={continuousMode:false,forceQRCode:false,...n},this.stateMachine.subscribe(e=>this.emit("state",e));}on(n,e){var i;return (i=this.listeners)[n]??(i[n]=new Set),this.listeners[n].add(e),()=>this.listeners[n].delete(e)}async start(){if(this.config.authType!=="id-verification"&&this.config.authType!=="signup"&&this.config.authType!=="login"){this.fail(new Error("Invalid authType"));return}if(!this.config.projectId){this.fail(new Error("Missing projectId"));return}if(!this.config.publicKey){this.fail(new Error("Missing publicKey"));return}if(this.stateMachine.current==="idle"){this.resetSession(),Fe(),this.stateMachine.transition("initializing");try{this.sessionKey=this.crypto.generateSymmetricKey(),this.sessionId=crypto.randomUUID()+crypto.randomUUID(),this.useWebSocket=this.shouldUseWebSocket(),this.useWebSocket?await this.startWebSocketFlow():await this.startDeepLinkFlow();}catch(n){this.fail(n instanceof Error?n:new Error("Start failed"));}}}stop(){this.terminate(false);}openWebAuth(){if(!this.sessionKey||!this.sessionId){this.fail(new Error("No active session. Call start() before openWebAuth()."));return}let n=window.location.origin,i=`https://vault.pelicanidentity.com/auth?${new URLSearchParams({projectId:this.config.projectId,publicKey:this.config.publicKey,authType:this.config.authType,sessionId:this.sessionId,sessionKey:this.sessionKey,origin:n}).toString()}`,a=window.open(i,"pelican-auth","width=480,height=640,left=400,top=100,resizable=no,scrollbars=no")??window.open(i,"_blank");if(!a){this.fail(new Error("Unable to open authentication window. Please allow popups for this site and try again."));return}this.detachVisibilityRecovery(),this.transport?.close(),this.transport=void 0,a.focus(),this.stateMachine.transition("awaiting-pair");let c=()=>{window.removeEventListener("message",u),clearInterval(g);},u=y=>{if(y.origin!=="https://vault.pelicanidentity.com"||y.source!==a)return;let{type:E,payload:z}=y.data??{};if(E==="pelican-auth-success"){if(console.log("Web auth success"),c(),!z?.cipher||!z?.nonce){this.fail(new Error("Invalid web auth payload")),this.restartIfContinuous();return}try{let q=this.crypto.decryptSymmetric({encrypted:{cipher:z.cipher,nonce:z.nonce},keyString:this.sessionKey});if(!q){this.fail(new Error("Failed to decrypt web auth response")),this.restartIfContinuous();return}let st=JSON.parse(q);this.emit("success",st),this.stateMachine.transition("authenticated"),this.restartIfContinuous();}catch{this.fail(new Error("Failed to decrypt web auth response")),this.restartIfContinuous();}}E==="pelican-auth-cancelled"&&(c(),this.fail(new Error("Authentication cancelled")),this.restartIfContinuous()),E==="pelican-auth-error"&&(c(),this.fail(new Error(z?.message??"Web auth failed")),this.restartIfContinuous());};window.addEventListener("message",u);let g=setInterval(()=>{a.closed&&(c(),["authenticated","confirmed","error"].includes(this.stateMachine.current)||(this.fail(new Error("Authentication window closed")),this.restartIfContinuous()));},500);}destroy(){this.detachVisibilityRecovery(),this.clearBackupCheck(),this.transport?.close(),this.transport=void 0,this.listeners={};}useQrInstead(){this.useWebSocket=true,this.emit("deeplink",""),this.stateMachine.transition("initializing"),this.startWebSocketFlow();}useDeepLinkInstead(){this.useWebSocket=false,this.stateMachine.transition("initializing"),this.startDeepLinkFlow();}shouldUseWebSocket(){let n=navigator.userAgent,e=/(iPad|Android(?!.*Mobile))/i.test(n),a=/Android|webOS|iPhone|iPod|BlackBerry|IEMobile|Opera Mini/i.test(n)&&!e;return this.config.forceQRCode||!a}async startWebSocketFlow(){let{relayUrl:n,deeplinkUrl:e}=await this.fetchRelayUrl();this.transport=new Gn({onOpen:()=>{this.transport.send({type:"register",sessionID:this.sessionId,...this.config}),this.stateMachine.transition("awaiting-pair");},onMessage:i=>this.handleWebSocketMessage(i),onError:i=>{console.error("WebSocket error:",i),this.fail(new Error("WebSocket connection failed"));}}),this.transport.connect(n),await this.emitQRCode(e);}handleWebSocketMessage(n){switch(n.type){case "paired":this.stateMachine.transition("paired"),this.transport.send({type:"authenticate",sessionID:this.sessionId,...this.config,url:window.location.href});return;case "phone-auth-success":this.handleAuthSuccess(n);return;case "phone-terminated":this.fail(new Error("Authentication cancelled on device")),this.restartIfContinuous();return;case "confirmed":this.terminate(true),this.restartIfContinuous();return}}handleAuthSuccess(n){if(!this.sessionKey||!n.cipher||!n.nonce){this.fail(new Error("Invalid authentication payload")),this.restartIfContinuous();return}try{let e=this.crypto.decryptSymmetric({encrypted:{cipher:n.cipher,nonce:n.nonce},keyString:this.sessionKey});if(!e){this.fail(new Error("Invalid authentication data")),this.restartIfContinuous();return}let i=JSON.parse(e);this.emit("success",i),this.stateMachine.transition("authenticated"),this.transport?.send({type:"confirm",sessionID:this.sessionId});}catch{this.fail(new Error("Failed to decrypt authentication data")),this.restartIfContinuous();}}async startDeepLinkFlow(){let{deeplinkUrl:n}=await this.fetchRelayUrl();this.sessionKey&&Jn(this.sessionId,this.sessionKey,10*6e4),await this.emitDeepLink(n),this.deeplinkUrl=n,this.stateMachine.transition("awaiting-pair");}openDeepLink(){if(!this.deeplinkUrl){this.fail(new Error("Deep link not found"));return}this.attachVisibilityRecovery();let n=navigator.userAgent,e=bo;/iPad|iPhone|iPod/.test(n)?e=go:/android/i.test(n)&&(e=yo);let i=Date.now();window.location.href=this.deeplinkUrl,setTimeout(()=>{Date.now()-i<3500&&(window.location.href=e);},3e3);}clearBackupCheck(){this.backupCheckTimeout&&(clearTimeout(this.backupCheckTimeout),this.backupCheckTimeout=void 0);}async checkSession(){let n=Zn();if(!n){this.fail(new Error("Authentication session not found")),this.restartIfContinuous();return}this.stateMachine.transition("awaiting-auth");try{let e=await fetch(`${_r}/session?session_id=${n.sessionId}`);if(!e.ok){this.fail(new Error("Session not found")),this.restartIfContinuous();return}let i=await e.json(),a=this.crypto.decryptSymmetric({encrypted:{cipher:i.cipher,nonce:i.nonce},keyString:n.sessionKey});if(!a){console.warn("Failed to decrypt session"),this.fail(new Error("Failed to decrypt session")),this.restartIfContinuous();return}let c=JSON.parse(a);this.clearBackupCheck(),Fe(),this.emit("success",c),this.stateMachine.transition("authenticated"),this.config.continuousMode?setTimeout(()=>{this.stateMachine.transition("idle"),this.start();},1500):this.stateMachine.transition("idle");}catch(e){console.debug("Session check failed:",e),this.fail(new Error("Session check failed")),this.restartIfContinuous();return}}async emitQRCode(n){let e=`${n}?sessionID=${encodeURIComponent(this.sessionId)}&sessionKey=${encodeURIComponent(this.sessionKey)}&publicKey=${encodeURIComponent(this.config.publicKey)}&authType=${this.config.authType}&projectId=${encodeURIComponent(this.config.projectId)}`,i=await uo.default.toDataURL(e,{type:"image/png",scale:3,color:{light:"#ffffff",dark:"#424242ff"}});this.emit("qr",i);}async emitDeepLink(n){let e=`${n}?sessionID=${encodeURIComponent(this.sessionId)}&sessionKey=${encodeURIComponent(this.sessionKey)}&publicKey=${encodeURIComponent(this.config.publicKey)}&authType=${this.config.authType}&projectId=${encodeURIComponent(this.config.projectId)}`;this.emit("deeplink",e);}attachVisibilityRecovery(){let n=false;this.visibilityHandler=async()=>{document.visibilityState==="visible"&&(this.useWebSocket||n||(n=true,await this.checkSession()));},document.addEventListener("visibilitychange",this.visibilityHandler);}detachVisibilityRecovery(){this.visibilityHandler&&(document.removeEventListener("visibilitychange",this.visibilityHandler),this.visibilityHandler=void 0);}async fetchRelayUrl(){let{publicKey:n,projectId:e,authType:i}=this.config,a=await fetch(`${_r}/relay?public_key=${n}&auth_type=${i}&project_id=${e}`);if(!a.ok){let u=await a.text();throw new Error(u)}let c=await a.json();return {deeplinkUrl:c.deeplink_url,relayUrl:c.relay_url}}terminate(n){this.clearBackupCheck(),this.transport&&(n||this.transport.send({type:"client-terminated",sessionID:this.sessionId,projectId:this.config.projectId,publicKey:this.config.publicKey,authType:this.config.authType}),this.transport.close(),this.transport=void 0),Fe(),this.resetSession(),this.config.continuousMode||this.detachVisibilityRecovery(),this.stateMachine.transition(n?"confirmed":"idle");}restartIfContinuous(){this.config.continuousMode?(this.stateMachine.transition("idle"),this.clearBackupCheck(),this.transport?.close(),this.transport=void 0,setTimeout(()=>{this.start();},150)):this.stateMachine.transition("idle");}resetSession(){this.sessionId="",this.sessionKey=null;}emit(n,e){this.listeners[n]?.forEach(i=>i(e));}fail(n){this.emit("error",n),this.stateMachine.transition("error");}};Lt.BASEURL=_r;Lt.CryptoService=Wn;Lt.PelicanAuthentication=mo;Lt.StateMachine=Qn;Lt.Transport=Gn;Lt.clearAllAuthData=po;Lt.clearAuthSession=Fe;Lt.getAuthSession=Zn;Lt.storeAuthSession=Jn;});var ti=pi(Xn());function wo(){if(document.getElementById("pelican-auth-styles"))return;let n=document.createElement("style");n.id="pelican-auth-styles",n.textContent=`
9
9
  /* Pelican Auth Button Wrapper Styles */
10
10
  .pelican-auth-btn-wrapper * {
11
11
  box-sizing: border-box;