@qrauth/web-components 0.4.0 → 0.4.1

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.
@@ -1,5 +1,12 @@
1
- /* @qrauth/web-components v0.4.0 — https://qrauth.io */
2
- "use strict";var QRAuthComponents=(()=>{var v=Object.defineProperty;var k=Object.getOwnPropertyDescriptor;var E=Object.getOwnPropertyNames;var I=Object.prototype.hasOwnProperty;var S=(o,a,t)=>a in o?v(o,a,{enumerable:!0,configurable:!0,writable:!0,value:t}):o[a]=t;var A=(o,a)=>{for(var t in a)v(o,t,{get:a[t],enumerable:!0})},T=(o,a,t,e)=>{if(a&&typeof a=="object"||typeof a=="function")for(let i of E(a))!I.call(o,i)&&i!==t&&v(o,i,{get:()=>a[i],enumerable:!(e=k(a,i))||e.enumerable});return o};var C=o=>T(v({},"__esModule",{value:!0}),o);var n=(o,a,t)=>S(o,typeof a!="symbol"?a+"":a,t);var $={};A($,{QRAuthElement:()=>p,QRAuthEphemeral:()=>b,QRAuthLogin:()=>g,QRAuthTwoFA:()=>m});var p=class extends HTMLElement{constructor(){super();n(this,"shadow");n(this,"_sseConnection",null);n(this,"_pollInterval",null);this.shadow=this.attachShadow({mode:"open"})}static get observedAttributes(){return["tenant","theme","base-url","force-mode","mobile-fallback-only"]}get tenant(){return this.getAttribute("tenant")||""}get theme(){return this.getAttribute("theme")||"light"}get baseUrl(){let t=this.getAttribute("base-url");return t!==null?t:"https://qrauth.io"}connectedCallback(){this.render()}disconnectedCallback(){this.cleanup()}attributeChangedCallback(t,e,i){e!==i&&this.render()}isMobileLike(){if(typeof window>"u")return!1;let t=this.getAttribute("force-mode");if(t==="mobile")return!0;if(t==="desktop"||this.hasAttribute("mobile-fallback-only"))return!1;if(typeof window.matchMedia=="function"){let e=window.matchMedia("(pointer: coarse)").matches,i=window.matchMedia("(hover: none)").matches;if(e&&i)return!0}return/Android|iPhone|iPad|iPod|Mobile|Tablet|BlackBerry|Opera Mini/i.test(navigator.userAgent)}connectSSE(t){this.disconnectSSE(),this._sseConnection=new EventSource(t),this._sseConnection.onerror=()=>{this.disconnectSSE()}}onSSEEvent(t,e){this._sseConnection&&this._sseConnection.addEventListener(t,i=>{let r=i;try{e(JSON.parse(r.data))}catch{}})}disconnectSSE(){this._sseConnection&&(this._sseConnection.close(),this._sseConnection=null)}startPolling(t,e,i,r){this.stopPolling();let s=async()=>{try{let d=await fetch(t,{headers:r});d.ok&&i(await d.json())}catch{}};s(),this._pollInterval=setInterval(s,e)}stopPolling(){this._pollInterval&&(clearInterval(this._pollInterval),this._pollInterval=null)}cleanup(){this.disconnectSSE(),this.stopPolling()}emit(t,e){this.dispatchEvent(new CustomEvent(t,{bubbles:!0,composed:!0,detail:e}))}async generateCodeVerifier(){let t=new Uint8Array(32);return crypto.getRandomValues(t),this._base64url(t)}async computeCodeChallenge(t){let i=new TextEncoder().encode(t),r=await crypto.subtle.digest("SHA-256",i);return this._base64url(new Uint8Array(r))}_base64url(t){let e=Array.from(t,i=>String.fromCodePoint(i)).join("");return btoa(e).replace(/\+/g,"-").replace(/\//g,"_").replace(/=+$/,"")}getBaseStyles(){return`
1
+ /* @qrauth/web-components v0.4.1 — https://qrauth.io */
2
+ "use strict";var QRAuthComponents=(()=>{var Oe=Object.create;var z=Object.defineProperty;var Ke=Object.getOwnPropertyDescriptor;var Ye=Object.getOwnPropertyNames;var Xe=Object.getPrototypeOf,Ge=Object.prototype.hasOwnProperty;var Je=(i,e,t)=>e in i?z(i,e,{enumerable:!0,configurable:!0,writable:!0,value:t}):i[e]=t;var g=(i,e)=>()=>(e||i((e={exports:{}}).exports,e),e.exports),We=(i,e)=>{for(var t in e)z(i,t,{get:e[t],enumerable:!0})},zt=(i,e,t,r)=>{if(e&&typeof e=="object"||typeof e=="function")for(let n of Ye(e))!Ge.call(i,n)&&n!==t&&z(i,n,{get:()=>e[n],enumerable:!(r=Ke(e,n))||r.enumerable});return i};var Ze=(i,e,t)=>(t=i!=null?Oe(Xe(i)):{},zt(e||!i||!i.__esModule?z(t,"default",{value:i,enumerable:!0}):t,i)),tr=i=>zt(z({},"__esModule",{value:!0}),i);var p=(i,e,t)=>Je(i,typeof e!="symbol"?e+"":e,t);var Qt=g((ri,Vt)=>{Vt.exports=function(){return typeof Promise=="function"&&Promise.prototype&&Promise.prototype.then}});var I=g(T=>{var mt,er=[0,26,44,70,100,134,172,196,242,292,346,404,466,532,581,655,733,815,901,991,1085,1156,1258,1364,1474,1588,1706,1828,1921,2051,2185,2323,2465,2611,2761,2876,3034,3196,3362,3532,3706];T.getSymbolSize=function(e){if(!e)throw new Error('"version" cannot be null or undefined');if(e<1||e>40)throw new Error('"version" should be in range from 1 to 40');return e*4+17};T.getSymbolTotalCodewords=function(e){return er[e]};T.getBCHDigit=function(i){let e=0;for(;i!==0;)e++,i>>>=1;return e};T.setToSJISFunction=function(e){if(typeof e!="function")throw new Error('"toSJISFunc" is not a valid function.');mt=e};T.isKanjiModeEnabled=function(){return typeof mt<"u"};T.toSJIS=function(e){return mt(e)}});var tt=g(v=>{v.L={bit:1};v.M={bit:0};v.Q={bit:3};v.H={bit:2};function rr(i){if(typeof i!="string")throw new Error("Param is not a string");switch(i.toLowerCase()){case"l":case"low":return v.L;case"m":case"medium":return v.M;case"q":case"quartile":return v.Q;case"h":case"high":return v.H;default:throw new Error("Unknown EC Level: "+i)}}v.isValid=function(e){return e&&typeof e.bit<"u"&&e.bit>=0&&e.bit<4};v.from=function(e,t){if(v.isValid(e))return e;try{return rr(e)}catch{return t}}});var Ot=g((si,jt)=>{function Ht(){this.buffer=[],this.length=0}Ht.prototype={get:function(i){let e=Math.floor(i/8);return(this.buffer[e]>>>7-i%8&1)===1},put:function(i,e){for(let t=0;t<e;t++)this.putBit((i>>>e-t-1&1)===1)},getLengthInBits:function(){return this.length},putBit:function(i){let e=Math.floor(this.length/8);this.buffer.length<=e&&this.buffer.push(0),i&&(this.buffer[e]|=128>>>this.length%8),this.length++}};jt.exports=Ht});var Yt=g((oi,Kt)=>{function V(i){if(!i||i<1)throw new Error("BitMatrix size must be defined and greater than 0");this.size=i,this.data=new Uint8Array(i*i),this.reservedBit=new Uint8Array(i*i)}V.prototype.set=function(i,e,t,r){let n=i*this.size+e;this.data[n]=t,r&&(this.reservedBit[n]=!0)};V.prototype.get=function(i,e){return this.data[i*this.size+e]};V.prototype.xor=function(i,e,t){this.data[i*this.size+e]^=t};V.prototype.isReserved=function(i,e){return this.reservedBit[i*this.size+e]};Kt.exports=V});var Xt=g(et=>{var ir=I().getSymbolSize;et.getRowColCoords=function(e){if(e===1)return[];let t=Math.floor(e/7)+2,r=ir(e),n=r===145?26:Math.ceil((r-13)/(2*t-2))*2,s=[r-7];for(let o=1;o<t-1;o++)s[o]=s[o-1]-n;return s.push(6),s.reverse()};et.getPositions=function(e){let t=[],r=et.getRowColCoords(e),n=r.length;for(let s=0;s<n;s++)for(let o=0;o<n;o++)s===0&&o===0||s===0&&o===n-1||s===n-1&&o===0||t.push([r[s],r[o]]);return t}});var Wt=g(Jt=>{var nr=I().getSymbolSize,Gt=7;Jt.getPositions=function(e){let t=nr(e);return[[0,0],[t-Gt,0],[0,t-Gt]]}});var Zt=g(m=>{m.Patterns={PATTERN000:0,PATTERN001:1,PATTERN010:2,PATTERN011:3,PATTERN100:4,PATTERN101:5,PATTERN110:6,PATTERN111:7};var M={N1:3,N2:3,N3:40,N4:10};m.isValid=function(e){return e!=null&&e!==""&&!isNaN(e)&&e>=0&&e<=7};m.from=function(e){return m.isValid(e)?parseInt(e,10):void 0};m.getPenaltyN1=function(e){let t=e.size,r=0,n=0,s=0,o=null,a=null;for(let l=0;l<t;l++){n=s=0,o=a=null;for(let d=0;d<t;d++){let c=e.get(l,d);c===o?n++:(n>=5&&(r+=M.N1+(n-5)),o=c,n=1),c=e.get(d,l),c===a?s++:(s>=5&&(r+=M.N1+(s-5)),a=c,s=1)}n>=5&&(r+=M.N1+(n-5)),s>=5&&(r+=M.N1+(s-5))}return r};m.getPenaltyN2=function(e){let t=e.size,r=0;for(let n=0;n<t-1;n++)for(let s=0;s<t-1;s++){let o=e.get(n,s)+e.get(n,s+1)+e.get(n+1,s)+e.get(n+1,s+1);(o===4||o===0)&&r++}return r*M.N2};m.getPenaltyN3=function(e){let t=e.size,r=0,n=0,s=0;for(let o=0;o<t;o++){n=s=0;for(let a=0;a<t;a++)n=n<<1&2047|e.get(o,a),a>=10&&(n===1488||n===93)&&r++,s=s<<1&2047|e.get(a,o),a>=10&&(s===1488||s===93)&&r++}return r*M.N3};m.getPenaltyN4=function(e){let t=0,r=e.data.length;for(let s=0;s<r;s++)t+=e.data[s];return Math.abs(Math.ceil(t*100/r/5)-10)*M.N4};function sr(i,e,t){switch(i){case m.Patterns.PATTERN000:return(e+t)%2===0;case m.Patterns.PATTERN001:return e%2===0;case m.Patterns.PATTERN010:return t%3===0;case m.Patterns.PATTERN011:return(e+t)%3===0;case m.Patterns.PATTERN100:return(Math.floor(e/2)+Math.floor(t/3))%2===0;case m.Patterns.PATTERN101:return e*t%2+e*t%3===0;case m.Patterns.PATTERN110:return(e*t%2+e*t%3)%2===0;case m.Patterns.PATTERN111:return(e*t%3+(e+t)%2)%2===0;default:throw new Error("bad maskPattern:"+i)}}m.applyMask=function(e,t){let r=t.size;for(let n=0;n<r;n++)for(let s=0;s<r;s++)t.isReserved(s,n)||t.xor(s,n,sr(e,s,n))};m.getBestMask=function(e,t){let r=Object.keys(m.Patterns).length,n=0,s=1/0;for(let o=0;o<r;o++){t(o),m.applyMask(o,e);let a=m.getPenaltyN1(e)+m.getPenaltyN2(e)+m.getPenaltyN3(e)+m.getPenaltyN4(e);m.applyMask(o,e),a<s&&(s=a,n=o)}return n}});var vt=g(bt=>{var C=tt(),rt=[1,1,1,1,1,1,1,1,1,1,2,2,1,2,2,4,1,2,4,4,2,4,4,4,2,4,6,5,2,4,6,6,2,5,8,8,4,5,8,8,4,5,8,11,4,8,10,11,4,9,12,16,4,9,16,16,6,10,12,18,6,10,17,16,6,11,16,19,6,13,18,21,7,14,21,25,8,16,20,25,8,17,23,25,9,17,23,34,9,18,25,30,10,20,27,32,12,21,29,35,12,23,34,37,12,25,34,40,13,26,35,42,14,28,38,45,15,29,40,48,16,31,43,51,17,33,45,54,18,35,48,57,19,37,51,60,19,38,53,63,20,40,56,66,21,43,59,70,22,45,62,74,24,47,65,77,25,49,68,81],it=[7,10,13,17,10,16,22,28,15,26,36,44,20,36,52,64,26,48,72,88,36,64,96,112,40,72,108,130,48,88,132,156,60,110,160,192,72,130,192,224,80,150,224,264,96,176,260,308,104,198,288,352,120,216,320,384,132,240,360,432,144,280,408,480,168,308,448,532,180,338,504,588,196,364,546,650,224,416,600,700,224,442,644,750,252,476,690,816,270,504,750,900,300,560,810,960,312,588,870,1050,336,644,952,1110,360,700,1020,1200,390,728,1050,1260,420,784,1140,1350,450,812,1200,1440,480,868,1290,1530,510,924,1350,1620,540,980,1440,1710,570,1036,1530,1800,570,1064,1590,1890,600,1120,1680,1980,630,1204,1770,2100,660,1260,1860,2220,720,1316,1950,2310,750,1372,2040,2430];bt.getBlocksCount=function(e,t){switch(t){case C.L:return rt[(e-1)*4+0];case C.M:return rt[(e-1)*4+1];case C.Q:return rt[(e-1)*4+2];case C.H:return rt[(e-1)*4+3];default:return}};bt.getTotalCodewordsCount=function(e,t){switch(t){case C.L:return it[(e-1)*4+0];case C.M:return it[(e-1)*4+1];case C.Q:return it[(e-1)*4+2];case C.H:return it[(e-1)*4+3];default:return}}});var te=g(st=>{var Q=new Uint8Array(512),nt=new Uint8Array(256);(function(){let e=1;for(let t=0;t<255;t++)Q[t]=e,nt[e]=t,e<<=1,e&256&&(e^=285);for(let t=255;t<512;t++)Q[t]=Q[t-255]})();st.log=function(e){if(e<1)throw new Error("log("+e+")");return nt[e]};st.exp=function(e){return Q[e]};st.mul=function(e,t){return e===0||t===0?0:Q[nt[e]+nt[t]]}});var ee=g(H=>{var xt=te();H.mul=function(e,t){let r=new Uint8Array(e.length+t.length-1);for(let n=0;n<e.length;n++)for(let s=0;s<t.length;s++)r[n+s]^=xt.mul(e[n],t[s]);return r};H.mod=function(e,t){let r=new Uint8Array(e);for(;r.length-t.length>=0;){let n=r[0];for(let o=0;o<t.length;o++)r[o]^=xt.mul(t[o],n);let s=0;for(;s<r.length&&r[s]===0;)s++;r=r.slice(s)}return r};H.generateECPolynomial=function(e){let t=new Uint8Array([1]);for(let r=0;r<e;r++)t=H.mul(t,new Uint8Array([1,xt.exp(r)]));return t}});var ne=g((pi,ie)=>{var re=ee();function yt(i){this.genPoly=void 0,this.degree=i,this.degree&&this.initialize(this.degree)}yt.prototype.initialize=function(e){this.degree=e,this.genPoly=re.generateECPolynomial(this.degree)};yt.prototype.encode=function(e){if(!this.genPoly)throw new Error("Encoder not initialized");let t=new Uint8Array(e.length+this.degree);t.set(e);let r=re.mod(t,this.genPoly),n=this.degree-r.length;if(n>0){let s=new Uint8Array(this.degree);return s.set(r,n),s}return r};ie.exports=yt});var _t=g(se=>{se.isValid=function(e){return!isNaN(e)&&e>=1&&e<=40}});var wt=g(E=>{var oe="[0-9]+",or="[A-Z $%*+\\-./:]+",j="(?:[u3000-u303F]|[u3040-u309F]|[u30A0-u30FF]|[uFF00-uFFEF]|[u4E00-u9FAF]|[u2605-u2606]|[u2190-u2195]|u203B|[u2010u2015u2018u2019u2025u2026u201Cu201Du2225u2260]|[u0391-u0451]|[u00A7u00A8u00B1u00B4u00D7u00F7])+";j=j.replace(/u/g,"\\u");var ar="(?:(?![A-Z0-9 $%*+\\-./:]|"+j+`)(?:.|[\r
3
+ ]))+`;E.KANJI=new RegExp(j,"g");E.BYTE_KANJI=new RegExp("[^A-Z0-9 $%*+\\-./:]+","g");E.BYTE=new RegExp(ar,"g");E.NUMERIC=new RegExp(oe,"g");E.ALPHANUMERIC=new RegExp(or,"g");var lr=new RegExp("^"+j+"$"),dr=new RegExp("^"+oe+"$"),cr=new RegExp("^[A-Z0-9 $%*+\\-./:]+$");E.testKanji=function(e){return lr.test(e)};E.testNumeric=function(e){return dr.test(e)};E.testAlphanumeric=function(e){return cr.test(e)}});var A=g(b=>{var ur=_t(),Et=wt();b.NUMERIC={id:"Numeric",bit:1,ccBits:[10,12,14]};b.ALPHANUMERIC={id:"Alphanumeric",bit:2,ccBits:[9,11,13]};b.BYTE={id:"Byte",bit:4,ccBits:[8,16,16]};b.KANJI={id:"Kanji",bit:8,ccBits:[8,10,12]};b.MIXED={bit:-1};b.getCharCountIndicator=function(e,t){if(!e.ccBits)throw new Error("Invalid mode: "+e);if(!ur.isValid(t))throw new Error("Invalid version: "+t);return t>=1&&t<10?e.ccBits[0]:t<27?e.ccBits[1]:e.ccBits[2]};b.getBestModeForData=function(e){return Et.testNumeric(e)?b.NUMERIC:Et.testAlphanumeric(e)?b.ALPHANUMERIC:Et.testKanji(e)?b.KANJI:b.BYTE};b.toString=function(e){if(e&&e.id)return e.id;throw new Error("Invalid mode")};b.isValid=function(e){return e&&e.bit&&e.ccBits};function hr(i){if(typeof i!="string")throw new Error("Param is not a string");switch(i.toLowerCase()){case"numeric":return b.NUMERIC;case"alphanumeric":return b.ALPHANUMERIC;case"kanji":return b.KANJI;case"byte":return b.BYTE;default:throw new Error("Unknown mode: "+i)}}b.from=function(e,t){if(b.isValid(e))return e;try{return hr(e)}catch{return t}}});var ue=g(R=>{var ot=I(),pr=vt(),ae=tt(),B=A(),kt=_t(),de=7973,le=ot.getBCHDigit(de);function gr(i,e,t){for(let r=1;r<=40;r++)if(e<=R.getCapacity(r,t,i))return r}function ce(i,e){return B.getCharCountIndicator(i,e)+4}function fr(i,e){let t=0;return i.forEach(function(r){let n=ce(r.mode,e);t+=n+r.getBitsLength()}),t}function mr(i,e){for(let t=1;t<=40;t++)if(fr(i,t)<=R.getCapacity(t,e,B.MIXED))return t}R.from=function(e,t){return kt.isValid(e)?parseInt(e,10):t};R.getCapacity=function(e,t,r){if(!kt.isValid(e))throw new Error("Invalid QR Code version");typeof r>"u"&&(r=B.BYTE);let n=ot.getSymbolTotalCodewords(e),s=pr.getTotalCodewordsCount(e,t),o=(n-s)*8;if(r===B.MIXED)return o;let a=o-ce(r,e);switch(r){case B.NUMERIC:return Math.floor(a/10*3);case B.ALPHANUMERIC:return Math.floor(a/11*2);case B.KANJI:return Math.floor(a/13);case B.BYTE:default:return Math.floor(a/8)}};R.getBestVersionForData=function(e,t){let r,n=ae.from(t,ae.M);if(Array.isArray(e)){if(e.length>1)return mr(e,n);if(e.length===0)return 1;r=e[0]}else r=e;return gr(r.mode,r.getLength(),n)};R.getEncodedBits=function(e){if(!kt.isValid(e)||e<7)throw new Error("Invalid QR Code version");let t=e<<12;for(;ot.getBCHDigit(t)-le>=0;)t^=de<<ot.getBCHDigit(t)-le;return e<<12|t}});var fe=g(ge=>{var St=I(),pe=1335,br=21522,he=St.getBCHDigit(pe);ge.getEncodedBits=function(e,t){let r=e.bit<<3|t,n=r<<10;for(;St.getBCHDigit(n)-he>=0;)n^=pe<<St.getBCHDigit(n)-he;return(r<<10|n)^br}});var be=g((xi,me)=>{var vr=A();function N(i){this.mode=vr.NUMERIC,this.data=i.toString()}N.getBitsLength=function(e){return 10*Math.floor(e/3)+(e%3?e%3*3+1:0)};N.prototype.getLength=function(){return this.data.length};N.prototype.getBitsLength=function(){return N.getBitsLength(this.data.length)};N.prototype.write=function(e){let t,r,n;for(t=0;t+3<=this.data.length;t+=3)r=this.data.substr(t,3),n=parseInt(r,10),e.put(n,10);let s=this.data.length-t;s>0&&(r=this.data.substr(t),n=parseInt(r,10),e.put(n,s*3+1))};me.exports=N});var xe=g((yi,ve)=>{var xr=A(),It=["0","1","2","3","4","5","6","7","8","9","A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z"," ","$","%","*","+","-",".","/",":"];function U(i){this.mode=xr.ALPHANUMERIC,this.data=i}U.getBitsLength=function(e){return 11*Math.floor(e/2)+6*(e%2)};U.prototype.getLength=function(){return this.data.length};U.prototype.getBitsLength=function(){return U.getBitsLength(this.data.length)};U.prototype.write=function(e){let t;for(t=0;t+2<=this.data.length;t+=2){let r=It.indexOf(this.data[t])*45;r+=It.indexOf(this.data[t+1]),e.put(r,11)}this.data.length%2&&e.put(It.indexOf(this.data[t]),6)};ve.exports=U});var _e=g((_i,ye)=>{var yr=A();function D(i){this.mode=yr.BYTE,typeof i=="string"?this.data=new TextEncoder().encode(i):this.data=new Uint8Array(i)}D.getBitsLength=function(e){return e*8};D.prototype.getLength=function(){return this.data.length};D.prototype.getBitsLength=function(){return D.getBitsLength(this.data.length)};D.prototype.write=function(i){for(let e=0,t=this.data.length;e<t;e++)i.put(this.data[e],8)};ye.exports=D});var Ee=g((wi,we)=>{var _r=A(),wr=I();function L(i){this.mode=_r.KANJI,this.data=i}L.getBitsLength=function(e){return e*13};L.prototype.getLength=function(){return this.data.length};L.prototype.getBitsLength=function(){return L.getBitsLength(this.data.length)};L.prototype.write=function(i){let e;for(e=0;e<this.data.length;e++){let t=wr.toSJIS(this.data[e]);if(t>=33088&&t<=40956)t-=33088;else if(t>=57408&&t<=60351)t-=49472;else throw new Error("Invalid SJIS character: "+this.data[e]+`
4
+ Make sure your charset is UTF-8`);t=(t>>>8&255)*192+(t&255),i.put(t,13)}};we.exports=L});var ke=g((Ei,Ct)=>{"use strict";var O={single_source_shortest_paths:function(i,e,t){var r={},n={};n[e]=0;var s=O.PriorityQueue.make();s.push(e,0);for(var o,a,l,d,c,u,f,x,k;!s.empty();){o=s.pop(),a=o.value,d=o.cost,c=i[a]||{};for(l in c)c.hasOwnProperty(l)&&(u=c[l],f=d+u,x=n[l],k=typeof n[l]>"u",(k||x>f)&&(n[l]=f,s.push(l,f),r[l]=a))}if(typeof t<"u"&&typeof n[t]>"u"){var S=["Could not find a path from ",e," to ",t,"."].join("");throw new Error(S)}return r},extract_shortest_path_from_predecessor_list:function(i,e){for(var t=[],r=e,n;r;)t.push(r),n=i[r],r=i[r];return t.reverse(),t},find_path:function(i,e,t){var r=O.single_source_shortest_paths(i,e,t);return O.extract_shortest_path_from_predecessor_list(r,t)},PriorityQueue:{make:function(i){var e=O.PriorityQueue,t={},r;i=i||{};for(r in e)e.hasOwnProperty(r)&&(t[r]=e[r]);return t.queue=[],t.sorter=i.sorter||e.default_sorter,t},default_sorter:function(i,e){return i.cost-e.cost},push:function(i,e){var t={value:i,cost:e};this.queue.push(t),this.queue.sort(this.sorter)},pop:function(){return this.queue.shift()},empty:function(){return this.queue.length===0}}};typeof Ct<"u"&&(Ct.exports=O)});var Re=g(F=>{var h=A(),Ce=be(),Ae=xe(),Be=_e(),Te=Ee(),K=wt(),at=I(),Er=ke();function Se(i){return unescape(encodeURIComponent(i)).length}function Y(i,e,t){let r=[],n;for(;(n=i.exec(t))!==null;)r.push({data:n[0],index:n.index,mode:e,length:n[0].length});return r}function Me(i){let e=Y(K.NUMERIC,h.NUMERIC,i),t=Y(K.ALPHANUMERIC,h.ALPHANUMERIC,i),r,n;return at.isKanjiModeEnabled()?(r=Y(K.BYTE,h.BYTE,i),n=Y(K.KANJI,h.KANJI,i)):(r=Y(K.BYTE_KANJI,h.BYTE,i),n=[]),e.concat(t,r,n).sort(function(o,a){return o.index-a.index}).map(function(o){return{data:o.data,mode:o.mode,length:o.length}})}function At(i,e){switch(e){case h.NUMERIC:return Ce.getBitsLength(i);case h.ALPHANUMERIC:return Ae.getBitsLength(i);case h.KANJI:return Te.getBitsLength(i);case h.BYTE:return Be.getBitsLength(i)}}function kr(i){return i.reduce(function(e,t){let r=e.length-1>=0?e[e.length-1]:null;return r&&r.mode===t.mode?(e[e.length-1].data+=t.data,e):(e.push(t),e)},[])}function Sr(i){let e=[];for(let t=0;t<i.length;t++){let r=i[t];switch(r.mode){case h.NUMERIC:e.push([r,{data:r.data,mode:h.ALPHANUMERIC,length:r.length},{data:r.data,mode:h.BYTE,length:r.length}]);break;case h.ALPHANUMERIC:e.push([r,{data:r.data,mode:h.BYTE,length:r.length}]);break;case h.KANJI:e.push([r,{data:r.data,mode:h.BYTE,length:Se(r.data)}]);break;case h.BYTE:e.push([{data:r.data,mode:h.BYTE,length:Se(r.data)}])}}return e}function Ir(i,e){let t={},r={start:{}},n=["start"];for(let s=0;s<i.length;s++){let o=i[s],a=[];for(let l=0;l<o.length;l++){let d=o[l],c=""+s+l;a.push(c),t[c]={node:d,lastCount:0},r[c]={};for(let u=0;u<n.length;u++){let f=n[u];t[f]&&t[f].node.mode===d.mode?(r[f][c]=At(t[f].lastCount+d.length,d.mode)-At(t[f].lastCount,d.mode),t[f].lastCount+=d.length):(t[f]&&(t[f].lastCount=d.length),r[f][c]=At(d.length,d.mode)+4+h.getCharCountIndicator(d.mode,e))}}n=a}for(let s=0;s<n.length;s++)r[n[s]].end=0;return{map:r,table:t}}function Ie(i,e){let t,r=h.getBestModeForData(i);if(t=h.from(e,r),t!==h.BYTE&&t.bit<r.bit)throw new Error('"'+i+'" cannot be encoded with mode '+h.toString(t)+`.
5
+ Suggested mode is: `+h.toString(r));switch(t===h.KANJI&&!at.isKanjiModeEnabled()&&(t=h.BYTE),t){case h.NUMERIC:return new Ce(i);case h.ALPHANUMERIC:return new Ae(i);case h.KANJI:return new Te(i);case h.BYTE:return new Be(i)}}F.fromArray=function(e){return e.reduce(function(t,r){return typeof r=="string"?t.push(Ie(r,null)):r.data&&t.push(Ie(r.data,r.mode)),t},[])};F.fromString=function(e,t){let r=Me(e,at.isKanjiModeEnabled()),n=Sr(r),s=Ir(n,t),o=Er.find_path(s.map,"start","end"),a=[];for(let l=1;l<o.length-1;l++)a.push(s.table[o[l]].node);return F.fromArray(kr(a))};F.rawSplit=function(e){return F.fromArray(Me(e,at.isKanjiModeEnabled()))}});var qe=g(Pe=>{var dt=I(),Bt=tt(),Cr=Ot(),Ar=Yt(),Br=Xt(),Tr=Wt(),Rt=Zt(),Pt=vt(),Mr=ne(),lt=ue(),Rr=fe(),Pr=A(),Tt=Re();function qr(i,e){let t=i.size,r=Tr.getPositions(e);for(let n=0;n<r.length;n++){let s=r[n][0],o=r[n][1];for(let a=-1;a<=7;a++)if(!(s+a<=-1||t<=s+a))for(let l=-1;l<=7;l++)o+l<=-1||t<=o+l||(a>=0&&a<=6&&(l===0||l===6)||l>=0&&l<=6&&(a===0||a===6)||a>=2&&a<=4&&l>=2&&l<=4?i.set(s+a,o+l,!0,!0):i.set(s+a,o+l,!1,!0))}}function Nr(i){let e=i.size;for(let t=8;t<e-8;t++){let r=t%2===0;i.set(t,6,r,!0),i.set(6,t,r,!0)}}function Ur(i,e){let t=Br.getPositions(e);for(let r=0;r<t.length;r++){let n=t[r][0],s=t[r][1];for(let o=-2;o<=2;o++)for(let a=-2;a<=2;a++)o===-2||o===2||a===-2||a===2||o===0&&a===0?i.set(n+o,s+a,!0,!0):i.set(n+o,s+a,!1,!0)}}function Dr(i,e){let t=i.size,r=lt.getEncodedBits(e),n,s,o;for(let a=0;a<18;a++)n=Math.floor(a/3),s=a%3+t-8-3,o=(r>>a&1)===1,i.set(n,s,o,!0),i.set(s,n,o,!0)}function Mt(i,e,t){let r=i.size,n=Rr.getEncodedBits(e,t),s,o;for(s=0;s<15;s++)o=(n>>s&1)===1,s<6?i.set(s,8,o,!0):s<8?i.set(s+1,8,o,!0):i.set(r-15+s,8,o,!0),s<8?i.set(8,r-s-1,o,!0):s<9?i.set(8,15-s-1+1,o,!0):i.set(8,15-s-1,o,!0);i.set(r-8,8,1,!0)}function Lr(i,e){let t=i.size,r=-1,n=t-1,s=7,o=0;for(let a=t-1;a>0;a-=2)for(a===6&&a--;;){for(let l=0;l<2;l++)if(!i.isReserved(n,a-l)){let d=!1;o<e.length&&(d=(e[o]>>>s&1)===1),i.set(n,a-l,d),s--,s===-1&&(o++,s=7)}if(n+=r,n<0||t<=n){n-=r,r=-r;break}}}function Fr(i,e,t){let r=new Cr;t.forEach(function(l){r.put(l.mode.bit,4),r.put(l.getLength(),Pr.getCharCountIndicator(l.mode,i)),l.write(r)});let n=dt.getSymbolTotalCodewords(i),s=Pt.getTotalCodewordsCount(i,e),o=(n-s)*8;for(r.getLengthInBits()+4<=o&&r.put(0,4);r.getLengthInBits()%8!==0;)r.putBit(0);let a=(o-r.getLengthInBits())/8;for(let l=0;l<a;l++)r.put(l%2?17:236,8);return $r(r,i,e)}function $r(i,e,t){let r=dt.getSymbolTotalCodewords(e),n=Pt.getTotalCodewordsCount(e,t),s=r-n,o=Pt.getBlocksCount(e,t),a=r%o,l=o-a,d=Math.floor(r/o),c=Math.floor(s/o),u=c+1,f=d-c,x=new Mr(f),k=0,S=new Array(o),Ft=new Array(o),pt=0,je=new Uint8Array(i.buffer);for(let q=0;q<o;q++){let ft=q<l?c:u;S[q]=je.slice(k,k+ft),Ft[q]=x.encode(S[q]),k+=ft,pt=Math.max(pt,ft)}let gt=new Uint8Array(r),$t=0,_,w;for(_=0;_<pt;_++)for(w=0;w<o;w++)_<S[w].length&&(gt[$t++]=S[w][_]);for(_=0;_<f;_++)for(w=0;w<o;w++)gt[$t++]=Ft[w][_];return gt}function zr(i,e,t,r){let n;if(Array.isArray(i))n=Tt.fromArray(i);else if(typeof i=="string"){let d=e;if(!d){let c=Tt.rawSplit(i);d=lt.getBestVersionForData(c,t)}n=Tt.fromString(i,d||40)}else throw new Error("Invalid data");let s=lt.getBestVersionForData(n,t);if(!s)throw new Error("The amount of data is too big to be stored in a QR Code");if(!e)e=s;else if(e<s)throw new Error(`
6
+ The chosen QR Code version cannot contain this amount of data.
7
+ Minimum version required to store current data is: `+s+`.
8
+ `);let o=Fr(e,t,n),a=dt.getSymbolSize(e),l=new Ar(a);return qr(l,e),Nr(l),Ur(l,e),Mt(l,t,0),e>=7&&Dr(l,e),Lr(l,o),isNaN(r)&&(r=Rt.getBestMask(l,Mt.bind(null,l,t))),Rt.applyMask(r,l),Mt(l,t,r),{modules:l,version:e,errorCorrectionLevel:t,maskPattern:r,segments:n}}Pe.create=function(e,t){if(typeof e>"u"||e==="")throw new Error("No input text");let r=Bt.M,n,s;return typeof t<"u"&&(r=Bt.from(t.errorCorrectionLevel,Bt.M),n=lt.from(t.version),s=Rt.from(t.maskPattern),t.toSJISFunc&&dt.setToSJISFunction(t.toSJISFunc)),zr(e,n,r,s)}});var qt=g(P=>{function Ne(i){if(typeof i=="number"&&(i=i.toString()),typeof i!="string")throw new Error("Color should be defined as hex string");let e=i.slice().replace("#","").split("");if(e.length<3||e.length===5||e.length>8)throw new Error("Invalid hex color: "+i);(e.length===3||e.length===4)&&(e=Array.prototype.concat.apply([],e.map(function(r){return[r,r]}))),e.length===6&&e.push("F","F");let t=parseInt(e.join(""),16);return{r:t>>24&255,g:t>>16&255,b:t>>8&255,a:t&255,hex:"#"+e.slice(0,6).join("")}}P.getOptions=function(e){e||(e={}),e.color||(e.color={});let t=typeof e.margin>"u"||e.margin===null||e.margin<0?4:e.margin,r=e.width&&e.width>=21?e.width:void 0,n=e.scale||4;return{width:r,scale:r?4:n,margin:t,color:{dark:Ne(e.color.dark||"#000000ff"),light:Ne(e.color.light||"#ffffffff")},type:e.type,rendererOpts:e.rendererOpts||{}}};P.getScale=function(e,t){return t.width&&t.width>=e+t.margin*2?t.width/(e+t.margin*2):t.scale};P.getImageWidth=function(e,t){let r=P.getScale(e,t);return Math.floor((e+t.margin*2)*r)};P.qrToImageData=function(e,t,r){let n=t.modules.size,s=t.modules.data,o=P.getScale(n,r),a=Math.floor((n+r.margin*2)*o),l=r.margin*o,d=[r.color.light,r.color.dark];for(let c=0;c<a;c++)for(let u=0;u<a;u++){let f=(c*a+u)*4,x=r.color.light;if(c>=l&&u>=l&&c<a-l&&u<a-l){let k=Math.floor((c-l)/o),S=Math.floor((u-l)/o);x=d[s[k*n+S]?1:0]}e[f++]=x.r,e[f++]=x.g,e[f++]=x.b,e[f]=x.a}}});var Ue=g(ct=>{var Nt=qt();function Vr(i,e,t){i.clearRect(0,0,e.width,e.height),e.style||(e.style={}),e.height=t,e.width=t,e.style.height=t+"px",e.style.width=t+"px"}function Qr(){try{return document.createElement("canvas")}catch{throw new Error("You need to specify a canvas element")}}ct.render=function(e,t,r){let n=r,s=t;typeof n>"u"&&(!t||!t.getContext)&&(n=t,t=void 0),t||(s=Qr()),n=Nt.getOptions(n);let o=Nt.getImageWidth(e.modules.size,n),a=s.getContext("2d"),l=a.createImageData(o,o);return Nt.qrToImageData(l.data,e,n),Vr(a,s,o),a.putImageData(l,0,0),s};ct.renderToDataURL=function(e,t,r){let n=r;typeof n>"u"&&(!t||!t.getContext)&&(n=t,t=void 0),n||(n={});let s=ct.render(e,t,n),o=n.type||"image/png",a=n.rendererOpts||{};return s.toDataURL(o,a.quality)}});var Fe=g(Le=>{var Hr=qt();function De(i,e){let t=i.a/255,r=e+'="'+i.hex+'"';return t<1?r+" "+e+'-opacity="'+t.toFixed(2).slice(1)+'"':r}function Ut(i,e,t){let r=i+e;return typeof t<"u"&&(r+=" "+t),r}function jr(i,e,t){let r="",n=0,s=!1,o=0;for(let a=0;a<i.length;a++){let l=Math.floor(a%e),d=Math.floor(a/e);!l&&!s&&(s=!0),i[a]?(o++,a>0&&l>0&&i[a-1]||(r+=s?Ut("M",l+t,.5+d+t):Ut("m",n,0),n=0,s=!1),l+1<e&&i[a+1]||(r+=Ut("h",o),o=0)):n++}return r}Le.render=function(e,t,r){let n=Hr.getOptions(t),s=e.modules.size,o=e.modules.data,a=s+n.margin*2,l=n.color.light.a?"<path "+De(n.color.light,"fill")+' d="M0 0h'+a+"v"+a+'H0z"/>':"",d="<path "+De(n.color.dark,"stroke")+' d="'+jr(o,s,n.margin)+'"/>',c='viewBox="0 0 '+a+" "+a+'"',f='<svg xmlns="http://www.w3.org/2000/svg" '+(n.width?'width="'+n.width+'" height="'+n.width+'" ':"")+c+' shape-rendering="crispEdges">'+l+d+`</svg>
9
+ `;return typeof r=="function"&&r(null,f),f}});var ze=g(X=>{var Or=Qt(),Dt=qe(),$e=Ue(),Kr=Fe();function Lt(i,e,t,r,n){let s=[].slice.call(arguments,1),o=s.length,a=typeof s[o-1]=="function";if(!a&&!Or())throw new Error("Callback required as last argument");if(a){if(o<2)throw new Error("Too few arguments provided");o===2?(n=t,t=e,e=r=void 0):o===3&&(e.getContext&&typeof n>"u"?(n=r,r=void 0):(n=r,r=t,t=e,e=void 0))}else{if(o<1)throw new Error("Too few arguments provided");return o===1?(t=e,e=r=void 0):o===2&&!e.getContext&&(r=t,t=e,e=void 0),new Promise(function(l,d){try{let c=Dt.create(t,r);l(i(c,e,r))}catch(c){d(c)}})}try{let l=Dt.create(t,r);n(null,i(l,e,r))}catch(l){n(l)}}X.create=Dt.create;X.toCanvas=Lt.bind(null,$e.render);X.toDataURL=Lt.bind(null,$e.renderToDataURL);X.toString=Lt.bind(null,function(i,e,t){return Kr.render(i,t)})});var Wr={};We(Wr,{QRAuthElement:()=>y,QRAuthEphemeral:()=>W,QRAuthLogin:()=>J,QRAuthTwoFA:()=>Z});var y=class extends HTMLElement{constructor(){super();p(this,"shadow");p(this,"_sseConnection",null);p(this,"_pollInterval",null);this.shadow=this.attachShadow({mode:"open"})}static get observedAttributes(){return["tenant","theme","base-url","force-mode","mobile-fallback-only"]}get tenant(){return this.getAttribute("tenant")||""}get theme(){return this.getAttribute("theme")||"light"}get baseUrl(){let t=this.getAttribute("base-url");return t!==null?t:"https://qrauth.io"}connectedCallback(){this.render()}disconnectedCallback(){this.cleanup()}attributeChangedCallback(t,r,n){r!==n&&this.render()}isMobileLike(){if(typeof window>"u")return!1;let t=this.getAttribute("force-mode");if(t==="mobile")return!0;if(t==="desktop"||this.hasAttribute("mobile-fallback-only"))return!1;if(typeof window.matchMedia=="function"){let r=window.matchMedia("(pointer: coarse)").matches,n=window.matchMedia("(hover: none)").matches;if(r&&n)return!0}return/Android|iPhone|iPad|iPod|Mobile|Tablet|BlackBerry|Opera Mini/i.test(navigator.userAgent)}connectSSE(t){this.disconnectSSE(),this._sseConnection=new EventSource(t),this._sseConnection.onerror=()=>{this.disconnectSSE()}}onSSEEvent(t,r){this._sseConnection&&this._sseConnection.addEventListener(t,n=>{let s=n;try{r(JSON.parse(s.data))}catch{}})}disconnectSSE(){this._sseConnection&&(this._sseConnection.close(),this._sseConnection=null)}startPolling(t,r,n,s){this.stopPolling();let o=async()=>{try{let a=await fetch(t,{headers:s});a.ok&&n(await a.json())}catch{}};o(),this._pollInterval=setInterval(o,r)}stopPolling(){this._pollInterval&&(clearInterval(this._pollInterval),this._pollInterval=null)}cleanup(){this.disconnectSSE(),this.stopPolling()}emit(t,r){this.dispatchEvent(new CustomEvent(t,{bubbles:!0,composed:!0,detail:r}))}async generateCodeVerifier(){let t=new Uint8Array(32);return crypto.getRandomValues(t),this._base64url(t)}async computeCodeChallenge(t){let n=new TextEncoder().encode(t),s=await crypto.subtle.digest("SHA-256",n);return this._base64url(new Uint8Array(s))}_base64url(t){let r=Array.from(t,n=>String.fromCodePoint(n)).join("");return btoa(r).replace(/\+/g,"-").replace(/\//g,"_").replace(/=+$/,"")}getBaseStyles(){return`
3
10
  :host {
4
11
  display: inline-block;
5
12
  font-family: var(--qrauth-font, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif);
@@ -30,7 +37,7 @@
30
37
  --_btn-hover: var(--qrauth-btn-hover, #2e4578);
31
38
  }
32
39
  * { box-sizing: border-box; margin: 0; padding: 0; }
33
- `}};var u=`<svg viewBox="0 0 200 200" xmlns="http://www.w3.org/2000/svg" aria-hidden="true">
40
+ `}};var Ve=Ze(ze(),1);function $(i,e=440){if(!i)return"";let t=Math.max(1,Math.floor(Number.isFinite(e)?e:440)),r;try{r=Ve.default.create(i,{errorCorrectionLevel:"M"})}catch{return""}let n=r.modules,s=4,o=n.size+s*2,a=t/o,l="";for(let d=0;d<n.size;d++)for(let c=0;c<n.size;c++)if(n.data[d*n.size+c]){let u=(c+s)*a,f=(d+s)*a;l+=`<rect x="${u.toFixed(2)}" y="${f.toFixed(2)}" width="${a.toFixed(2)}" height="${a.toFixed(2)}"/>`}return`<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 ${t} ${t}" width="${t}" height="${t}" shape-rendering="crispEdges" role="img" aria-label="QR code"><rect width="100%" height="100%" fill="#ffffff"/><g fill="#000000">${l}</g></svg>`}var G=`<svg viewBox="0 0 200 200" xmlns="http://www.w3.org/2000/svg" aria-hidden="true">
34
41
  <path d="M48 24 H152 Q166 24 166 38 V108 Q166 156 100 182 Q34 156 34 108 V38 Q34 24 48 24 Z"
35
42
  fill="none" stroke="#fff" stroke-width="5"/>
36
43
  <g fill="#fff" opacity="0.2">
@@ -47,12 +54,12 @@
47
54
  <path d="M62 104 L88 134 L144 64"
48
55
  fill="none" stroke="#fff" stroke-width="15"
49
56
  stroke-linecap="round" stroke-linejoin="round"/>
50
- </svg>`,_=`<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" aria-hidden="true">
57
+ </svg>`,Qe=`<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" aria-hidden="true">
51
58
  <path d="M9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41L9 16.17z" fill="currentColor"/>
52
- </svg>`,B=`<svg class="spinner" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" aria-hidden="true">
59
+ </svg>`,Yr=`<svg class="spinner" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" aria-hidden="true">
53
60
  <circle cx="12" cy="12" r="10" fill="none" stroke="currentColor" stroke-width="2.5"
54
61
  stroke-dasharray="31.416" stroke-dashoffset="10" stroke-linecap="round"/>
55
- </svg>`,g=class extends p{constructor(){super(...arguments);n(this,"_sessionId",null);n(this,"_sessionToken",null);n(this,"_codeVerifier",null);n(this,"_status","idle");n(this,"_expiresAt",null);n(this,"_timerInterval",null);n(this,"_pollTimeout",null)}static get observedAttributes(){return[...super.observedAttributes,"scopes","redirect-url","on-auth","display","animated","redirect-uri"]}get scopes(){return this.getAttribute("scopes")||"identity"}get redirectUrl(){return this.getAttribute("redirect-url")}get onAuth(){return this.getAttribute("on-auth")}get display(){return this.getAttribute("display")||"button"}get animated(){return this.hasAttribute("animated")}get redirectUri(){return this.getAttribute("redirect-uri")}get forceMode(){let t=this.getAttribute("force-mode");return t==="mobile"||t==="desktop"?t:"auto"}get mobileFallbackOnly(){return this.hasAttribute("mobile-fallback-only")}disconnectedCallback(){super.disconnectedCallback(),this._clearTimers()}render(){this.display==="inline"?this._renderInline():this._renderButton()}_renderButton(){this.shadow.innerHTML=`
62
+ </svg>`,J=class extends y{constructor(){super(...arguments);p(this,"_sessionId",null);p(this,"_sessionToken",null);p(this,"_codeVerifier",null);p(this,"_status","idle");p(this,"_expiresAt",null);p(this,"_currentQrUrl",null);p(this,"_timerInterval",null);p(this,"_pollTimeout",null)}static get observedAttributes(){return[...super.observedAttributes,"scopes","redirect-url","on-auth","display","animated","redirect-uri"]}get scopes(){return this.getAttribute("scopes")||"identity"}get redirectUrl(){return this.getAttribute("redirect-url")}get onAuth(){return this.getAttribute("on-auth")}get display(){return this.getAttribute("display")||"button"}get animated(){return this.hasAttribute("animated")}get redirectUri(){return this.getAttribute("redirect-uri")}get forceMode(){let t=this.getAttribute("force-mode");return t==="mobile"||t==="desktop"?t:"auto"}get mobileFallbackOnly(){return this.hasAttribute("mobile-fallback-only")}disconnectedCallback(){super.disconnectedCallback(),this._clearTimers()}render(){this.display==="inline"?this._renderInline():this._renderButton()}_renderButton(){this.shadow.innerHTML=`
56
63
  <style>
57
64
  ${this.getBaseStyles()}
58
65
  :host { display: inline-block; }
@@ -118,7 +125,7 @@
118
125
  </style>
119
126
 
120
127
  <button class="btn" id="open-btn" aria-label="Sign in with QRAuth">
121
- <span class="btn-icon">${u}</span>
128
+ <span class="btn-icon">${G}</span>
122
129
  Sign in with QRAuth
123
130
  </button>
124
131
 
@@ -177,7 +184,7 @@
177
184
  </div>
178
185
  `,this._bindInlineEvents()}_inlineIdleContent(){return`
179
186
  <button class="start-btn" id="start-btn" aria-label="Sign in with QRAuth">
180
- <span class="btn-icon">${u}</span>
187
+ <span class="btn-icon">${G}</span>
181
188
  Sign in with QRAuth
182
189
  </button>
183
190
  `}_modalContent(){return`
@@ -185,29 +192,29 @@
185
192
  <div id="modal-body">
186
193
  ${this._bodyForStatus("idle")}
187
194
  </div>
188
- `}_bodyForStatus(t,e){switch(t){case"idle":return`
195
+ `}_bodyForStatus(t,r){switch(t){case"idle":return`
189
196
  <div class="state-header">
190
- <div class="brand-icon">${u}</div>
197
+ <div class="brand-icon">${G}</div>
191
198
  <h3>Sign in with QRAuth</h3>
192
199
  <p>Secure, passwordless authentication</p>
193
200
  </div>
194
201
  `;case"loading":return`
195
202
  <div class="state-loading">
196
- <div class="spinner-wrap">${B}</div>
203
+ <div class="spinner-wrap">${Yr}</div>
197
204
  <p class="status-text">Generating QR code...</p>
198
205
  </div>
199
- `;case"pending":case"SCANNED":{if(this.isMobileLike())return this._mobilePendingBody(t,e);let i=t==="SCANNED";return`
206
+ `;case"pending":case"SCANNED":{if(this.isMobileLike())return this._mobilePendingBody(t,r);let n=t==="SCANNED";return`
200
207
  <h3>Sign in with QRAuth</h3>
201
208
  <p class="subtitle">Scan this QR code with your phone camera</p>
202
- ${this._qrFrameHtml(e?.qrUrl??"",i)}
203
- <div class="status-text ${i?"status-scanned":""}">
204
- ${i?"&#10003; QR code scanned &mdash; waiting for approval...":"Waiting for scan..."}
209
+ ${this._qrFrameHtml(r?.qrUrl??"",n)}
210
+ <div class="status-text ${n?"status-scanned":""}">
211
+ ${n?"&#10003; QR code scanned &mdash; waiting for approval...":"Waiting for scan..."}
205
212
  </div>
206
- <div class="timer" id="timer">${e?.timerHtml??""}</div>
213
+ <div class="timer" id="timer">${r?.timerHtml??""}</div>
207
214
  <div class="footer">Secured by <a href="https://qrauth.io" target="_blank" rel="noopener">QRAuth</a></div>
208
215
  `}case"APPROVED":return`
209
216
  <div class="state-approved">
210
- <div class="success-icon">${_}</div>
217
+ <div class="success-icon">${Qe}</div>
211
218
  <h3>Identity verified!</h3>
212
219
  <p class="subtitle">You are now signed in</p>
213
220
  </div>
@@ -229,29 +236,29 @@
229
236
  <div class="state-error">
230
237
  <div class="error-icon">&#9888;</div>
231
238
  <h3>Something went wrong</h3>
232
- <p class="subtitle">${e?.errorMessage??"Failed to start authentication."}</p>
239
+ <p class="subtitle">${r?.errorMessage??"Failed to start authentication."}</p>
233
240
  <button class="retry-btn" id="retry-btn">Try again</button>
234
241
  </div>
235
- `;default:return""}}_qrFrameHtml(t,e){let i=t?`https://api.qrserver.com/v1/create-qr-code/?size=440x440&data=${encodeURIComponent(t)}`:"";return`
236
- <div class="qr-frame ${e?"scanned":""}${this.animated?" animated":""}">
237
- <img src="${i}" alt="QR Code for authentication" width="220" height="220" loading="lazy"/>
238
- <div class="qr-badge">${u}</div>
239
- ${e?'<div class="scanned-overlay"><span class="scanned-check">'+_+"</span></div>":""}
242
+ `;default:return""}}_qrFrameHtml(t,r){let n=$(t,440);return`
243
+ <div class="qr-frame ${r?"scanned":""}${this.animated?" animated":""}">
244
+ <div class="qr-image" role="img" aria-label="QR Code for authentication">${n}</div>
245
+ <div class="qr-badge">${G}</div>
246
+ ${r?'<div class="scanned-overlay"><span class="scanned-check">'+Qe+"</span></div>":""}
240
247
  </div>
241
- `}_mobilePendingBody(t,e){let i=t==="SCANNED";return`
248
+ `}_mobilePendingBody(t,r){let n=t==="SCANNED";return`
242
249
  <h3>Sign in with QRAuth</h3>
243
250
  <p class="subtitle">Tap continue to verify on this device.</p>
244
251
  <button class="mobile-cta" id="mobile-cta" type="button">
245
- <span class="btn-icon">${u}</span>
252
+ <span class="btn-icon">${G}</span>
246
253
  Continue with QRAuth
247
254
  </button>
248
- <div class="status-text ${i?"status-scanned":""}">
249
- ${i?"&#10003; Scanned &mdash; waiting for approval...":"Waiting for approval..."}
255
+ <div class="status-text ${n?"status-scanned":""}">
256
+ ${n?"&#10003; Scanned &mdash; waiting for approval...":"Waiting for approval..."}
250
257
  </div>
251
- <div class="timer" id="timer">${e?.timerHtml??""}</div>
258
+ <div class="timer" id="timer">${r?.timerHtml??""}</div>
252
259
  <details class="alt-device">
253
260
  <summary>Use another device</summary>
254
- ${this._qrFrameHtml(e?.qrUrl??"",i)}
261
+ ${this._qrFrameHtml(r?.qrUrl??"",n)}
255
262
  </details>
256
263
  <div class="footer">Secured by <a href="https://qrauth.io" target="_blank" rel="noopener">QRAuth</a></div>
257
264
  `}_sharedModalStyles(){return`
@@ -335,7 +342,8 @@
335
342
  0%, 100% { box-shadow: 0 0 0 0 rgba(0,167,111,0); }
336
343
  50% { box-shadow: 0 0 0 8px rgba(0,167,111,0.15); }
337
344
  }
338
- .qr-frame img { display: block; width: 220px; height: 220px; border-radius: 4px; }
345
+ .qr-frame .qr-image { display: block; width: 220px; height: 220px; border-radius: 4px; overflow: hidden; }
346
+ .qr-frame .qr-image svg { display: block; width: 100%; height: 100%; }
339
347
  .qr-badge {
340
348
  position: absolute;
341
349
  top: 50%;
@@ -506,7 +514,7 @@
506
514
  }
507
515
  .footer a { color: var(--_disabled); text-decoration: none; }
508
516
  .footer a:hover { text-decoration: underline; }
509
- `}_bindButtonEvents(){this.shadow.getElementById("open-btn")?.addEventListener("click",()=>{this._openModal(),this._startAuth()});let e=this.shadow.getElementById("overlay");e?.addEventListener("click",i=>{i.target===e&&this._closeModal()}),this._bindModalButtons()}_bindInlineEvents(){this.shadow.getElementById("start-btn")?.addEventListener("click",()=>{this._startAuth()})}_bindModalButtons(){this.shadow.getElementById("close-btn")?.addEventListener("click",()=>this._closeModal()),this.shadow.getElementById("retry-btn")?.addEventListener("click",()=>this._retry()),this.shadow.getElementById("mobile-cta")?.addEventListener("click",()=>this._openApprovalPage())}_openApprovalPage(){if(!this._sessionToken)return;let t=`${this.baseUrl}/a/${this._sessionToken}`;window.open(t,"_blank","noopener")||(window.location.href=t)}_openModal(){this.shadow.getElementById("overlay")?.classList.remove("hidden"),this._updateBody(this._bodyForStatus("idle"))}_closeModal(){this.shadow.getElementById("overlay")?.classList.add("hidden"),this._clearTimers(),this._sessionId=null,this._sessionToken=null,this._codeVerifier=null,this._status="idle",this._expiresAt=null}async _startAuth(){this._status="loading",this._updateBody(this._bodyForStatus("loading"));try{this._codeVerifier=await this.generateCodeVerifier();let t=await this.computeCodeChallenge(this._codeVerifier),e={"Content-Type":"application/json","X-Client-Id":this.tenant},i={scopes:this.scopes.split(/\s+/).filter(Boolean),codeChallenge:t,codeChallengeMethod:"S256"};this.redirectUri&&(i.redirectUrl=this.redirectUri);let r=await fetch(`${this.baseUrl}/api/v1/auth-sessions`,{method:"POST",headers:e,body:JSON.stringify(i)});if(!r.ok){let d=await r.json().catch(()=>({message:"Failed to create session"}));throw new Error(d.message??"Failed to create session")}let s=await r.json();this._sessionId=s.sessionId,this._sessionToken=s.token||(s.qrUrl?s.qrUrl.split("/").pop()??null:null),this._expiresAt=new Date(s.expiresAt).getTime(),this._status="pending",this._updateBody(this._bodyForStatus("pending",{qrUrl:s.qrUrl})),this._bindModalButtons(),this._startCountdown(),this._beginPolling(s.sessionId)}catch(t){let e=t instanceof Error?t.message:"Unexpected error";this._status="error",this._updateBody(this._bodyForStatus("error",{errorMessage:e})),this._bindModalButtons(),this.emit("qrauth:error",{message:e})}}_retry(){if(this._clearTimers(),this._sessionId=null,this._sessionToken=null,this._codeVerifier=null,this._status="idle",this._expiresAt=null,this.display==="inline"){let t=this.shadow.getElementById("inline-body");t&&(t.innerHTML=this._inlineIdleContent(),this._bindInlineEvents())}else this._startAuth()}_beginPolling(t){let e="PENDING",i=2e3,r=5e3,s=0,d=20,h=async()=>{if(!this._sessionId)return;let l=`${this.baseUrl}/api/v1/auth-sessions/${t}`;this._codeVerifier&&(l+=`?code_verifier=${encodeURIComponent(this._codeVerifier)}`);try{let c=await(await fetch(l,{headers:{"X-Client-Id":this.tenant}})).json();if(s=0,i=2e3,c.status!==e&&(e=c.status,this._handleStatusChange(c.status,c),["APPROVED","DENIED","EXPIRED"].includes(c.status)))return;this._pollTimeout=setTimeout(h,i)}catch{if(s++,s>=d){this._handleStatusChange("EXPIRED",void 0);return}i=Math.min(i*1.5,r),this._pollTimeout=setTimeout(h,i)}};this._pollTimeout=setTimeout(h,i)}_handleStatusChange(t,e){switch(this._status=t,t){case"SCANNED":{let i=this.shadow.querySelector(".qr-frame img")?.src,r=i?decodeURIComponent(i.replace(/.*[?&]data=/,"").split("&")[0]):"";this._updateBody(this._bodyForStatus("SCANNED",{qrUrl:r,timerHtml:this._formatTimer()})),this._bindModalButtons(),this.emit("qrauth:scanned",e);break}case"APPROVED":{this._clearTimers(),this._updateBody(this._bodyForStatus("APPROVED")),this._bindModalButtons(),this.emit("qrauth:authenticated",{sessionId:e?.sessionId,user:e?.user,signature:e?.signature});let i=this.onAuth;if(i){let r=window[i];typeof r=="function"&&r(e)}this.redirectUrl?setTimeout(()=>{window.location.href=this.redirectUrl},1500):this.display==="button"&&setTimeout(()=>this._closeModal(),2200);break}case"DENIED":this._clearTimers(),this._updateBody(this._bodyForStatus("DENIED")),this._bindModalButtons(),this.emit("qrauth:denied");break;case"EXPIRED":this._clearTimers(),this._status="EXPIRED",this._updateBody(this._bodyForStatus("EXPIRED")),this._bindModalButtons(),this.emit("qrauth:expired");break}}_startCountdown(){this._timerInterval=setInterval(()=>{let t=this.shadow.getElementById("timer");if(!t||!this._expiresAt)return;let e=Math.max(0,Math.floor((this._expiresAt-Date.now())/1e3));t.textContent=e>0?this._formatTimer(e):"",e<=0&&(clearInterval(this._timerInterval),this._timerInterval=null,(this._status==="pending"||this._status==="SCANNED")&&this._handleStatusChange("EXPIRED",void 0))},1e3)}_formatTimer(t){let e=t??(this._expiresAt?Math.max(0,Math.floor((this._expiresAt-Date.now())/1e3)):0),i=Math.floor(e/60),r=e%60;return`Expires in ${i}:${r<10?"0":""}${r}`}_updateBody(t){let e=this.display==="inline"?this.shadow.getElementById("inline-body"):this.shadow.getElementById("modal-body");e&&(e.innerHTML=t)}_clearTimers(){this._timerInterval&&(clearInterval(this._timerInterval),this._timerInterval=null),this._pollTimeout&&(clearTimeout(this._pollTimeout),this._pollTimeout=null)}};customElements.define("qrauth-login",g);var x=`<svg viewBox="0 0 200 200" xmlns="http://www.w3.org/2000/svg" aria-hidden="true">
517
+ `}_bindButtonEvents(){this.shadow.getElementById("open-btn")?.addEventListener("click",()=>{this._openModal(),this._startAuth()});let r=this.shadow.getElementById("overlay");r?.addEventListener("click",n=>{n.target===r&&this._closeModal()}),this._bindModalButtons()}_bindInlineEvents(){this.shadow.getElementById("start-btn")?.addEventListener("click",()=>{this._startAuth()})}_bindModalButtons(){this.shadow.getElementById("close-btn")?.addEventListener("click",()=>this._closeModal()),this.shadow.getElementById("retry-btn")?.addEventListener("click",()=>this._retry()),this.shadow.getElementById("mobile-cta")?.addEventListener("click",()=>this._openApprovalPage())}_openApprovalPage(){if(!this._sessionToken)return;let t=new URL(`${this.baseUrl}/a/${this._sessionToken}`);t.searchParams.set("dr","1");let r=t.toString();window.open(r,"_blank","noopener")||(window.location.href=r)}_openModal(){this.shadow.getElementById("overlay")?.classList.remove("hidden"),this._updateBody(this._bodyForStatus("idle"))}_closeModal(){this.shadow.getElementById("overlay")?.classList.add("hidden"),this._clearTimers(),this._sessionId=null,this._sessionToken=null,this._codeVerifier=null,this._status="idle",this._expiresAt=null,this._currentQrUrl=null}async _startAuth(){this._status="loading",this._updateBody(this._bodyForStatus("loading"));try{this._codeVerifier=await this.generateCodeVerifier();let t=await this.computeCodeChallenge(this._codeVerifier),r={"Content-Type":"application/json","X-Client-Id":this.tenant},n={scopes:this.scopes.split(/\s+/).filter(Boolean),codeChallenge:t,codeChallengeMethod:"S256"};this.redirectUri&&(n.redirectUrl=this.redirectUri);let s=await fetch(`${this.baseUrl}/api/v1/auth-sessions`,{method:"POST",headers:r,body:JSON.stringify(n)});if(!s.ok){let a=await s.json().catch(()=>({message:"Failed to create session"}));throw new Error(a.message??"Failed to create session")}let o=await s.json();this._sessionId=o.sessionId,this._sessionToken=o.token||(o.qrUrl?o.qrUrl.split("/").pop()??null:null),this._expiresAt=new Date(o.expiresAt).getTime(),this._currentQrUrl=o.qrUrl??null,this._status="pending",this._updateBody(this._bodyForStatus("pending",{qrUrl:o.qrUrl})),this._bindModalButtons(),this._startCountdown(),this._beginPolling(o.sessionId)}catch(t){let r=t instanceof Error?t.message:"Unexpected error";this._status="error",this._updateBody(this._bodyForStatus("error",{errorMessage:r})),this._bindModalButtons(),this.emit("qrauth:error",{message:r})}}_retry(){if(this._clearTimers(),this._sessionId=null,this._sessionToken=null,this._codeVerifier=null,this._status="idle",this._expiresAt=null,this._currentQrUrl=null,this.display==="inline"){let t=this.shadow.getElementById("inline-body");t&&(t.innerHTML=this._inlineIdleContent(),this._bindInlineEvents())}else this._startAuth()}_beginPolling(t){let r="PENDING",n=2e3,s=5e3,o=0,a=20,l=async()=>{if(!this._sessionId)return;let d=`${this.baseUrl}/api/v1/auth-sessions/${t}`;this._codeVerifier&&(d+=`?code_verifier=${encodeURIComponent(this._codeVerifier)}`);try{let u=await(await fetch(d,{headers:{"X-Client-Id":this.tenant}})).json();if(o=0,n=2e3,u.status!==r&&(r=u.status,this._handleStatusChange(u.status,u),["APPROVED","DENIED","EXPIRED"].includes(u.status)))return;this._pollTimeout=setTimeout(l,n)}catch{if(o++,o>=a){this._handleStatusChange("EXPIRED",void 0);return}n=Math.min(n*1.5,s),this._pollTimeout=setTimeout(l,n)}};this._pollTimeout=setTimeout(l,n)}_handleStatusChange(t,r){switch(this._status=t,t){case"SCANNED":{this._updateBody(this._bodyForStatus("SCANNED",{qrUrl:this._currentQrUrl??"",timerHtml:this._formatTimer()})),this._bindModalButtons(),this.emit("qrauth:scanned",r);break}case"APPROVED":{this._clearTimers(),this._updateBody(this._bodyForStatus("APPROVED")),this._bindModalButtons(),this.emit("qrauth:authenticated",{sessionId:r?.sessionId,user:r?.user,signature:r?.signature});let n=this.onAuth;if(n){let s=window[n];typeof s=="function"&&s(r)}this.redirectUrl?setTimeout(()=>{window.location.href=this.redirectUrl},1500):this.display==="button"&&setTimeout(()=>this._closeModal(),2200);break}case"DENIED":this._clearTimers(),this._updateBody(this._bodyForStatus("DENIED")),this._bindModalButtons(),this.emit("qrauth:denied");break;case"EXPIRED":this._clearTimers(),this._status="EXPIRED",this._updateBody(this._bodyForStatus("EXPIRED")),this._bindModalButtons(),this.emit("qrauth:expired");break}}_startCountdown(){this._timerInterval=setInterval(()=>{let t=this.shadow.getElementById("timer");if(!t||!this._expiresAt)return;let r=Math.max(0,Math.floor((this._expiresAt-Date.now())/1e3));t.textContent=r>0?this._formatTimer(r):"",r<=0&&(clearInterval(this._timerInterval),this._timerInterval=null,(this._status==="pending"||this._status==="SCANNED")&&this._handleStatusChange("EXPIRED",void 0))},1e3)}_formatTimer(t){let r=t??(this._expiresAt?Math.max(0,Math.floor((this._expiresAt-Date.now())/1e3)):0),n=Math.floor(r/60),s=r%60;return`Expires in ${n}:${s<10?"0":""}${s}`}_updateBody(t){let r=this.display==="inline"?this.shadow.getElementById("inline-body"):this.shadow.getElementById("modal-body");r&&(r.innerHTML=t)}_clearTimers(){this._timerInterval&&(clearInterval(this._timerInterval),this._timerInterval=null),this._pollTimeout&&(clearTimeout(this._pollTimeout),this._pollTimeout=null)}};customElements.define("qrauth-login",J);var ut=`<svg viewBox="0 0 200 200" xmlns="http://www.w3.org/2000/svg" aria-hidden="true">
510
518
  <path d="M48 24 H152 Q166 24 166 38 V108 Q166 156 100 182 Q34 156 34 108 V38 Q34 24 48 24 Z"
511
519
  fill="none" stroke="#fff" stroke-width="5"/>
512
520
  <g fill="#fff" opacity="0.2">
@@ -523,12 +531,12 @@
523
531
  <path d="M62 104 L88 134 L144 64"
524
532
  fill="none" stroke="#fff" stroke-width="15"
525
533
  stroke-linecap="round" stroke-linejoin="round"/>
526
- </svg>`,R=`<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" aria-hidden="true">
534
+ </svg>`,Xr=`<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" aria-hidden="true">
527
535
  <path d="M9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41L9 16.17z" fill="currentColor"/>
528
- </svg>`,M=`<svg class="spinner" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" aria-hidden="true">
536
+ </svg>`,Gr=`<svg class="spinner" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" aria-hidden="true">
529
537
  <circle cx="12" cy="12" r="10" fill="none" stroke="currentColor" stroke-width="2.5"
530
538
  stroke-dasharray="31.416" stroke-dashoffset="10" stroke-linecap="round"/>
531
- </svg>`,b=class extends p{constructor(){super(...arguments);n(this,"_sessionId",null);n(this,"_claimUrl",null);n(this,"_status","idle");n(this,"_expiresAt",null);n(this,"_timerInterval",null);n(this,"_pollTimeout",null)}static get observedAttributes(){return[...super.observedAttributes,"scopes","ttl","max-uses","device-binding","display"]}get scopes(){return this.getAttribute("scopes")||"access"}get ttl(){return this.getAttribute("ttl")||"30m"}get maxUses(){return parseInt(this.getAttribute("max-uses")||"1",10)}get deviceBinding(){return this.hasAttribute("device-binding")}get display(){return this.getAttribute("display")||"inline"}get forceMode(){let t=this.getAttribute("force-mode");return t==="mobile"||t==="desktop"?t:"auto"}get mobileFallbackOnly(){return this.hasAttribute("mobile-fallback-only")}disconnectedCallback(){super.disconnectedCallback(),this._clearTimers()}render(){this.display==="button"?this._renderButton():this._renderInline()}_renderButton(){this.shadow.innerHTML=`
539
+ </svg>`,W=class extends y{constructor(){super(...arguments);p(this,"_sessionId",null);p(this,"_claimUrl",null);p(this,"_status","idle");p(this,"_expiresAt",null);p(this,"_timerInterval",null);p(this,"_pollTimeout",null)}static get observedAttributes(){return[...super.observedAttributes,"scopes","ttl","max-uses","device-binding","display"]}get scopes(){return this.getAttribute("scopes")||"access"}get ttl(){return this.getAttribute("ttl")||"30m"}get maxUses(){return parseInt(this.getAttribute("max-uses")||"1",10)}get deviceBinding(){return this.hasAttribute("device-binding")}get display(){return this.getAttribute("display")||"inline"}get forceMode(){let t=this.getAttribute("force-mode");return t==="mobile"||t==="desktop"?t:"auto"}get mobileFallbackOnly(){return this.hasAttribute("mobile-fallback-only")}disconnectedCallback(){super.disconnectedCallback(),this._clearTimers()}render(){this.display==="button"?this._renderButton():this._renderInline()}_renderButton(){this.shadow.innerHTML=`
532
540
  <style>
533
541
  ${this.getBaseStyles()}
534
542
  :host { display: inline-block; }
@@ -594,7 +602,7 @@
594
602
  </style>
595
603
 
596
604
  <button class="btn" id="open-btn" aria-label="Get access QR code">
597
- <span class="btn-icon">${x}</span>
605
+ <span class="btn-icon">${ut}</span>
598
606
  Get Access QR
599
607
  </button>
600
608
 
@@ -653,7 +661,7 @@
653
661
  </div>
654
662
  `,this._bindInlineEvents()}_inlineIdleContent(){return`
655
663
  <button class="start-btn" id="start-btn" aria-label="Get access QR code">
656
- <span class="btn-icon">${x}</span>
664
+ <span class="btn-icon">${ut}</span>
657
665
  Get Access QR
658
666
  </button>
659
667
  `}_modalContent(){return`
@@ -661,30 +669,30 @@
661
669
  <div id="modal-body">
662
670
  ${this._bodyForStatus("idle")}
663
671
  </div>
664
- `}_bodyForStatus(t,e){switch(t){case"idle":return`
672
+ `}_bodyForStatus(t,r){switch(t){case"idle":return`
665
673
  <div class="state-header">
666
- <div class="brand-icon">${x}</div>
674
+ <div class="brand-icon">${ut}</div>
667
675
  <h3>Ephemeral Access</h3>
668
676
  <p>Scan to claim temporary access</p>
669
677
  </div>
670
678
  `;case"loading":return`
671
679
  <div class="state-loading">
672
- <div class="spinner-wrap">${M}</div>
680
+ <div class="spinner-wrap">${Gr}</div>
673
681
  <p class="status-text">Generating access QR...</p>
674
682
  </div>
675
- `;case"active":{let i=e?.claimUrl?`https://api.qrserver.com/v1/create-qr-code/?size=440x440&data=${encodeURIComponent(e.claimUrl)}`:"",r=e?.useCount??0,s=e?.maxUses??1,h=s>1?`<div class="use-badge">${r}/${s} claimed</div>`:"";return`
683
+ `;case"active":{let n=$(r?.claimUrl??"",440),s=r?.useCount??0,o=r?.maxUses??1,l=o>1?`<div class="use-badge">${s}/${o} claimed</div>`:"";return`
676
684
  <h3>Scan to Access</h3>
677
685
  <p class="subtitle">Present this QR code to gain entry</p>
678
686
  <div class="qr-frame">
679
- <img src="${i}" alt="Ephemeral access QR code" width="220" height="220" loading="lazy"/>
680
- <div class="qr-badge">${x}</div>
687
+ <div class="qr-image" role="img" aria-label="Ephemeral access QR code">${n}</div>
688
+ <div class="qr-badge">${ut}</div>
681
689
  </div>
682
- ${h}
683
- <div class="timer" id="timer">${e?.timerHtml??""}</div>
690
+ ${l}
691
+ <div class="timer" id="timer">${r?.timerHtml??""}</div>
684
692
  <div class="footer">Secured by <a href="https://qrauth.io" target="_blank" rel="noopener">QRAuth</a></div>
685
693
  `}case"CLAIMED":return`
686
694
  <div class="state-claimed">
687
- <div class="success-icon">${R}</div>
695
+ <div class="success-icon">${Xr}</div>
688
696
  <h3>Access granted!</h3>
689
697
  <p class="subtitle">The QR code has been claimed successfully</p>
690
698
  </div>
@@ -705,7 +713,7 @@
705
713
  <div class="state-error">
706
714
  <div class="error-icon">&#9888;</div>
707
715
  <h3>Something went wrong</h3>
708
- <p class="subtitle">${e?.errorMessage??"Failed to create ephemeral session."}</p>
716
+ <p class="subtitle">${r?.errorMessage??"Failed to create ephemeral session."}</p>
709
717
  <button class="retry-btn" id="retry-btn">Try again</button>
710
718
  </div>
711
719
  `;default:return""}}_sharedModalStyles(){return`
@@ -783,7 +791,8 @@
783
791
  position: relative;
784
792
  transition: border-color 0.3s;
785
793
  }
786
- .qr-frame img { display: block; width: 220px; height: 220px; border-radius: 4px; }
794
+ .qr-frame .qr-image { display: block; width: 220px; height: 220px; border-radius: 4px; overflow: hidden; }
795
+ .qr-frame .qr-image svg { display: block; width: 100%; height: 100%; }
787
796
  .qr-badge {
788
797
  position: absolute;
789
798
  top: 50%;
@@ -890,7 +899,7 @@
890
899
  }
891
900
  .footer a { color: var(--_disabled); text-decoration: none; }
892
901
  .footer a:hover { text-decoration: underline; }
893
- `}_bindButtonEvents(){this.shadow.getElementById("open-btn")?.addEventListener("click",()=>{this._openModal(),this._startSession()});let e=this.shadow.getElementById("overlay");e?.addEventListener("click",i=>{i.target===e&&this._closeModal()}),this._bindModalButtons()}_bindInlineEvents(){this.shadow.getElementById("start-btn")?.addEventListener("click",()=>{this._startSession()})}_bindModalButtons(){this.shadow.getElementById("close-btn")?.addEventListener("click",()=>this._closeModal()),this.shadow.getElementById("retry-btn")?.addEventListener("click",()=>this._retry())}_openModal(){this.shadow.getElementById("overlay")?.classList.remove("hidden"),this._updateBody(this._bodyForStatus("idle"))}_closeModal(){this.shadow.getElementById("overlay")?.classList.add("hidden"),this._clearTimers(),this._sessionId=null,this._claimUrl=null,this._status="idle",this._expiresAt=null}async _startSession(){this._status="loading",this._updateBody(this._bodyForStatus("loading"));try{let t=await fetch(`${this.baseUrl}/api/v1/ephemeral`,{method:"POST",headers:{"Content-Type":"application/json","X-Client-Id":this.tenant},body:JSON.stringify({scopes:this.scopes.split(/\s+/).filter(Boolean),ttl:this.ttl,maxUses:this.maxUses,deviceBinding:this.deviceBinding})});if(!t.ok){let i=await t.json().catch(()=>({message:"Failed to create session"}));throw new Error(i.message??"Failed to create session")}let e=await t.json();this._sessionId=e.sessionId,this._claimUrl=e.claimUrl,this._expiresAt=new Date(e.expiresAt).getTime(),this._status="active",this._updateBody(this._bodyForStatus("active",{claimUrl:e.claimUrl,timerHtml:this._formatTimer(),useCount:0,maxUses:e.maxUses})),this._bindModalButtons(),this._startCountdown(),this._beginPolling(e.sessionId)}catch(t){let e=t instanceof Error?t.message:"Unexpected error";this._status="error",this._updateBody(this._bodyForStatus("error",{errorMessage:e})),this._bindModalButtons(),this.emit("qrauth:error",{message:e})}}_retry(){if(this._clearTimers(),this._sessionId=null,this._claimUrl=null,this._status="idle",this._expiresAt=null,this.display==="inline"){let t=this.shadow.getElementById("inline-body");t&&(t.innerHTML=this._inlineIdleContent(),this._bindInlineEvents())}else this._startSession()}_beginPolling(t){let e=2e3,i=5e3,r=0,s=20,d=async()=>{if(this._sessionId)try{let l=await(await fetch(`${this.baseUrl}/api/v1/ephemeral/${t}`,{headers:{"X-Client-Id":this.tenant}})).json();if(r=0,e=2e3,this._handleStatusChange(l.status,l),["CLAIMED","EXPIRED","REVOKED"].includes(l.status)){if(l.status==="CLAIMED"&&l.useCount<l.maxUses){this._updateBody(this._bodyForStatus("active",{claimUrl:this._claimUrl??void 0,timerHtml:this._formatTimer(),useCount:l.useCount,maxUses:l.maxUses})),this._bindModalButtons(),this._pollTimeout=setTimeout(d,e);return}return}this._pollTimeout=setTimeout(d,e)}catch{if(r++,r>=s){this._handleStatusChange("EXPIRED",void 0);return}e=Math.min(e*1.5,i),this._pollTimeout=setTimeout(d,e)}};this._pollTimeout=setTimeout(d,e)}_handleStatusChange(t,e){switch(t){case"CLAIMED":{this._clearTimers(),this._status="CLAIMED",this._updateBody(this._bodyForStatus("CLAIMED")),this._bindModalButtons(),this.emit("qrauth:claimed",{sessionId:e?.sessionId,status:e?.status,scopes:e?.scopes,metadata:e?.metadata,useCount:e?.useCount,maxUses:e?.maxUses}),this.display==="button"&&setTimeout(()=>this._closeModal(),2200);break}case"EXPIRED":this._clearTimers(),this._status="EXPIRED",this._updateBody(this._bodyForStatus("EXPIRED")),this._bindModalButtons(),this.emit("qrauth:expired");break;case"REVOKED":this._clearTimers(),this._status="REVOKED",this._updateBody(this._bodyForStatus("REVOKED")),this._bindModalButtons(),this.emit("qrauth:revoked");break}}_startCountdown(){this._timerInterval=setInterval(()=>{let t=this.shadow.getElementById("timer");if(!t||!this._expiresAt)return;let e=Math.max(0,Math.floor((this._expiresAt-Date.now())/1e3));t.textContent=e>0?this._formatTimer(e):"",e<=0&&(clearInterval(this._timerInterval),this._timerInterval=null,this._status==="active"&&this._handleStatusChange("EXPIRED",void 0))},1e3)}_formatTimer(t){let e=t??(this._expiresAt?Math.max(0,Math.floor((this._expiresAt-Date.now())/1e3)):0),i=Math.floor(e/60),r=e%60;return`Expires in ${i}:${r<10?"0":""}${r}`}_updateBody(t){let e=this.display==="inline"?this.shadow.getElementById("inline-body"):this.shadow.getElementById("modal-body");e&&(e.innerHTML=t)}_clearTimers(){this._timerInterval&&(clearInterval(this._timerInterval),this._timerInterval=null),this._pollTimeout&&(clearTimeout(this._pollTimeout),this._pollTimeout=null)}};customElements.define("qrauth-ephemeral",b);var f=`<svg viewBox="0 0 200 200" xmlns="http://www.w3.org/2000/svg" aria-hidden="true">
902
+ `}_bindButtonEvents(){this.shadow.getElementById("open-btn")?.addEventListener("click",()=>{this._openModal(),this._startSession()});let r=this.shadow.getElementById("overlay");r?.addEventListener("click",n=>{n.target===r&&this._closeModal()}),this._bindModalButtons()}_bindInlineEvents(){this.shadow.getElementById("start-btn")?.addEventListener("click",()=>{this._startSession()})}_bindModalButtons(){this.shadow.getElementById("close-btn")?.addEventListener("click",()=>this._closeModal()),this.shadow.getElementById("retry-btn")?.addEventListener("click",()=>this._retry())}_openModal(){this.shadow.getElementById("overlay")?.classList.remove("hidden"),this._updateBody(this._bodyForStatus("idle"))}_closeModal(){this.shadow.getElementById("overlay")?.classList.add("hidden"),this._clearTimers(),this._sessionId=null,this._claimUrl=null,this._status="idle",this._expiresAt=null}async _startSession(){this._status="loading",this._updateBody(this._bodyForStatus("loading"));try{let t=await fetch(`${this.baseUrl}/api/v1/ephemeral`,{method:"POST",headers:{"Content-Type":"application/json","X-Client-Id":this.tenant},body:JSON.stringify({scopes:this.scopes.split(/\s+/).filter(Boolean),ttl:this.ttl,maxUses:this.maxUses,deviceBinding:this.deviceBinding})});if(!t.ok){let n=await t.json().catch(()=>({message:"Failed to create session"}));throw new Error(n.message??"Failed to create session")}let r=await t.json();this._sessionId=r.sessionId,this._claimUrl=r.claimUrl,this._expiresAt=new Date(r.expiresAt).getTime(),this._status="active",this._updateBody(this._bodyForStatus("active",{claimUrl:r.claimUrl,timerHtml:this._formatTimer(),useCount:0,maxUses:r.maxUses})),this._bindModalButtons(),this._startCountdown(),this._beginPolling(r.sessionId)}catch(t){let r=t instanceof Error?t.message:"Unexpected error";this._status="error",this._updateBody(this._bodyForStatus("error",{errorMessage:r})),this._bindModalButtons(),this.emit("qrauth:error",{message:r})}}_retry(){if(this._clearTimers(),this._sessionId=null,this._claimUrl=null,this._status="idle",this._expiresAt=null,this.display==="inline"){let t=this.shadow.getElementById("inline-body");t&&(t.innerHTML=this._inlineIdleContent(),this._bindInlineEvents())}else this._startSession()}_beginPolling(t){let r=2e3,n=5e3,s=0,o=20,a=async()=>{if(this._sessionId)try{let d=await(await fetch(`${this.baseUrl}/api/v1/ephemeral/${t}`,{headers:{"X-Client-Id":this.tenant}})).json();if(s=0,r=2e3,this._handleStatusChange(d.status,d),["CLAIMED","EXPIRED","REVOKED"].includes(d.status)){if(d.status==="CLAIMED"&&d.useCount<d.maxUses){this._updateBody(this._bodyForStatus("active",{claimUrl:this._claimUrl??void 0,timerHtml:this._formatTimer(),useCount:d.useCount,maxUses:d.maxUses})),this._bindModalButtons(),this._pollTimeout=setTimeout(a,r);return}return}this._pollTimeout=setTimeout(a,r)}catch{if(s++,s>=o){this._handleStatusChange("EXPIRED",void 0);return}r=Math.min(r*1.5,n),this._pollTimeout=setTimeout(a,r)}};this._pollTimeout=setTimeout(a,r)}_handleStatusChange(t,r){switch(t){case"CLAIMED":{this._clearTimers(),this._status="CLAIMED",this._updateBody(this._bodyForStatus("CLAIMED")),this._bindModalButtons(),this.emit("qrauth:claimed",{sessionId:r?.sessionId,status:r?.status,scopes:r?.scopes,metadata:r?.metadata,useCount:r?.useCount,maxUses:r?.maxUses}),this.display==="button"&&setTimeout(()=>this._closeModal(),2200);break}case"EXPIRED":this._clearTimers(),this._status="EXPIRED",this._updateBody(this._bodyForStatus("EXPIRED")),this._bindModalButtons(),this.emit("qrauth:expired");break;case"REVOKED":this._clearTimers(),this._status="REVOKED",this._updateBody(this._bodyForStatus("REVOKED")),this._bindModalButtons(),this.emit("qrauth:revoked");break}}_startCountdown(){this._timerInterval=setInterval(()=>{let t=this.shadow.getElementById("timer");if(!t||!this._expiresAt)return;let r=Math.max(0,Math.floor((this._expiresAt-Date.now())/1e3));t.textContent=r>0?this._formatTimer(r):"",r<=0&&(clearInterval(this._timerInterval),this._timerInterval=null,this._status==="active"&&this._handleStatusChange("EXPIRED",void 0))},1e3)}_formatTimer(t){let r=t??(this._expiresAt?Math.max(0,Math.floor((this._expiresAt-Date.now())/1e3)):0),n=Math.floor(r/60),s=r%60;return`Expires in ${n}:${s<10?"0":""}${s}`}_updateBody(t){let r=this.display==="inline"?this.shadow.getElementById("inline-body"):this.shadow.getElementById("modal-body");r&&(r.innerHTML=t)}_clearTimers(){this._timerInterval&&(clearInterval(this._timerInterval),this._timerInterval=null),this._pollTimeout&&(clearTimeout(this._pollTimeout),this._pollTimeout=null)}};customElements.define("qrauth-ephemeral",W);var ht=`<svg viewBox="0 0 200 200" xmlns="http://www.w3.org/2000/svg" aria-hidden="true">
894
903
  <path d="M48 24 H152 Q166 24 166 38 V108 Q166 156 100 182 Q34 156 34 108 V38 Q34 24 48 24 Z"
895
904
  fill="none" stroke="#fff" stroke-width="5"/>
896
905
  <g fill="#fff" opacity="0.2">
@@ -907,12 +916,12 @@
907
916
  <path d="M62 104 L88 134 L144 64"
908
917
  fill="none" stroke="#fff" stroke-width="15"
909
918
  stroke-linecap="round" stroke-linejoin="round"/>
910
- </svg>`,y=`<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" aria-hidden="true">
919
+ </svg>`,He=`<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" aria-hidden="true">
911
920
  <path d="M9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41L9 16.17z" fill="currentColor"/>
912
- </svg>`,q=`<svg class="spinner" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" aria-hidden="true">
921
+ </svg>`,Jr=`<svg class="spinner" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" aria-hidden="true">
913
922
  <circle cx="12" cy="12" r="10" fill="none" stroke="currentColor" stroke-width="2.5"
914
923
  stroke-dasharray="31.416" stroke-dashoffset="10" stroke-linecap="round"/>
915
- </svg>`,m=class extends p{constructor(){super(...arguments);n(this,"_sessionId",null);n(this,"_sessionToken",null);n(this,"_codeVerifier",null);n(this,"_status","idle");n(this,"_expiresAt",null);n(this,"_timerInterval",null);n(this,"_pollTimeout",null)}static get observedAttributes(){return[...super.observedAttributes,"session-token","scopes","auto-start","redirect-uri"]}get sessionToken(){return this.getAttribute("session-token")}get scopes(){return this.getAttribute("scopes")||"identity"}get autoStart(){return this.hasAttribute("auto-start")}get redirectUri(){return this.getAttribute("redirect-uri")}get forceMode(){let t=this.getAttribute("force-mode");return t==="mobile"||t==="desktop"?t:"auto"}get mobileFallbackOnly(){return this.hasAttribute("mobile-fallback-only")}connectedCallback(){super.connectedCallback(),this.autoStart&&this._startAuth()}disconnectedCallback(){super.disconnectedCallback(),this._clearTimers()}render(){this.shadow.innerHTML=`
924
+ </svg>`,Z=class extends y{constructor(){super(...arguments);p(this,"_sessionId",null);p(this,"_sessionToken",null);p(this,"_codeVerifier",null);p(this,"_status","idle");p(this,"_expiresAt",null);p(this,"_currentQrUrl",null);p(this,"_timerInterval",null);p(this,"_pollTimeout",null)}static get observedAttributes(){return[...super.observedAttributes,"session-token","scopes","auto-start","redirect-uri"]}get sessionToken(){return this.getAttribute("session-token")}get scopes(){return this.getAttribute("scopes")||"identity"}get autoStart(){return this.hasAttribute("auto-start")}get redirectUri(){return this.getAttribute("redirect-uri")}get forceMode(){let t=this.getAttribute("force-mode");return t==="mobile"||t==="desktop"?t:"auto"}get mobileFallbackOnly(){return this.hasAttribute("mobile-fallback-only")}connectedCallback(){super.connectedCallback(),this.autoStart&&this._startAuth()}disconnectedCallback(){super.disconnectedCallback(),this._clearTimers()}render(){this.shadow.innerHTML=`
916
925
  <style>
917
926
  ${this.getBaseStyles()}
918
927
  :host { display: block; }
@@ -987,41 +996,41 @@
987
996
  ${this._bodyForStatus("idle")}
988
997
  </div>
989
998
  </div>
990
- `,this._bindBodyEvents()}_bodyForStatus(t,e){let i=`
999
+ `,this._bindBodyEvents()}_bodyForStatus(t,r){let n=`
991
1000
  <div class="step-label">
992
1001
  <span class="step-dot"></span>
993
1002
  Step 2 of 2 &mdash; Verify identity
994
1003
  </div>
995
1004
  `;switch(t){case"idle":return`
996
- ${i}
1005
+ ${n}
997
1006
  <div class="state-header">
998
- <div class="brand-icon">${f}</div>
1007
+ <div class="brand-icon">${ht}</div>
999
1008
  <h3>Verify your identity</h3>
1000
1009
  <p class="subtitle">Scan the QR code with your phone to confirm it&apos;s you</p>
1001
1010
  </div>
1002
1011
  <button class="start-btn" id="start-btn" aria-label="Start 2FA verification">
1003
- <span class="btn-icon">${f}</span>
1012
+ <span class="btn-icon">${ht}</span>
1004
1013
  Verify your identity
1005
1014
  </button>
1006
1015
  `;case"loading":return`
1007
- ${i}
1016
+ ${n}
1008
1017
  <div class="state-loading">
1009
- <div class="spinner-wrap">${q}</div>
1018
+ <div class="spinner-wrap">${Jr}</div>
1010
1019
  <p class="status-text">Generating QR code...</p>
1011
1020
  </div>
1012
- `;case"pending":case"SCANNED":{if(this.isMobileLike())return this._mobilePendingBody(t,e,i);let r=t==="SCANNED";return`
1013
- ${i}
1021
+ `;case"pending":case"SCANNED":{if(this.isMobileLike())return this._mobilePendingBody(t,r,n);let s=t==="SCANNED";return`
1022
+ ${n}
1014
1023
  <h3>Scan to verify</h3>
1015
1024
  <p class="subtitle">Use your phone camera to complete verification</p>
1016
- ${this._qrFrameHtml(e?.qrUrl??"",r)}
1017
- <div class="status-text ${r?"status-scanned":""}">
1018
- ${r?"&#10003; Scanned &mdash; waiting for approval...":"Waiting for scan..."}
1025
+ ${this._qrFrameHtml(r?.qrUrl??"",s)}
1026
+ <div class="status-text ${s?"status-scanned":""}">
1027
+ ${s?"&#10003; Scanned &mdash; waiting for approval...":"Waiting for scan..."}
1019
1028
  </div>
1020
- <div class="timer" id="timer">${e?.timerHtml??""}</div>
1029
+ <div class="timer" id="timer">${r?.timerHtml??""}</div>
1021
1030
  <div class="footer">Secured by <a href="https://qrauth.io" target="_blank" rel="noopener">QRAuth</a></div>
1022
1031
  `}case"APPROVED":return`
1023
1032
  <div class="state-approved">
1024
- <div class="success-icon">${y}</div>
1033
+ <div class="success-icon">${He}</div>
1025
1034
  <h3>Identity verified!</h3>
1026
1035
  <p class="subtitle">Second factor confirmed</p>
1027
1036
  </div>
@@ -1043,30 +1052,30 @@
1043
1052
  <div class="state-error">
1044
1053
  <div class="error-icon">&#9888;</div>
1045
1054
  <h3>Something went wrong</h3>
1046
- <p class="subtitle">${e?.errorMessage??"Failed to start verification."}</p>
1055
+ <p class="subtitle">${r?.errorMessage??"Failed to start verification."}</p>
1047
1056
  <button class="retry-btn" id="retry-btn">Try again</button>
1048
1057
  </div>
1049
- `;default:return""}}_qrFrameHtml(t,e){let i=t?`https://api.qrserver.com/v1/create-qr-code/?size=320x320&data=${encodeURIComponent(t)}`:"";return`
1050
- <div class="qr-frame ${e?"scanned":""}">
1051
- <img src="${i}" alt="QR Code for 2FA verification" width="160" height="160" loading="lazy"/>
1052
- <div class="qr-badge">${f}</div>
1053
- ${e?'<div class="scanned-overlay"><span class="scanned-check">'+y+"</span></div>":""}
1058
+ `;default:return""}}_qrFrameHtml(t,r){let n=$(t,320);return`
1059
+ <div class="qr-frame ${r?"scanned":""}">
1060
+ <div class="qr-image" role="img" aria-label="QR Code for 2FA verification">${n}</div>
1061
+ <div class="qr-badge">${ht}</div>
1062
+ ${r?'<div class="scanned-overlay"><span class="scanned-check">'+He+"</span></div>":""}
1054
1063
  </div>
1055
- `}_mobilePendingBody(t,e,i=""){let r=t==="SCANNED";return`
1056
- ${i}
1064
+ `}_mobilePendingBody(t,r,n=""){let s=t==="SCANNED";return`
1065
+ ${n}
1057
1066
  <h3>Verify your identity</h3>
1058
1067
  <p class="subtitle">Tap continue to verify on this device.</p>
1059
1068
  <button class="mobile-cta" id="mobile-cta" type="button">
1060
- <span class="btn-icon">${f}</span>
1069
+ <span class="btn-icon">${ht}</span>
1061
1070
  Continue with QRAuth
1062
1071
  </button>
1063
- <div class="status-text ${r?"status-scanned":""}">
1064
- ${r?"&#10003; Scanned &mdash; waiting for approval...":"Waiting for approval..."}
1072
+ <div class="status-text ${s?"status-scanned":""}">
1073
+ ${s?"&#10003; Scanned &mdash; waiting for approval...":"Waiting for approval..."}
1065
1074
  </div>
1066
- <div class="timer" id="timer">${e?.timerHtml??""}</div>
1075
+ <div class="timer" id="timer">${r?.timerHtml??""}</div>
1067
1076
  <details class="alt-device">
1068
1077
  <summary>Use another device</summary>
1069
- ${this._qrFrameHtml(e?.qrUrl??"",r)}
1078
+ ${this._qrFrameHtml(r?.qrUrl??"",s)}
1070
1079
  </details>
1071
1080
  <div class="footer">Secured by <a href="https://qrauth.io" target="_blank" rel="noopener">QRAuth</a></div>
1072
1081
  `}_sharedStyles(){return`
@@ -1127,7 +1136,8 @@
1127
1136
  transition: border-color 0.3s;
1128
1137
  }
1129
1138
  .qr-frame.scanned { border-color: var(--_success); }
1130
- .qr-frame img { display: block; width: 160px; height: 160px; border-radius: 4px; }
1139
+ .qr-frame .qr-image { display: block; width: 160px; height: 160px; border-radius: 4px; overflow: hidden; }
1140
+ .qr-frame .qr-image svg { display: block; width: 100%; height: 100%; }
1131
1141
 
1132
1142
  /* Smaller badge for compact QR */
1133
1143
  .qr-badge {
@@ -1300,5 +1310,5 @@
1300
1310
  }
1301
1311
  .footer a { color: var(--_disabled); text-decoration: none; }
1302
1312
  .footer a:hover { text-decoration: underline; }
1303
- `}_bindBodyEvents(){this.shadow.getElementById("start-btn")?.addEventListener("click",()=>this._startAuth()),this.shadow.getElementById("retry-btn")?.addEventListener("click",()=>this._retry()),this.shadow.getElementById("mobile-cta")?.addEventListener("click",()=>this._openApprovalPage())}_openApprovalPage(){if(!this._sessionToken)return;let t=`${this.baseUrl}/a/${this._sessionToken}`;window.open(t,"_blank","noopener")||(window.location.href=t)}async _startAuth(){this._status="loading",this._updateBody(this._bodyForStatus("loading"));try{this._codeVerifier=await this.generateCodeVerifier();let t=await this.computeCodeChallenge(this._codeVerifier),e={"Content-Type":"application/json","X-Client-Id":this.tenant},i={scopes:this.scopes.split(/\s+/).filter(Boolean),codeChallenge:t,codeChallengeMethod:"S256"};this.redirectUri&&(i.redirectUrl=this.redirectUri);let r=await fetch(`${this.baseUrl}/api/v1/auth-sessions`,{method:"POST",headers:e,body:JSON.stringify(i)});if(!r.ok){let d=await r.json().catch(()=>({message:"Failed to create session"}));throw new Error(d.message??"Failed to create session")}let s=await r.json();this._sessionId=s.sessionId,this._sessionToken=s.token||(s.qrUrl?s.qrUrl.split("/").pop()??null:null),this._expiresAt=new Date(s.expiresAt).getTime(),this._status="pending",this._updateBody(this._bodyForStatus("pending",{qrUrl:s.qrUrl})),this._bindBodyEvents(),this._startCountdown(),this._beginPolling(s.sessionId)}catch(t){let e=t instanceof Error?t.message:"Unexpected error";this._status="error",this._updateBody(this._bodyForStatus("error",{errorMessage:e})),this._bindBodyEvents(),this.emit("qrauth:error",{message:e})}}_retry(){this._clearTimers(),this._sessionId=null,this._sessionToken=null,this._codeVerifier=null,this._status="idle",this._expiresAt=null,this._updateBody(this._bodyForStatus("idle")),this._bindBodyEvents()}_beginPolling(t){let e="PENDING",i=2e3,r=5e3,s=0,d=20,h=async()=>{if(!this._sessionId)return;let l=`${this.baseUrl}/api/v1/auth-sessions/${t}`;this._codeVerifier&&(l+=`?code_verifier=${encodeURIComponent(this._codeVerifier)}`);try{let c=await(await fetch(l,{headers:{"X-Client-Id":this.tenant}})).json();if(s=0,i=2e3,c.status!==e&&(e=c.status,this._handleStatusChange(c.status,c),["APPROVED","DENIED","EXPIRED"].includes(c.status)))return;this._pollTimeout=setTimeout(h,i)}catch{if(s++,s>=d){this._handleStatusChange("EXPIRED",void 0);return}i=Math.min(i*1.5,r),this._pollTimeout=setTimeout(h,i)}};this._pollTimeout=setTimeout(h,i)}_handleStatusChange(t,e){switch(this._status=t,t){case"SCANNED":{let i=this.shadow.querySelector(".qr-frame img")?.src,r=i?decodeURIComponent(i.replace(/.*[?&]data=/,"").split("&")[0]):"";this._updateBody(this._bodyForStatus("SCANNED",{qrUrl:r,timerHtml:this._formatTimer()})),this._bindBodyEvents();break}case"APPROVED":{this._clearTimers(),this._updateBody(this._bodyForStatus("APPROVED")),this.emit("qrauth:verified",{sessionId:e?.sessionId,user:e?.user,signature:e?.signature});break}case"DENIED":this._clearTimers(),this._updateBody(this._bodyForStatus("DENIED")),this._bindBodyEvents(),this.emit("qrauth:denied");break;case"EXPIRED":this._clearTimers(),this._status="EXPIRED",this._updateBody(this._bodyForStatus("EXPIRED")),this._bindBodyEvents(),this.emit("qrauth:expired");break}}_startCountdown(){this._timerInterval=setInterval(()=>{let t=this.shadow.getElementById("timer");if(!t||!this._expiresAt)return;let e=Math.max(0,Math.floor((this._expiresAt-Date.now())/1e3));t.textContent=e>0?this._formatTimer(e):"",e<=0&&(clearInterval(this._timerInterval),this._timerInterval=null,(this._status==="pending"||this._status==="SCANNED")&&this._handleStatusChange("EXPIRED",void 0))},1e3)}_formatTimer(t){let e=t??(this._expiresAt?Math.max(0,Math.floor((this._expiresAt-Date.now())/1e3)):0),i=Math.floor(e/60),r=e%60;return`Expires in ${i}:${r<10?"0":""}${r}`}_updateBody(t){let e=this.shadow.getElementById("body");e&&(e.innerHTML=t)}_clearTimers(){this._timerInterval&&(clearInterval(this._timerInterval),this._timerInterval=null),this._pollTimeout&&(clearTimeout(this._pollTimeout),this._pollTimeout=null)}};customElements.define("qrauth-2fa",m);return C($);})();
1313
+ `}_bindBodyEvents(){this.shadow.getElementById("start-btn")?.addEventListener("click",()=>this._startAuth()),this.shadow.getElementById("retry-btn")?.addEventListener("click",()=>this._retry()),this.shadow.getElementById("mobile-cta")?.addEventListener("click",()=>this._openApprovalPage())}_openApprovalPage(){if(!this._sessionToken)return;let t=new URL(`${this.baseUrl}/a/${this._sessionToken}`);t.searchParams.set("dr","1");let r=t.toString();window.open(r,"_blank","noopener")||(window.location.href=r)}async _startAuth(){this._status="loading",this._updateBody(this._bodyForStatus("loading"));try{this._codeVerifier=await this.generateCodeVerifier();let t=await this.computeCodeChallenge(this._codeVerifier),r={"Content-Type":"application/json","X-Client-Id":this.tenant},n={scopes:this.scopes.split(/\s+/).filter(Boolean),codeChallenge:t,codeChallengeMethod:"S256"};this.redirectUri&&(n.redirectUrl=this.redirectUri);let s=await fetch(`${this.baseUrl}/api/v1/auth-sessions`,{method:"POST",headers:r,body:JSON.stringify(n)});if(!s.ok){let a=await s.json().catch(()=>({message:"Failed to create session"}));throw new Error(a.message??"Failed to create session")}let o=await s.json();this._sessionId=o.sessionId,this._sessionToken=o.token||(o.qrUrl?o.qrUrl.split("/").pop()??null:null),this._expiresAt=new Date(o.expiresAt).getTime(),this._currentQrUrl=o.qrUrl??null,this._status="pending",this._updateBody(this._bodyForStatus("pending",{qrUrl:o.qrUrl})),this._bindBodyEvents(),this._startCountdown(),this._beginPolling(o.sessionId)}catch(t){let r=t instanceof Error?t.message:"Unexpected error";this._status="error",this._updateBody(this._bodyForStatus("error",{errorMessage:r})),this._bindBodyEvents(),this.emit("qrauth:error",{message:r})}}_retry(){this._clearTimers(),this._sessionId=null,this._sessionToken=null,this._codeVerifier=null,this._status="idle",this._expiresAt=null,this._currentQrUrl=null,this._updateBody(this._bodyForStatus("idle")),this._bindBodyEvents()}_beginPolling(t){let r="PENDING",n=2e3,s=5e3,o=0,a=20,l=async()=>{if(!this._sessionId)return;let d=`${this.baseUrl}/api/v1/auth-sessions/${t}`;this._codeVerifier&&(d+=`?code_verifier=${encodeURIComponent(this._codeVerifier)}`);try{let u=await(await fetch(d,{headers:{"X-Client-Id":this.tenant}})).json();if(o=0,n=2e3,u.status!==r&&(r=u.status,this._handleStatusChange(u.status,u),["APPROVED","DENIED","EXPIRED"].includes(u.status)))return;this._pollTimeout=setTimeout(l,n)}catch{if(o++,o>=a){this._handleStatusChange("EXPIRED",void 0);return}n=Math.min(n*1.5,s),this._pollTimeout=setTimeout(l,n)}};this._pollTimeout=setTimeout(l,n)}_handleStatusChange(t,r){switch(this._status=t,t){case"SCANNED":{this._updateBody(this._bodyForStatus("SCANNED",{qrUrl:this._currentQrUrl??"",timerHtml:this._formatTimer()})),this._bindBodyEvents();break}case"APPROVED":{this._clearTimers(),this._updateBody(this._bodyForStatus("APPROVED")),this.emit("qrauth:verified",{sessionId:r?.sessionId,user:r?.user,signature:r?.signature});break}case"DENIED":this._clearTimers(),this._updateBody(this._bodyForStatus("DENIED")),this._bindBodyEvents(),this.emit("qrauth:denied");break;case"EXPIRED":this._clearTimers(),this._status="EXPIRED",this._updateBody(this._bodyForStatus("EXPIRED")),this._bindBodyEvents(),this.emit("qrauth:expired");break}}_startCountdown(){this._timerInterval=setInterval(()=>{let t=this.shadow.getElementById("timer");if(!t||!this._expiresAt)return;let r=Math.max(0,Math.floor((this._expiresAt-Date.now())/1e3));t.textContent=r>0?this._formatTimer(r):"",r<=0&&(clearInterval(this._timerInterval),this._timerInterval=null,(this._status==="pending"||this._status==="SCANNED")&&this._handleStatusChange("EXPIRED",void 0))},1e3)}_formatTimer(t){let r=t??(this._expiresAt?Math.max(0,Math.floor((this._expiresAt-Date.now())/1e3)):0),n=Math.floor(r/60),s=r%60;return`Expires in ${n}:${s<10?"0":""}${s}`}_updateBody(t){let r=this.shadow.getElementById("body");r&&(r.innerHTML=t)}_clearTimers(){this._timerInterval&&(clearInterval(this._timerInterval),this._timerInterval=null),this._pollTimeout&&(clearTimeout(this._pollTimeout),this._pollTimeout=null)}};customElements.define("qrauth-2fa",Z);return tr(Wr);})();
1304
1314
  //# sourceMappingURL=qrauth-components.js.map
package/dist/twofa.d.ts CHANGED
@@ -47,6 +47,7 @@ export declare class QRAuthTwoFA extends QRAuthElement {
47
47
  private _codeVerifier;
48
48
  private _status;
49
49
  private _expiresAt;
50
+ private _currentQrUrl;
50
51
  private _timerInterval;
51
52
  private _pollTimeout;
52
53
  get sessionToken(): string | null;
@@ -81,6 +82,11 @@ export declare class QRAuthTwoFA extends QRAuthElement {
81
82
  * The existing polling loop in _beginPolling picks up SCANNED / APPROVED
82
83
  * transitions from the server once the user completes the flow there, so
83
84
  * qrauth:verified fires unchanged.
85
+ *
86
+ * The `dr=1` query flag tells the hosted approval page that this is a
87
+ * same-device click (not a cross-device QR scan), and that the
88
+ * post-approval redirect to redirectUrl should fire. The QR matrix
89
+ * encodes the bare /a/:token URL, so a scanner cannot carry this flag.
84
90
  */
85
91
  private _openApprovalPage;
86
92
  private _startAuth;