@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.mjs CHANGED
@@ -5,7 +5,7 @@ Make sure your charset is UTF-8`);i=(i>>>8&255)*192+(i&255),n.put(i,13);}};_n.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=Xi(e,i,c),y=qe.getSymbolSize(e),E=new Ki(y);return Wi(E,e),Ji(E),Zi(E,e),mr(E,i,0),e>=7&&Qi(E,e),Gi(E,g),isNaN(a)&&(a=wr.getBestMask(E,mr.bind(null,E,i))),wr.applyMask(a,E),mr(E,i,a),{modules:E,version:e,errorCorrectionLevel:i,maskPattern:a,segments:c}}jn.create=function(e,i){if(typeof e>"u"||e==="")throw new Error("No input text");let a=yr.M,c,u;return typeof i<"u"&&(a=yr.from(i.errorCorrectionLevel,yr.M),c=Oe.from(i.version),u=wr.from(i.maskPattern),i.toSJISFunc&&qe.setToSJISFunction(i.toSJISFunc)),eo(e,c,a,u)};});var Er=et(Vt=>{function zn(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:zn(e.color.dark||"#000000ff"),light:zn(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 On=et(Ke=>{var Cr=Er();function ro(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 no(){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=no()),c=Cr.getOptions(c);let g=Cr.getImageWidth(e.modules.size,c),y=u.getContext("2d"),E=y.createImageData(g,g);return Cr.qrToImageData(E.data,e,c),ro(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 Yn=et(Kn=>{var io=Er();function qn(n,e){let i=n.a/255,a=e+'="'+n.hex+'"';return i<1?a+" "+e+'-opacity="'+i.toFixed(2).slice(1)+'"':a}function Ar(n,e,i){let a=n+e;return typeof i<"u"&&(a+=" "+i),a}function oo(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?Ar("M",E+i,.5+z+i):Ar("m",c,0),c=0,u=false),E+1<e&&n[y+1]||(a+=Ar("h",g),g=0)):c++;}return a}Kn.render=function(e,i,a){let c=io.getOptions(i),u=e.modules.size,g=e.modules.data,y=u+c.margin*2,E=c.color.light.a?"<path "+qn(c.color.light,"fill")+' d="M0 0h'+y+"v"+y+'H0z"/>':"",z="<path "+qn(c.color.dark,"stroke")+' d="'+oo(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 $n=et(ve=>{var so=Hr(),Sr=Dn(),Fn=On(),fo=Yn();function _r(n,e,i,a,c){let u=[].slice.call(arguments,1),g=u.length,y=typeof u[g-1]=="function";if(!y&&!so())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=Sr.create(i,a);E(n(q,e,a));}catch(q){z(q);}})}try{let E=Sr.create(i,a);c(null,n(E,e,a));}catch(E){c(E);}}ve.create=Sr.create;ve.toCanvas=_r.bind(null,Fn.render);ve.toDataURL=_r.bind(null,Fn.renderToDataURL);ve.toString=_r.bind(null,function(n,e,i){return fo.render(n,i)});});var Gn=et(Lt=>{var ao=Kr(),Wt=Fr(),co=$n();function Hn(n){return n&&n.__esModule?n:{default:n}}var Ye=Hn(ao),lo=Hn(co),Vn=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}}},uo=Vn,ho=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 ho,Wn=(n,e,i)=>{$e.set("session",{sessionId:n,sessionKey:e},{ttlMs:i});},Jn=()=>$e.get("session"),Fe=()=>{$e.remove("session");},xo=()=>{$e.clear();},Zn=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)}},Qn=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}},Br="https://identityapi.pelicanidentity.com",po="https://apps.apple.com/us/app/pelican-vault/id6755097751",go="https://play.google.com/store/apps/details?id=com.HeraculesDesignTechLtd.pelican",yo="https://pelicanidentity.com/pelican-vault",bo=class{constructor(n){if(this.crypto=new uo,this.stateMachine=new Zn,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 Qn({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&&Wn(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=yo;/iPad|iPhone|iPod/.test(n)?e=po:/android/i.test(n)&&(e=go);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=Jn();if(!n){this.fail(new Error("Authentication session not found")),this.restartIfContinuous();return}this.stateMachine.transition("awaiting-auth");try{let e=await fetch(`${Br}/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 lo.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(`${Br}/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=Br;Lt.CryptoService=Vn;Lt.PelicanAuthentication=bo;Lt.StateMachine=Zn;Lt.Transport=Qn;Lt.clearAllAuthData=xo;Lt.clearAuthSession=Fe;Lt.getAuthSession=Jn;Lt.storeAuthSession=Wn;});var Xn=xi(Gn());function mo(){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 $n=et(ve=>{var so=Hr(),Sr=Dn(),Fn=On(),fo=Yn();function _r(n,e,i,a,c){let u=[].slice.call(arguments,1),g=u.length,y=typeof u[g-1]=="function";if(!y&&!so())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=Sr.create(i,a);E(n(q,e,a));}catch(q){z(q);}})}try{let E=Sr.create(i,a);c(null,n(E,e,a));}catch(E){c(E);}}ve.create=Sr.create;ve.toCanvas=_r.bind(null,Fn.render);ve.toDataURL=_r.bind(null,Fn.renderToDataURL);ve.toString=_r.bind(null,function(n,e,i){return fo.render(n,i)});});var Gn=et(Lt=>{var ao=Kr(),Wt=Fr(),co=$n();function Hn(n){return n&&n.__esModule?n:{default:n}}var Ye=Hn(ao),lo=Hn(co),Vn=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}}},uo=Vn,ho=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 ho,Wn=(n,e,i)=>{$e.set("session",{sessionId:n,sessionKey:e},{ttlMs:i});},Jn=()=>$e.get("session"),Fe=()=>{$e.remove("session");},xo=()=>{$e.clear();},Zn=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)}},Qn=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}},Br="https://identityapi.pelicanidentity.com",po="https://apps.apple.com/us/app/pelican-vault/id6755097751",go="https://play.google.com/store/apps/details?id=com.HeraculesDesignTechLtd.pelican",yo="https://pelicanidentity.com/pelican-vault",bo=class{constructor(n){if(this.crypto=new uo,this.stateMachine=new Zn,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 Qn({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&&Wn(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=yo;/iPad|iPhone|iPod/.test(n)?e=po:/android/i.test(n)&&(e=go);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=Jn();if(!n){this.fail(new Error("Authentication session not found")),this.restartIfContinuous();return}this.stateMachine.transition("awaiting-auth");try{let e=await fetch(`${Br}/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 lo.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(`${Br}/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=Br;Lt.CryptoService=Vn;Lt.PelicanAuthentication=bo;Lt.StateMachine=Zn;Lt.Transport=Qn;Lt.clearAllAuthData=xo;Lt.clearAuthSession=Fe;Lt.getAuthSession=Jn;Lt.storeAuthSession=Wn;});var Xn=xi(Gn());function mo(){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;