@sendoracloud/sdk-web 3.24.1 → 3.24.2

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.cjs CHANGED
@@ -1 +1 @@
1
- "use strict";var Se=Object.defineProperty;var dt=Object.getOwnPropertyDescriptor;var ct=Object.getOwnPropertyNames;var ht=Object.prototype.hasOwnProperty;var pt=(s,e)=>{for(var t in e)Se(s,t,{get:e[t],enumerable:!0})},ft=(s,e,t,r)=>{if(e&&typeof e=="object"||typeof e=="function")for(let n of ct(e))!ht.call(s,n)&&n!==t&&Se(s,n,{get:()=>e[n],enumerable:!(r=dt(e,n))||r.enumerable});return s};var gt=s=>ft(Se({},"__esModule",{value:!0}),s);var or={};pt(or,{AMBIGUOUS_HELD_GUEST:()=>ce,AUTH_HELD_SLOT_KEYS:()=>rt,AUTH_STATES:()=>Ve,AUTH_WITHHELD_CODES:()=>G,AlreadyIdentifiedError:()=>K,Analytics:()=>L,Audiences:()=>q,Auth:()=>V,AuthError:()=>u,Chatbot:()=>O,Consent:()=>H,CredentialInUseError:()=>C,DEAD_CODES:()=>le,EmailAlreadyTakenError:()=>b,FeatureFlags:()=>U,HELD_GUEST_SLOTS:()=>T,HeldGuestLimitError:()=>W,HeldGuestProjectMismatch:()=>_,InAppMessaging:()=>N,LinkError:()=>f,Links:()=>B,REFRESH_END_REASONS:()=>ue,REJECTED_IN_WITHHELD:()=>$e,RELEASE_HELD_ON_END_REASONS:()=>de,SendoraCloud:()=>ye,Surveys:()=>x,ValidationError:()=>m,WebPush:()=>$,default:()=>ir,extractShortcodeFromUrl:()=>at,projectVerdict:()=>he,safeUrl:()=>S,sanitizeHtml:()=>ne});module.exports=gt(or);var Pe=/^[a-zA-Z][a-zA-Z0-9._:-]{0,127}$/;var mt=new Set(["__proto__","constructor","prototype"]),m=class extends Error{constructor(e){super(`[SendoraCloud] ${e}`),this.name="SendoraValidationError"}};function Le(s){if(typeof s!="string"||!Pe.test(s))throw new m(`Invalid event name: must match ${Pe}, got "${String(s)}".`)}function Ue(s){if(s==null)return;if(typeof s!="object"||Array.isArray(s))throw new m("Properties must be a plain object, not an array or primitive.");let e=xe(s);if(e>5)throw new m(`Properties nested too deeply (${e} levels, max 5).`);Ne(s);let t;try{t=JSON.stringify(s).length}catch{throw new m("Properties contain a circular reference or unserializable value.")}if(t>32768)throw new m(`Properties too large (${t} bytes, max 32768).`)}function xe(s,e=0){if(e>6||s==null||typeof s!="object")return e;let t=e;for(let r of Object.keys(s)){let n=xe(s[r],e+1);n>t&&(t=n)}return t}function Ne(s){if(!(s==null||typeof s!="object"))for(let e of Object.keys(s)){if(mt.has(e))throw new m(`Forbidden property key "${e}" (prototype pollution guard).`);Ne(s[e])}}var yt=/^pk_[A-Za-z0-9_-]{16,}$/;function Oe(s){if(!s||typeof s!="string")throw new m("apiKey is required.");if(s.startsWith("sk_")||s.startsWith("sendora_secret_"))throw new m("Secret keys must NEVER be used in browser SDK. Use a publishable key (pk_...).");if(!yt.test(s))throw new m("Invalid publishable key format. Expected pk_... (17+ chars).")}function He(s){let e=s.replace(/\/$/,"");if(!(e.startsWith("http://localhost")||e.startsWith("http://127.0.0.1"))&&!e.startsWith("https://"))throw new m("apiUrl must be https:// (only http://localhost is allowed for dev).")}var Me={name:"@sendoracloud/sdk-web",version:"3.24.1",description:"Sendora Cloud Web SDK \u2014 analytics, feature flags, surveys, in-app messaging, chatbot, auth, deep links (Branch / Firebase parity). Zero dependencies, TypeScript, SSR-safe.",type:"module",main:"./dist/index.cjs",module:"./dist/index.js",types:"./dist/index.d.ts",exports:{".":{types:"./dist/index.d.ts",import:"./dist/index.js",require:"./dist/index.cjs"}},files:["dist","README.md","LICENSE"],keywords:["sendora","analytics","feature-flags","surveys","in-app-messaging","chatbot","tracking","customer-engagement"],homepage:"https://sendoracloud.com/sdks",bugs:{url:"https://github.com/sendoracloud/sdk-web/issues"},author:"Sendora Cloud <hello@sendoracloud.com>",license:"Apache-2.0",publishConfig:{access:"public"},sideEffects:!1,scripts:{build:"tsup src/index.ts --format cjs,esm --dts --clean --minify",typecheck:"tsc --noEmit && tsc --noEmit -p tsconfig.test.json",test:"vitest run",prepublishOnly:"npm run build"},devDependencies:{typescript:"^5.4.0",tsup:"^8.0.0"}};var R=Me.version;var kt="https://api.sendoracloud.com",vt=1e4,At="@sendoracloud/sdk-web",re=class{constructor(e){let t=(e.apiUrl??kt).replace(/\/$/,"");He(t),this.apiKey=e.apiKey,this.baseUrl=t,this.debug=!!e.debug}get(e,t){return this.request("GET",e,void 0,t)}post(e,t,r){return this.request("POST",e,t,r)}patch(e,t,r){return this.request("PATCH",e,t,r)}delete(e,t){return this.request("DELETE",e,void 0,t)}async request(e,t,r,n){let i=`${this.baseUrl}/api/v1${t}`,o=typeof AbortController<"u"?new AbortController:null,a=o?setTimeout(()=>o.abort(),vt):null;try{let l=await fetch(i,{method:e,headers:{"Content-Type":"application/json","X-API-Key":this.apiKey,"X-Sendora-SDK-Name":At,"X-Sendora-SDK-Version":R,...n??{}},body:r?JSON.stringify(r):void 0,signal:o?o.signal:void 0});a&&clearTimeout(a);let d;try{d=await l.json()}catch{d={success:!1,error:{code:"PARSE_ERROR",message:`HTTP ${l.status}`}}}if(this.debug&&console.debug(`[SendoraCloud] ${e} ${t} \u2192 ${l.status}`),!l.ok){if(t.startsWith("/auth-service/")&&!this.debug)console.warn(`[SendoraCloud] ${e} ${t} \u2192 HTTP ${l.status}`);else{let g=d?.error?.code??"HTTP_ERROR",k=d?.error?.message??`HTTP ${l.status}`,v=d?.error?.details?.fieldErrors,y=v?` (${Object.entries(v).map(([w,z])=>`${w}: ${(z??[]).join(", ")}`).join("; ")})`:"";console.warn(`[SendoraCloud] ${e} ${t} \u2192 HTTP ${l.status} \u2014 ${g}: ${k}${y}`)}d&&d.error&&(d.error={...d.error,status:l.status})}return d}catch(l){a&&clearTimeout(a);let d=l instanceof Error&&l.name==="AbortError"?"timeout":"error";return console.warn(`[SendoraCloud] ${e} ${t} network ${d}`),{success:!1,error:{code:"NETWORK_ERROR",message:d}}}}};var St="sendora_",se=class{constructor(e,t=!1){this.memoryStore=new Map;this.useLocalStorage=t?!1:this.checkLocalStorage(),this.prefix=e??St}get(e){let t=this.prefix+e;if(this.useLocalStorage)try{return localStorage.getItem(t)}catch{return this.memoryStore.get(t)??null}return this.memoryStore.get(t)??null}set(e,t){let r=this.prefix+e;if(this.useLocalStorage)try{localStorage.setItem(r,t);return}catch{}this.memoryStore.set(r,t)}remove(e){let t=this.prefix+e;if(this.useLocalStorage)try{localStorage.removeItem(t)}catch{}this.memoryStore.delete(t)}isPersistent(){return this.useLocalStorage}relativeKey(e){return e.startsWith(this.prefix)?e.slice(this.prefix.length):null}clearPrefix(e){let t=this.prefix+e;if(this.useLocalStorage)try{for(let r=localStorage.length-1;r>=0;r--){let n=localStorage.key(r);n&&n.startsWith(t)&&localStorage.removeItem(n)}}catch{}for(let r of Array.from(this.memoryStore.keys()))r.startsWith(t)&&this.memoryStore.delete(r)}checkLocalStorage(){try{if(typeof localStorage>"u")return!1;let e="__sendora_test__";return localStorage.setItem(e,"1"),localStorage.removeItem(e),!0}catch{return!1}}};function P(s=""){let e=new Uint8Array(16),t=typeof globalThis<"u"&&"crypto"in globalThis?globalThis.crypto:void 0;if(!t||typeof t.getRandomValues!="function")throw new Error("[SendoraCloud] crypto.getRandomValues unavailable \u2014 refusing to mint IDs without a CSPRNG");t.getRandomValues(e);let r="";for(let n of e)r+=n.toString(16).padStart(2,"0");return s+r}var Fe=500,Ee=10,Ie=6e4,L=class{constructor(e,t,r,n){this.queue=[];this.timer=null;this.userId=null;this.identityToken=null;this.consecutiveFailures=0;this.nextFlushAfter=0;this.breakerOpenAt=0;this.breakerWarned=!1;this.http=t,this.storage=r,this.consent=n,this.projectId=e.projectId,this.flushInterval=e.flushInterval??5e3,this.maxQueueSize=e.maxQueueSize??20,this.persistUserId=!!e.persistUserId,this.stripQueryParams=e.stripQueryParams!==!1,this.appVersion=e.appVersion,this.storage.get("schema_version")===null&&this.storage.set("schema_version","1");let i=this.storage.get("anonymous_id");if(i?this.anonymousId=i:(this.anonymousId=P("anon_"),this.storage.set("anonymous_id",this.anonymousId)),this.persistUserId){let o=this.storage.get("user_id");o&&(this.userId=o)}this.timer=setInterval(()=>this.flush(),this.flushInterval),typeof window<"u"&&window.addEventListener("beforeunload",()=>this.flush()),this.consent.subscribe(o=>{o&&this.flush()})}track(e,t){Le(e),t&&Ue(t),this.queue.length>=Fe&&this.queue.shift(),this.queue.push({eventType:e,properties:t??{},userId:this.userId??void 0,anonymousId:this.anonymousId,timestamp:new Date().toISOString(),identityToken:this.identityToken??void 0}),this.queue.length>=this.maxQueueSize&&this.flush()}page(e){if(typeof window>"u")return;let t=this.stripQueryParams?window.location.origin+window.location.pathname:window.location.href;this.track("page.viewed",{url:t,path:window.location.pathname,title:document.title,referrer:document.referrer||void 0,...e})}identify(e,t,r){if(typeof e!="string"||e.length===0||e.length>256)throw new Error("[SendoraCloud] userId must be a 1-256 char string.");this.userId=e,this.identityToken=r?.identityToken??null,this.persistUserId&&this.storage.set("user_id",e),this.track("user.identified",{...t})}reset(e=!0){this.userId=null,this.identityToken=null,this.storage.remove("user_id"),e&&(this.anonymousId=P("anon_"),this.storage.set("anonymous_id",this.anonymousId)),this.storage.clearPrefix("iam_shown_"),this.storage.clearPrefix("survey_shown_")}withholdIdentity(){this.userId=null,this.identityToken=null}dropQueue(){this.queue=[]}async flush(){if(this.queue.length===0||!this.consent.isGranted()||Date.now()<this.nextFlushAfter)return;this.consecutiveFailures>Ee&&Date.now()-this.breakerOpenAt>=Ie&&(this.consecutiveFailures=0,this.breakerOpenAt=0,this.breakerWarned=!1);let e=this.queue.splice(0,100),t=this.getSessionId(),r=e.map(a=>({projectId:this.projectId,module:"custom",eventType:a.eventType,userId:a.userId,anonymousId:a.anonymousId,identityToken:a.identityToken,timestamp:a.timestamp??new Date().toISOString(),properties:a.properties??{},context:this.getContext(),...t?{sessionId:t}:{},consent:["analytics"]}));if((await this.http.post("/events/batch",{events:r})).success){this.consecutiveFailures=0,this.breakerOpenAt=0,this.breakerWarned=!1;return}if(this.consecutiveFailures++,this.consecutiveFailures>Ee){this.breakerWarned||(this.breakerOpenAt=Date.now(),this.breakerWarned=!0,console.warn(`[SendoraCloud] Analytics circuit breaker open after ${Ee} consecutive failed flushes \u2014 events will be dropped until a flush succeeds or ${Ie}ms elapse.`));return}let i=Math.min(Ie,1e3*2**this.consecutiveFailures);this.nextFlushAfter=Date.now()+i;let o=Math.max(0,Fe-this.queue.length);o>0&&this.queue.unshift(...e.slice(0,o))}destroy(){this.timer&&clearInterval(this.timer),this.timer=null,this.flush()}getSessionId(){try{return typeof sessionStorage>"u"?void 0:sessionStorage.getItem("sendora_session_id")||void 0}catch{return}}getContext(){return typeof window>"u"?{sdk:{name:"@sendoracloud/sdk-web",version:R}}:{page:{url:this.stripQueryParams?window.location.origin+window.location.pathname:window.location.href,path:window.location.pathname,title:document.title},referrer:document.referrer||void 0,locale:typeof navigator<"u"?navigator.language:void 0,device:this.buildDevice(),sdk:{name:"@sendoracloud/sdk-web",version:R}}}buildDevice(){if(typeof navigator>"u")return;let e=navigator.userAgent||"",r=navigator.userAgentData?.mobile??/Mobi|Android|iPhone|iPod/i.test(e);return{type:/iPad|Tablet|(?:Android(?!.*Mobile))/i.test(e)?"tablet":r?"mobile":"desktop",os:"Web",osVersion:"",model:"",appVersion:this.resolveAppVersion(),browser:Et(e)}}resolveAppVersion(){if(this.appVersion)return this.appVersion;if(typeof document<"u"){let r=document.querySelector('meta[name="sendora:app-version"]')?.getAttribute("content");if(r)return r}let e=globalThis.__SENDORA_APP_VERSION__;return typeof e=="string"?e:""}};function Et(s){let e=[["Edge",/Edg\/(\d+)/],["Opera",/OPR\/(\d+)/],["Firefox",/Firefox\/(\d+)/],["Samsung Internet",/SamsungBrowser\/(\d+)/],["Chrome",/Chrome\/(\d+)/],["Safari",/Version\/(\d+)[^ ]* Safari/]];for(let[t,r]of e){let n=r.exec(s);if(n)return`${t} ${n[1]}`}return"Unknown"}var U=class{constructor(e,t,r){this.cache=new Map;this.refreshInterval=null;this.http=t,this.storage=r;let n=this.storage.get("flags");if(n)try{let i=JSON.parse(n);if(Array.isArray(i))for(let o of i)Re(o)&&this.cache.set(o.key,o)}catch{}}setContext(e){this.userId=e.userId,this.entityId=e.entityId,this.environment=e.environment}async getFlag(e){if(typeof e!="string"||e.length===0||e.length>128)return null;let t=this.cache.get(e);if(t)return t.value;let r=await this.http.post("/feature-flags/evaluate",{key:e,userId:this.userId,entityId:this.entityId,environment:this.environment});return r.success&&r.data&&Re(r.data)?(this.cache.set(e,r.data),this.persistCache(),r.data.value):null}async isEnabled(e,t=!1){let r=await this.getFlag(e);return typeof r=="boolean"?r:t}async refreshAll(){let e=await this.http.post("/feature-flags/evaluate-all",{userId:this.userId,entityId:this.entityId,environment:this.environment});if(e.success&&Array.isArray(e.data)){this.cache.clear();for(let t of e.data)Re(t)&&this.cache.set(t.key,t);this.persistCache()}}startAutoRefresh(e=6e4){this.stopAutoRefresh(),this.refreshAll(),this.refreshInterval=setInterval(()=>this.refreshAll(),e)}stopAutoRefresh(){this.refreshInterval&&clearInterval(this.refreshInterval),this.refreshInterval=null}getAllFlags(){let e={};for(let[t,r]of this.cache)e[t]=r.value;return e}reset(){this.cache.clear(),this.storage.remove("flags"),this.userId=void 0,this.entityId=void 0,this.environment=void 0}destroy(){this.stopAutoRefresh()}persistCache(){this.storage.set("flags",JSON.stringify(Array.from(this.cache.values())))}};function Re(s){if(s==null||typeof s!="object")return!1;let e=s;return Object.prototype.hasOwnProperty.call(e,"__proto__")||Object.prototype.hasOwnProperty.call(e,"constructor")?!1:typeof e.key=="string"&&"value"in e}var It=32*1024,x=class{constructor(e,t,r){this.activeSurvey=null;this.http=t,this.storage=r}onDisplay(e){this.onSurveyDisplay=e}async showSurvey(e){if(typeof e!="string"||!/^[A-Za-z0-9_-]{6,64}$/.test(e))return null;let t=`survey_shown_${e}`;if(this.storage.get(t))return null;let r=await this.http.get(`/surveys/${encodeURIComponent(e)}/config`);return!r.success||!r.data||!Rt(r.data)?null:(this.activeSurvey=r.data,this.storage.set(t,"1"),this.onSurveyDisplay&&this.onSurveyDisplay(r.data),r.data)}async submitResponse(e,t,r=!0){let n=0;try{n=JSON.stringify(t).length}catch{return!1}if(n>It)return!1;let i=await this.http.post("/surveys/responses",{surveyId:e,answers:t,completed:r});return i.success&&(this.activeSurvey=null),i.success}dismiss(){this.activeSurvey=null}getActiveSurvey(){return this.activeSurvey}};function Rt(s){if(s==null||typeof s!="object")return!1;let e=s;return typeof e.id!="string"||typeof e.name!="string"||!Array.isArray(e.questions)?!1:e.questions.every(Tt)}function Tt(s){if(s==null||typeof s!="object")return!1;let e=s;return typeof e.id=="string"&&typeof e.text=="string"}function S(s){if(!(!s||typeof s!="string"))try{let e=typeof window<"u"?window.location.href:"https://local/",t=new URL(s,e);return t.protocol==="http:"||t.protocol==="https:"?t.href:void 0}catch{return}}var _t=new Set(["b","i","u","em","strong","a","p","br","span","ul","ol","li","h1","h2","h3","h4"]),bt={a:new Set(["href","target","rel"])};function ne(s){if(typeof DOMParser>"u")return"";let t=new DOMParser().parseFromString(`<div>${s}</div>`,"text/html").body.firstElementChild;return t?(je(t),t.innerHTML):""}function je(s){let e=Array.from(s.children);for(let t of e){let r=t.tagName.toLowerCase();if(!_t.has(r)){let i=document.createTextNode(t.textContent??"");t.replaceWith(i);continue}let n=bt[r]??new Set;for(let i of Array.from(t.attributes)){if(!n.has(i.name.toLowerCase())){t.removeAttribute(i.name);continue}if(i.name.toLowerCase()==="href"){let o=S(i.value);o?t.setAttribute("href",o):t.removeAttribute(i.name)}}r==="a"&&(t.setAttribute("rel","noopener noreferrer"),t.setAttribute("target","_blank")),je(t)}}var N=class{constructor(e,t,r){this.messages=[];this.pollInterval=null;this.http=t,this.storage=r}onDisplay(e){this.onMessageDisplay=e}async checkMessages(){let e=await this.http.get("/in-app-messages/active");if(!e.success||!Array.isArray(e.data))return null;this.messages=e.data.map(Ct);for(let t of this.messages){let r=`iam_shown_${t.id}`;if(!this.storage.get(r))return this.storage.set(r,"1"),this.onMessageDisplay&&this.onMessageDisplay(t),t}return null}async recordAction(e,t){await this.http.post("/in-app-messages/impressions",{messageId:e,action:t})}startPolling(e=3e5){this.stopPolling(),this.checkMessages(),this.pollInterval=setInterval(()=>this.checkMessages(),e)}stopPolling(){this.pollInterval&&clearInterval(this.pollInterval),this.pollInterval=null}getMessages(){return this.messages}destroy(){this.stopPolling()}};function Ct(s){return{...s,content:{...s.content,ctaUrl:S(s.content.ctaUrl),imageUrl:S(s.content.imageUrl)}}}var Dt=4e3,O=class{constructor(e,t,r){this.chatbotId=null;this.messages=[];this.http=t,this.storage=r;let n=this.storage.get("chat_session_id");this.sessionId=n??P("chat_"),n||this.storage.set("chat_session_id",this.sessionId)}init(e){if(typeof e!="string"||!/^[A-Za-z0-9_-]{6,64}$/.test(e))throw new Error("[SendoraCloud] Invalid chatbotId.");this.chatbotId=e}onNewMessage(e){this.onMessage=e}async sendMessage(e,t){if(!this.chatbotId||typeof e!="string"||e.length===0||e.length>Dt)return null;let r={role:"user",content:e,timestamp:new Date().toISOString()};this.messages.push(r);let n=await this.http.post("/chatbot/message",{chatbotId:this.chatbotId,sessionId:this.sessionId,message:e,userId:t});if(n.success&&n.data&&typeof n.data.reply=="string"){let i={role:"assistant",content:n.data.reply,timestamp:new Date().toISOString()};return this.messages.push(i),this.onMessage&&this.onMessage(i),i}return null}getMessages(){return[...this.messages]}newSession(){this.messages=[],this.sessionId=P("chat_"),this.storage.set("chat_session_id",this.sessionId)}getSessionId(){return this.sessionId}};var H=class{constructor(e,t){this.listeners=new Set;this.granted=e,this.http=t}isGranted(){return this.granted}grant(){this.granted||(this.granted=!0,this.emit())}revoke(){this.granted&&(this.granted=!1,this.emit())}subscribe(e){return this.listeners.add(e),()=>this.listeners.delete(e)}async record(e){if(!this.http)throw new Error("consent.record requires SDK init (HttpClient unavailable)");let t=await this.http.post("/consent/record",e);if(!t.success||!t.data)throw new Error(t.error?.message??"consent.record failed");return t.data}async requestDeletion(e){if(!this.http)throw new Error("consent.requestDeletion requires SDK init (HttpClient unavailable)");let t=await this.http.post("/consent/deletion-request",e);if(!t.success||!t.data)throw new Error(t.error?.message??"consent.requestDeletion failed");return t.data}emit(){for(let e of this.listeners)try{e(this.granted)}catch{}}};var M="auth_access_token",F="auth_access_expires",ie="auth_refresh_token",oe="auth_user",Y="auth_session",j=["auth_held_0","auth_held_1","auth_held_2","auth_held_3","auth_held_4"],ae="auth_mint_key",Ge="schema_version";var We=[M,F,ie,oe,Y],Pt=[...We,...j],Cr=[...Pt,ae];function Lt(s){if(s===null)return{user:null,unreadable:!1};try{let e=JSON.parse(s);return!e||typeof e!="object"||typeof e.id!="string"||e.id.length===0?{user:null,unreadable:!0}:{user:e,unreadable:!1}}catch{return{user:null,unreadable:!0}}}function Ut(s){if(s===null)return{record:null,unreadable:!1};try{let e=JSON.parse(s);if(!e||typeof e!="object"||e.v!==1)return{record:null,unreadable:!0};if(!e.user||typeof e.user!="object"||typeof e.user.id!="string"||e.user.id.length===0)return{record:null,unreadable:!0};if(typeof e.refreshToken!="string"||e.refreshToken.length===0)return{record:null,unreadable:!0};let t=typeof e.accessToken=="string"&&e.accessToken.length>0?e.accessToken:null,r=typeof e.accessExpiresAt=="number"&&Number.isFinite(e.accessExpiresAt)?e.accessExpiresAt:0,n=Array.isArray(e.heldReportPending)?e.heldReportPending.filter(i=>typeof i=="string"):void 0;return{record:{v:1,user:e.user,accessToken:t,accessExpiresAt:r,refreshToken:e.refreshToken,...n&&n.length>0?{heldReportPending:n}:{}},unreadable:!1}}catch{return{record:null,unreadable:!0}}}function Ke(s){if(s===null)return{slot:null,unreadable:!1};try{let e=JSON.parse(s);return!e||typeof e!="object"||e.v!==1||typeof e.userId!="string"||e.userId.length===0||typeof e.refreshToken!="string"||e.refreshToken.length===0?{slot:null,unreadable:!0}:{slot:{v:1,userId:e.userId,sid:typeof e.sid=="string"?e.sid:"",refreshToken:e.refreshToken,tokenAtHold:typeof e.tokenAtHold=="string"?e.tokenAtHold:e.refreshToken,heldAt:typeof e.heldAt=="number"&&Number.isFinite(e.heldAt)?e.heldAt:0,project:typeof e.project=="string"?e.project:null,autoRestore:e.autoRestore!==!1},unreadable:!1}}catch{return{slot:null,unreadable:!0}}}var J=class{constructor(e){this.storage=e}readDisk(){let{record:e,unreadable:t}=Ut(this.storage.get(Y)),{user:r,unreadable:n}=Lt(this.storage.get(oe)),i=this.storage.get(F),o=i?Number(i):0;return{record:e,recordUnreadable:t,legacy:{user:r,userUnreadable:n,accessToken:this.storage.get(M),accessExpiresAt:Number.isFinite(o)?o:0,refreshToken:this.storage.get(ie)}}}currentRefresh(){return this.readDisk().legacy.refreshToken}static recordTrusted(e){return!!e.record&&!!e.legacy.refreshToken&&e.record.refreshToken===e.legacy.refreshToken}writeSession(e){this.storage.set(oe,JSON.stringify(e.user)),e.accessToken?(this.storage.set(M,e.accessToken),this.storage.set(F,String(e.accessExpiresAt))):(this.storage.remove(M),this.storage.remove(F)),this.storage.set(ie,e.refreshToken),this.storage.set(Y,JSON.stringify(e)),this.storage.get(Ge)!=="2"&&this.storage.set(Ge,"2")}clearRecord(){this.storage.remove(Y)}writeLimboTokens(e){this.storage.set(M,e.accessToken),this.storage.set(F,String(e.accessExpiresAt)),this.storage.set(ie,e.refreshToken)}clearSession(){for(let e of We)this.storage.remove(e)}clearStaleBlob(){this.storage.remove(oe),this.storage.remove(M),this.storage.remove(F),this.storage.remove(Y)}readSlots(){let e=[],t=[];return j.forEach((r,n)=>{let{slot:i,unreadable:o}=Ke(this.storage.get(r));e.push(i),o&&t.push(n)}),{slots:e,unreadable:t}}readSlot(e){return Ke(this.storage.get(j[e])).slot}writeSlot(e,t){let r=j[e];t===null?this.storage.remove(r):this.storage.set(r,JSON.stringify(t))}freeSlot(){let{slots:e,unreadable:t}=this.readSlots();for(let r=0;r<e.length;r++)if(e[r]===null&&!t.includes(r))return r;return null}readMintKey(){return this.storage.get(ae)}writeMintKey(e){this.storage.set(ae,e)}clearMintKey(){this.storage.remove(ae)}};var Ve=["unknown","signed_out","anonymous","identified","withheld"],T=5,le=["INVALID_REFRESH_TOKEN"],ue=["expired","revoked","evicted","deleted","reuse","unknown"],de=["deleted","revoked","expired"],ce="AMBIGUOUS_HELD_GUEST",$e=["MINT","SIGN_IN","LINK","CLAIM","RESTORE","DISCARD","DELETE","SESSION_VERB"],G={SESSION_WITHHELD:"SESSION_WITHHELD",PROJECT_MISMATCH:"PROJECT_MISMATCH"};var qe="project";function he(s,e){if(s===void 0)return"match";let t=E(e);if(t===null||!Object.prototype.hasOwnProperty.call(t,qe))return"unknown";let r=t[qe];return r===null?"mismatch":typeof r=="string"&&r===s?"match":"mismatch"}function E(s){if(typeof s!="string"||s.length===0)return null;let e=s.split(".");if(e.length!==3)return null;let t=Nt(e[1]);if(t===null)return null;let r=Ot(t);if(r===null)return null;let n;try{n=JSON.parse(r)}catch{return null}return n===null||typeof n!="object"||Array.isArray(n)?null:n}var xt=(()=>{let s=new Int16Array(128).fill(-1),e="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";for(let t=0;t<e.length;t++)s[e.charCodeAt(t)]=t;return s[45]=62,s[95]=63,s[43]=62,s[47]=63,s})();function Nt(s){let e=s.length;for(;e>0&&s.charCodeAt(e-1)===61;)e--;if(e%4===1)return null;let t=new Uint8Array(Math.floor(e*3/4)),r=0,n=0,i=0;for(let o=0;o<e;o++){let a=s.charCodeAt(o),l=a<128?xt[a]:-1;if(l<0)return null;r=r<<6|l,n+=6,n>=8&&(n-=8,t[i++]=r>>n&255)}return i===t.length?t:t.subarray(0,i)}function Ot(s){let e="",t=0,r=s.length;for(;t<r;){let n=s[t],i,o;if(n<128)i=n,o=0;else if(n>=194&&n<=223)i=n&31,o=1;else if(n>=224&&n<=239)i=n&15,o=2;else if(n>=240&&n<=244)i=n&7,o=3;else return null;if(t+o>=r)return null;for(let a=1;a<=o;a++){let l=s[t+a];if((l&192)!==128)return null;i=i<<6|l&63}if(o===2&&i<2048||o===3&&(i<65536||i>1114111)||i>=55296&&i<=57343)return null;if(i>65535){let a=i-65536;e+=String.fromCharCode(55296+(a>>10),56320+(a&1023))}else e+=String.fromCharCode(i);t+=o+1}return e}var Be=3e4,Ht=5*6e4,Mt=/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;function Te(s){if(!s||typeof s!="object")return!1;let e=s,t=e.user,r=e.tokens;return!(!t||typeof t.id!="string"||t.id.length===0||!r||typeof r.accessToken!="string"||r.accessToken.length===0||typeof r.refreshToken!="string"||r.refreshToken.length===0||typeof r.expiresIn!="number"||r.expiresIn<=0||t.isAnonymous!==void 0&&typeof t.isAnonymous!="boolean"||t.email!==void 0&&t.email!==null&&typeof t.email!="string"||t.emailVerified!==void 0&&typeof t.emailVerified!="boolean"||t.name!==void 0&&t.name!==null&&typeof t.name!="string"||t.signupMethod!==void 0&&t.signupMethod!==null&&typeof t.signupMethod!="string"||t.lastLoginMethod!==void 0&&t.lastLoginMethod!==null&&typeof t.lastLoginMethod!="string"||t.project!==void 0&&t.project!==null&&typeof t.project!="string"||e.retiredAnonUserId!==void 0&&typeof e.retiredAnonUserId!="string")}var b=class extends Error{constructor(e="An account with this email already exists"){super(e),this.name="EmailAlreadyTakenError"}},K=class extends Error{constructor(e="Already signed in with an identity; use link*() to add a credential, or sign out first"){super(e),this.name="AlreadyIdentifiedError"}},C=class extends Error{constructor(t="This credential is already linked to a different account",r){super(t);this.code="CREDENTIAL_IN_USE";this.kind="credential_in_use";this.retryable=!1;this.name="CredentialInUseError",this.provider=r?.provider,this.collision=r?.collision,this.status=r?.status}};function Ft(s){let e=s?.error?.details;if(!e||typeof e!="object")return{};let t=e;return{provider:typeof t.provider=="string"?t.provider:void 0,collision:t.collision==="identity"||t.collision==="email"?t.collision:void 0}}function ze(s){let e=s?.error?.details;if(!e||typeof e!="object")return;let t=e.endReason;return typeof t=="string"&&ue.includes(t)?t:void 0}var jt=new Set(["network","server","rate_limited","account_locked"]);function Gt(s,e){switch(s){case"NETWORK_ERROR":case"NETWORK_TIMEOUT":return"network";case"PARSE_ERROR":case"RESTORE_FAILED":return"server";case"RATE_LIMITED":case"RATE_LIMIT":case"RATE_LIMIT_EXCEEDED":case"QUOTA_EXCEEDED":return"rate_limited";case"ACCOUNT_LOCKED":return"account_locked";case"CREDENTIAL_IN_USE":return"credential_in_use";case"LAST_CREDENTIAL":return"last_credential";case"RECENT_AUTH_REQUIRED":return"recent_auth_required";case"NOT_ANONYMOUS":case"FORBIDDEN_NON_ANONYMOUS":return"already_identified";case"PASSKEY_USER_CANCELLED":case"GAME_CENTER_CANCELLED":case"PLAY_GAMES_CANCELLED":case"SSO_CANCELLED":case"SIGN_IN_SUPERSEDED":case"LINK_SUPERSEDED":case"CLAIM_SUPERSEDED":case"HELD_GUEST_CHANGED":return"cancelled";case"GAME_CENTER_UNAVAILABLE":case"PLAY_GAMES_UNAVAILABLE":case"ENTITLEMENT_ERROR":case"tier_required":case"SESSION_WITHHELD":case"PROJECT_MISMATCH":case"HELD_GUEST_LIMIT":case"HELD_GUEST_PROJECT_MISMATCH":case"UNSUPPORTED_LINK_CREDENTIAL":return"config";case"UNAUTHORIZED":case"INVALID_CREDENTIALS":case"INVALID_REFRESH_TOKEN":case"EMAIL_OTP_INVALID":case"MAGIC_LINK_INVALID":case"PASSKEY_RP_MISMATCH":case"NOT_SIGNED_IN":case"AMBIGUOUS_HELD_GUEST":case"HELD_GUEST_NOT_FOUND":case"HELD_GUEST_GONE":case"NOT_IDENTIFIED":case"CREDENTIAL_STALE":case"MFA_REQUIRED":return"invalid_credential";default:break}if(typeof e=="number"){if(e===429)return"rate_limited";if(e>=500)return"server";if(e>=400)return"invalid_credential"}return"unknown"}var u=class extends Error{constructor(e,t,r){super(t),this.name="AuthError",this.code=e,this.kind=r?.kind??Gt(e,r?.status),this.retryable=jt.has(this.kind),this.retryAfterSeconds=r?.retryAfterSeconds,this.status=r?.status}},W=class extends u{constructor(e,t=`Every held-guest slot is occupied (${5}); restore or discard one first`){super("HELD_GUEST_LIMIT",t,{kind:"config"}),this.name="HeldGuestLimitError",this.heldGuests=e}},_=class extends u{constructor(e,t,r){super("HELD_GUEST_PROJECT_MISMATCH",`Held guest ${e} belongs to project ${r??"null"}, not ${t}`,{kind:"config"}),this.name="HeldGuestProjectMismatch",this.userId=e,this.expectedProjectId=t,this.actualProjectId=r}};function Kt(s){if(s instanceof u||s instanceof b||s instanceof K||s instanceof C)return s;let e=s?.name;return e==="AbortError"||e==="TimeoutError"||e==="NetworkTimeoutError"?new u("NETWORK_TIMEOUT",s instanceof Error?s.message:"timeout",{kind:"network"}):new u("UNKNOWN_ERROR",s instanceof Error?s.message:String(s),{kind:"unknown"})}function p(s){let e=s.error?.status,t=s.error?.details?.retryAfterSeconds;return{status:typeof e=="number"?e:void 0,retryAfterSeconds:typeof t=="number"&&Number.isFinite(t)&&t>0?t:void 0}}var V=class{constructor(e,t,r,n,i,o,a={}){this.state="unknown";this.record=null;this.user=null;this.accessToken=null;this.accessExpiresAt=0;this.withheld=null;this.clockSkewConfirmed=!1;this.inflight=Promise.resolve();this.refreshInflight=null;this.attemptInFlight=!1;this.refreshFailureCount=0;this.refreshCooldownUntil=0;this.visibilityResetUnsub=null;this.proactiveRefreshTimer=null;this.proactiveRefreshCleanup=null;this.storageEventUnsub=null;this.rehydrateScheduled=!1;this.takeoverListeners=new Set;this.lastTakeover=null;this.deletionCancelledListeners=new Set;this.lastDeletionCancelled=null;this.lastAnonRetirement=null;this.authStateListeners=new Set;this.identityWithheldListeners=new Set;this.hydrated=!1;this.http=t,this.storage=r,this.store=new J(r),this.analytics=n,this.flags=i,this.chatbot=o,this.hooks=a,this.expectedProjectId=e.expectedProjectId,this.slotProjectAnchor=e.expectedProjectId??e.projectId,this.autoRestoreHeldGuest=e.autoRestoreHeldGuest!==!1,this.hydrateFromDisk("boot"),this.hydrated=!0,this.startStorageEventRehydrate()}status(){return this.state}authStateReady(){return Promise.resolve(this.state)}getCurrentUser(){return this.user}getUserSync(){return this.user}isReady(){return this.hydrated}onDeviceTakeover(e){return this.takeoverListeners.add(e),()=>{this.takeoverListeners.delete(e)}}getLastDeviceTakeover(){return this.lastTakeover}onAuthStateChanged(e){if(this.authStateListeners.add(e),this.hydrated){let t=this.user,r={event:"initial",status:this.state,user:t,...this.withheld?{withheld:this.withheld.info}:{}};try{e(r)}catch{}if(t)try{e({event:"signed_in",user:t})}catch{}}return()=>{this.authStateListeners.delete(e)}}onIdentityWithheld(e){return this.identityWithheldListeners.add(e),()=>{this.identityWithheldListeners.delete(e)}}emitAuthState(e){for(let t of this.authStateListeners)try{t(e)}catch{}}fireDeviceTakeover(e,t){if(!e||!Mt.test(e))return;let r={retiredAnonUserId:e,identifiedUserId:t,at:new Date};this.lastTakeover=r;for(let n of this.takeoverListeners)try{n(r)}catch{}this.emitAuthState({event:"device_takeover",user:this.user,retiredAnonUserId:e})}onDeletionCancelled(e){return this.deletionCancelledListeners.add(e),()=>{this.deletionCancelledListeners.delete(e)}}getLastDeletionCancelled(){return this.lastDeletionCancelled}getLastAnonRetirement(){return this.lastAnonRetirement}fireDeletionCancelled(e){let t={userId:e,at:new Date};this.lastDeletionCancelled=t;for(let r of this.deletionCancelledListeners)try{r(t)}catch{}this.emitAuthState({event:"deletion_cancelled",user:this.user})}recordServerSignals(e){e.anonRetirement&&(this.lastAnonRetirement=e.anonRetirement),e.retiredAnonUserId&&this.fireDeviceTakeover(e.retiredAnonUserId,e.user.id),e.reactivatedFromDeletion&&this.fireDeletionCancelled(e.user.id)}commit(e){switch(e.type){case"install":return this.commitInstall(e);case"clear":return this.commitClear(e);case"user":{if(this.currentSid()!==e.expectSid||!this.record)return!1;let t={...this.record,user:e.user};return this.record=t,this.user=e.user,this.store.writeSession(t),this.analytics.identify(e.user.id),this.flags.setContext({userId:e.user.id}),this.emitAuthState({event:"user_updated",user:e.user,cause:e.cause}),!0}case"release":{let t=this.store.readSlot(e.index);return t?(this.store.writeSlot(e.index,null),this.emitAuthState({event:"guest_released",userId:t.userId,reason:e.reason,...e.endReason?{endReason:e.endReason}:{}}),!0):!1}case"slot_tokens":{let t=this.store.readSlot(e.index);return!t||t.refreshToken!==e.sent?!1:(this.store.writeSlot(e.index,{...t,refreshToken:e.refreshToken,...e.project!==void 0&&t.project===null?{project:e.project}:{}}),!0)}case"withhold":return this.commitWithhold(e);case"unknown":return this.state="unknown",this.record=null,this.user=null,this.withheld=null,this.accessToken=e.accessToken,this.accessExpiresAt=e.accessExpiresAt,this.startProactiveRefreshCron(),this.startVisibilityRefreshReset(),!0;case"held_reported":{if(!this.record?.heldReportPending?.includes(e.userId))return!1;let t=this.record.heldReportPending.filter(n=>n!==e.userId),r={...this.record};return t.length>0?r.heldReportPending=t:delete r.heldReportPending,this.record=r,this.store.writeSession(r),!0}default:return!1}}commitInstall(e){if(e.expectSid!==void 0&&this.currentSid()!==e.expectSid||e.expectRefresh!==void 0&&this.store.currentRefresh()!==e.expectRefresh)return!1;let t=this.record,r=t?.user??null,n=r?.id!==e.record.user.id,i=null,o={...e.record};if(e.hold){let a=this.store.freeSlot();if(a===null)return!1;this.store.writeSlot(a,e.hold),i=this.heldCount();let l=new Set(t?.heldReportPending??[]);l.add(e.hold.userId),o.heldReportPending=[...l]}else t?.heldReportPending&&!o.heldReportPending&&!n&&(o.heldReportPending=t.heldReportPending);switch(r&&n&&(this.analytics.reset(!1),this.flags.reset(),this.chatbot.newSession(),e.revokePrevious&&t&&!r.isAnonymous&&this.revokeFireAndForget(t.refreshToken)),this.state=o.user.isAnonymous===!1?"identified":"anonymous",this.record=o,this.user=o.user,this.accessToken=o.accessToken,this.accessExpiresAt=o.accessExpiresAt,this.withheld=null,n&&(this.clockSkewConfirmed=!1,this.lastTakeover=null,this.lastDeletionCancelled=null,this.lastAnonRetirement=null),(e.reason!=="hydrate"||e.persist!==!1)&&this.store.writeSession(o),this.analytics.identify(o.user.id),this.flags.setContext({userId:o.user.id}),this.startProactiveRefreshCron(),this.startVisibilityRefreshReset(),this.refreshFailureCount=0,this.refreshCooldownUntil=0,e.hold&&i!==null&&this.emitAuthState({event:"guest_held",userId:e.hold.userId,count:i}),e.reason){case"mint":this.emitAuthState({event:"signed_in",user:o.user,cause:"mint"});break;case"sign_in":this.emitAuthState({event:"signed_in",user:o.user,cause:"sign_in"});break;case"upgrade":this.emitAuthState({event:"signed_in",user:o.user,cause:"link"});break;case"link":this.emitAuthState({event:"user_updated",user:o.user,cause:"link"});break;case"restore":this.emitAuthState({event:"signed_in",user:o.user,cause:"restore"});break;case"claim":this.emitAuthState({event:"user_updated",user:o.user,cause:"merge"});break;case"recover":this.emitAuthState({event:"signed_in",user:o.user});break;case"rehydrate":n&&this.emitAuthState({event:"signed_in",user:o.user});break;case"refresh":r&&JSON.stringify(r)!==JSON.stringify(o.user)&&this.emitAuthState({event:"user_updated",user:o.user,cause:"refresh"});break;case"hydrate":break;default:break}return e.release&&this.commit({type:"release",index:e.release.index,reason:e.release.reason}),e.hold&&this.reportHeld(e.hold.userId,e.hold.refreshToken),!0}commitClear(e){let t=this.record?.refreshToken??this.withheld?.refreshToken??this.store.currentRefresh();if(e.expectRefresh!==void 0&&this.store.currentRefresh()!==e.expectRefresh)return!1;let r=this.state!=="signed_out";if(this.state="signed_out",this.record=null,this.user=null,this.accessToken=null,this.accessExpiresAt=0,this.withheld=null,this.clockSkewConfirmed=!1,this.lastTakeover=null,this.lastDeletionCancelled=null,this.lastAnonRetirement=null,this.store.clearSession(),e.stampNoAutoRestore){let{slots:n}=this.store.readSlots();n.forEach((i,o)=>{i&&i.autoRestore&&this.store.writeSlot(o,{...i,autoRestore:!1})})}return e.keepAnalyticsIdentity||this.analytics.reset(e.reason==="user"||e.reason==="account_deleted"),e.dropQueue&&this.analytics.dropQueue(),this.flags.reset(),this.chatbot.newSession(),this.stopProactiveRefreshCron(),this.stopVisibilityRefreshReset(),this.refreshFailureCount=0,this.refreshCooldownUntil=0,e.revoke&&t&&this.revokeFireAndForget(t),r&&this.emitAuthState(e.endReason!==void 0?{event:"signed_out",user:null,reason:e.reason,endReason:e.endReason}:{event:"signed_out",user:null,reason:e.reason}),!0}commitWithhold(e){if(e.from==="refresh"){if(!e.rotation||this.store.currentRefresh()!==e.rotation.sent)return!1;this.record?this.store.writeSession({...this.record,accessToken:e.rotation.accessToken,accessExpiresAt:e.rotation.accessExpiresAt,refreshToken:e.rotation.refreshToken}):this.store.writeLimboTokens(e.rotation)}this.state="withheld",this.record=null,this.user=null,this.accessToken=null,this.accessExpiresAt=0,this.withheld={info:e.info,refreshToken:e.rotation?.refreshToken??e.refreshToken},this.stopProactiveRefreshCron(),this.stopVisibilityRefreshReset();try{this.hooks.onIdentityWithheld?.()}catch{}for(let t of this.identityWithheldListeners)try{t()}catch{}return e.from==="refresh"&&this.emitAuthState({event:"session_withheld",reason:"project_mismatch",expectedProjectId:e.info.expectedProjectId,actualProjectId:e.info.actualProjectId,userId:e.info.userId}),!0}hydrateFromDisk(e){let t=this.store.readDisk(),r=t.legacy.refreshToken,n=J.recordTrusted(t),i=t.record!==null&&!n,o=t.legacy.user,a=n?o&&o.id===t.record.user.id?o:t.record.user:o,l=t.legacy.accessToken??(n?t.record.accessToken:null),d=t.legacy.accessToken?t.legacy.accessExpiresAt:n?t.record.accessExpiresAt:0;if(!r){if((a||i||t.legacy.userUnreadable||t.recordUnreadable)&&this.store.clearStaleBlob(),e==="boot"){this.state="signed_out";return}this.state!=="signed_out"&&this.commit({type:"clear",reason:"user",revoke:!1,dropQueue:!1,stampNoAutoRestore:!1});return}if(!a){if(e==="storage_event"&&this.record&&this.record.refreshToken===r)return;i&&this.store.clearRecord(),this.commit({type:"unknown",accessToken:l,accessExpiresAt:d});return}let h=this.judge(l);if(h==="mismatch"){this.commit({type:"withhold",from:"hydrate",info:this.withheldInfo(a,l),refreshToken:r});return}if(h==="unknown"){this.commit({type:"unknown",accessToken:l,accessExpiresAt:d});return}let g={v:1,user:a,accessToken:l,accessExpiresAt:d,refreshToken:r,...t.record?.heldReportPending?{heldReportPending:t.record.heldReportPending}:{}};if(e==="storage_event"&&this.record&&this.record.refreshToken===r&&this.record.user.id===a.id)return;let k=!n||JSON.stringify(t.record.user)!==JSON.stringify(a)||t.record.accessToken!==l;if(this.commit({type:"install",reason:e==="boot"?"hydrate":"rehydrate",record:g,persist:k}),e==="boot"){let{slots:v}=this.store.readSlots();v.forEach((y,w)=>{y&&y.userId===a.id&&this.store.writeSlot(w,null)});for(let y of g.heldReportPending??[]){let w=this.store.readSlots().slots.find(z=>z?.userId===y);w?this.reportHeld(y,w.refreshToken):this.commit({type:"held_reported",userId:y})}}}startStorageEventRehydrate(){if(typeof window>"u"||typeof window.addEventListener!="function"||!this.storage.isPersistent())return;let e=t=>{let r=t.key===null?null:this.storage.relativeKey(t.key);t.key!==null&&(r===null||!r.startsWith("auth_"))||this.rehydrateScheduled||(this.rehydrateScheduled=!0,setTimeout(()=>{this.rehydrateScheduled=!1,this.hydrateFromDisk("storage_event")},0))};window.addEventListener("storage",e),this.storageEventUnsub=()=>window.removeEventListener("storage",e)}stopStorageEventRehydrate(){this.storageEventUnsub&&(this.storageEventUnsub(),this.storageEventUnsub=null)}currentSid(){let e=this.record?.accessToken;if(!e)return null;let t=E(e)?.sid;return typeof t=="string"?t:null}judge(e){return he(this.expectedProjectId,e)}projectClaim(e){let t=E(e)?.project;return typeof t=="string"?t:null}withheldInfo(e,t){return{reason:"project_mismatch",expectedProjectId:this.expectedProjectId??"",actualProjectId:this.projectClaim(t),userId:e.id,isAnonymous:e.isAnonymous!==!1}}heldCount(){return this.store.readSlots().slots.filter(e=>e!==null).length}buildHeld(e){let t=E(e.accessToken)?.sid;return{v:1,userId:e.user.id,sid:typeof t=="string"?t:"",refreshToken:e.refreshToken,tokenAtHold:e.refreshToken,heldAt:Math.max(Date.now(),...this.store.readSlots().slots.map(r=>r?r.heldAt+1:0)),project:this.projectClaim(e.accessToken),autoRestore:!0}}revokeFireAndForget(e){this.http.post("/auth-service/token/revoke",{refreshToken:e}).catch(()=>{})}reportHeld(e,t){this.http.post("/auth-service/guest/held",{refreshToken:t}).then(r=>{r.success&&this.commit({type:"held_reported",userId:e})}).catch(()=>{})}withheldError(){return new u(G.SESSION_WITHHELD,"The stored session belongs to a different project and is withheld; call discardWithheld() or re-init with the matching expectedProjectId",{kind:"config"})}canServeToken(e,t,r){return!e||!t||r>=t-Be?!1:this.clockSkewConfirmed?!0:tt(e,r)}canServeCachedToken(e){return this.canServeToken(this.accessToken,this.accessExpiresAt,e)}trackedDeadlineAlive(e){return!!this.accessToken&&!!this.accessExpiresAt&&e<this.accessExpiresAt-Be}deadlinesDisagree(e){return this.trackedDeadlineAlive(e)&&!this.canServeCachedToken(e)}learnClockSkewFrom(e,t){tt(e,t)||(this.clockSkewConfirmed=!0)}async refreshAndReconcile(e){let t=this.deadlinesDisagree(e),r=await this.refreshAccessToken();return t&&r&&this.learnClockSkewFrom(r,Date.now()),r}async getAccessToken(e){return this.state==="withheld"?null:!e?.forceRefresh&&this.state!=="unknown"&&this.canServeCachedToken(Date.now())?this.accessToken:this.store.currentRefresh()?this.refreshInflight?this.refreshInflight:Date.now()<this.refreshCooldownUntil?null:this.refreshAndReconcile(Date.now()):null}getAccessTokenSync(){return this.accessToken}getRefreshToken(){return this.state==="withheld"?null:this.store.currentRefresh()}async refreshAccessToken(){if(this.refreshInflight)return this.refreshInflight;let e=this.store.currentRefresh();return e?(this.refreshInflight=(async()=>{try{return await this.performRefresh(e)}finally{this.refreshInflight=null}})(),this.refreshInflight):null}async performRefresh(e){try{let t=await this.http.post("/auth-service/token/refresh",{refreshToken:e});if(!t.success)return Qe(t.error?.code)?(this.store.currentRefresh()===e&&this.commit({type:"clear",reason:"session_expired",endReason:ze(t),expectRefresh:e,revoke:!1,dropQueue:!1,stampNoAutoRestore:!1}),this.refreshFailureCount=0,this.refreshCooldownUntil=0,null):(this.armBackoff(),null);let r=X(t.data);if(!r)return this.armBackoff(),null;if(this.store.currentRefresh()!==e)return null;let n=Date.now()+r.expiresIn*1e3,i=this.judge(r.accessToken);if(i==="mismatch"){let a=this.record?.user??pe(t.data);return this.commit({type:"withhold",from:"refresh",info:this.withheldInfo(a??{id:Ze(r.accessToken)??"",email:null,emailVerified:!1,name:null,isAnonymous:!0},r.accessToken),refreshToken:r.refreshToken,rotation:{sent:e,accessToken:r.accessToken,refreshToken:r.refreshToken,accessExpiresAt:n}}),null}let o=pe(t.data);return this.record?this.commit({type:"install",reason:"refresh",record:{...this.record,user:o??this.record.user,accessToken:r.accessToken,accessExpiresAt:n,refreshToken:r.refreshToken},expectRefresh:e}):i==="match"&&o?this.commit({type:"install",reason:"recover",record:{v:1,user:o,accessToken:r.accessToken,accessExpiresAt:n,refreshToken:r.refreshToken},expectRefresh:e}):(this.store.writeLimboTokens({accessToken:r.accessToken,refreshToken:r.refreshToken,accessExpiresAt:n}),this.accessToken=r.accessToken,this.accessExpiresAt=n),this.refreshFailureCount=0,this.refreshCooldownUntil=0,r.accessToken}catch{return this.armBackoff(),null}}async refreshHeld(e,t){let r=t.refreshToken,n=await this.http.post("/auth-service/token/refresh",{refreshToken:r});if(!n.success){if(Qe(n.error?.code)){let a=ze(n);if(a&&de.includes(a))return this.commit({type:"release",index:e,reason:"dead",endReason:a}),{kind:"dead",endReason:a};throw new u("RESTORE_FAILED",`The held guest's token was refused${a?` (${a})`:" with no end reason"}; the slot is kept \u2014 retry later`,{status:p(n).status,kind:"server"})}throw new u(n.error?.code??"RESTORE_FAILED",n.error?.message??"Could not refresh the held guest",p(n))}let i=X(n.data);if(!i)throw new u("RESTORE_FAILED","Malformed refresh response for the held guest; the slot is kept",{kind:"server"});if(!this.commit({type:"slot_tokens",index:e,sent:r,refreshToken:i.refreshToken,...t.project===null?{project:this.projectClaim(i.accessToken)}:{}}))throw new u("HELD_GUEST_CHANGED","The held slot changed while its token was in flight",{kind:"cancelled"});return{kind:"ok",tokens:i,user:pe(n.data)}}async settle(){for(;this.state==="unknown";){if(!this.store.currentRefresh()){this.commit({type:"clear",reason:"user",revoke:!1,dropQueue:!1,stampNoAutoRestore:!1});return}if(await this.refreshAccessToken(),this.state!=="unknown")return;let e=Math.min(3e4,Math.max(250,this.refreshCooldownUntil-Date.now()));await new Promise(t=>setTimeout(t,e))}}armBackoff(){this.refreshFailureCount+=1;let e=Math.min(3e4,1e3*Math.pow(2,this.refreshFailureCount-1));this.refreshCooldownUntil=Date.now()+e}resetRefreshState(){this.refreshFailureCount=0,this.refreshCooldownUntil=0}startVisibilityRefreshReset(){if(this.visibilityResetUnsub||typeof document>"u")return;let e=()=>{document.visibilityState==="visible"&&this.resetRefreshState()};document.addEventListener("visibilitychange",e),this.visibilityResetUnsub=()=>document.removeEventListener("visibilitychange",e)}stopVisibilityRefreshReset(){this.visibilityResetUnsub&&(this.visibilityResetUnsub(),this.visibilityResetUnsub=null)}startProactiveRefreshCron(){if(typeof window>"u"||this.proactiveRefreshTimer)return;let e=.8,t=6e4,r=3e4,n=async()=>{if(this.attemptInFlight||this.state==="withheld")return;if(this.state==="unknown"){Date.now()>=this.refreshCooldownUntil&&await this.refreshAccessToken();return}if(!this.accessToken||!this.accessExpiresAt)return;let o=Date.now();if(!this.canServeCachedToken(o)){await this.refreshAndReconcile(o);return}let a=this.accessExpiresAt-o;if(a<=0)return;let d=Math.max(a,5*6e4)*(1-e)+(Math.random()*r*2-r);a<=d&&await this.refreshAccessToken()};this.proactiveRefreshTimer=window.setInterval(()=>{n()},t);let i=()=>{typeof document<"u"&&document.visibilityState==="visible"&&n()};typeof document<"u"&&document.addEventListener("visibilitychange",i),this.proactiveRefreshCleanup=()=>{this.proactiveRefreshTimer&&(window.clearInterval(this.proactiveRefreshTimer),this.proactiveRefreshTimer=null),typeof document<"u"&&document.removeEventListener("visibilitychange",i)}}stopProactiveRefreshCron(){this.proactiveRefreshCleanup&&(this.proactiveRefreshCleanup(),this.proactiveRefreshCleanup=null)}serialize(e){let t=async()=>{try{return await e()}catch(n){throw Kt(n)}},r=this.inflight.then(t,t);return this.inflight=r.catch(()=>{}),r}async bearerHeaders(){if(this.state==="withheld")throw this.withheldError();let e=await this.getAccessToken();if(!e)throw new u("NOT_SIGNED_IN","Not signed in");return{Authorization:`Bearer ${e}`}}signInAnonymously(e){return this.serialize(async()=>{if(this.state==="withheld")throw this.withheldError();if(this.state==="unknown"&&await this.settle(),this.status()==="withheld")throw this.withheldError();let{slots:t}=this.store.readSlots(),r=t.filter(l=>l!==null),n=this.record;if(n&&!e?.forceNew)return n.user;let i=r.length+(n&&n.user.isAnonymous?1:0);if(e?.forceNew){if(i>=5)throw new W(r.length);return this.mintFresh(e,n)}let o=r.map(l=>({slot:l,index:t.indexOf(l)})).filter(({slot:l})=>l.autoRestore&&!this.slotProjectMismatches(l)).sort((l,d)=>d.slot.heldAt-l.slot.heldAt);if(o.length>0&&(this.autoRestoreHeldGuest||i>=5))for(let{slot:l,index:d}of o)try{let h=await this.restoreSlot(d,l,"mint");if(h)return h}catch(h){if(h instanceof _)continue;throw h}let a=this.heldCount();if(a>=5)throw new W(a);return this.mintFresh(e,null)})}ensureSession(){return this.signInAnonymously()}slotProjectMismatches(e){let t=this.slotProjectAnchor;return t!==void 0&&e.project!==null&&e.project!==t}async mintFresh(e,t){let r=this.currentSid(),n=this.store.readMintKey()??Wt();this.store.writeMintKey(n),this.attemptInFlight=!0;try{await this.refreshInflight;let i=await this.http.post("/auth-service/anonymous",{name:e?.name,metadata:e?.metadata,mintKey:n});if(!i.success||!Te(i.data))throw new u(i.error?.code??"AUTH_ERROR",i.error?.message??"Anonymous signup failed",p(i));let o=i.data;this.guardMinted(o),await this.refreshInflight;let a=this.record,l=a&&a.user.isAnonymous&&t?this.buildHeld(a):void 0;if(!this.commit({type:"install",reason:"mint",record:_e(o),expectSid:r,hold:l,revokePrevious:!!a&&!a.user.isAnonymous}))throw this.revokeFireAndForget(o.tokens.refreshToken),new u("SIGN_IN_SUPERSEDED","The session changed while the mint was in flight; nothing was installed",{kind:"cancelled"});return this.store.clearMintKey(),this.recordServerSignals(o),o.user}finally{this.attemptInFlight=!1}}guardMinted(e){if(this.judge(e.tokens.accessToken)!=="match")throw this.revokeFireAndForget(e.tokens.refreshToken),new u(G.PROJECT_MISMATCH,`The server answered for project ${this.projectClaim(e.tokens.accessToken)??"null"}, not expectedProjectId ${this.expectedProjectId??""}; nothing was installed`,{kind:"config"})}async performSwitch(e,t,r){if(this.state==="withheld")throw this.withheldError();if(this.state==="unknown"&&await this.settle(),this.status()==="withheld")throw this.withheldError();let n=this.currentSid();this.attemptInFlight=!0;try{await this.refreshInflight;let i=await e();if(!i.success||!i.data)throw new u(i.error?.code??t,i.error?.message??r,p(i));let o=i.data;if(o.mfaRequired===!0&&typeof o.mfaChallengeToken=="string"){let g=o.user;return{kind:"mfa",challengeToken:o.mfaChallengeToken,userId:g?.id??""}}if(!Te(i.data))throw new u(i.error?.code??t,i.error?.message??r,p(i));let a=i.data;this.guardMinted(a),this.record&&await this.analytics.flush().catch(()=>{}),await this.refreshInflight;let l=this.record,d=l&&l.user.isAnonymous&&l.user.id!==a.user.id?this.buildHeld(l):void 0;if(!this.commit({type:"install",reason:"sign_in",record:_e(a),expectSid:n,hold:d,revokePrevious:!!l&&!l.user.isAnonymous&&l.user.id!==a.user.id}))throw this.revokeFireAndForget(a.tokens.refreshToken),new u("SIGN_IN_SUPERSEDED","The session changed while the sign-in was in flight; nothing was installed",{kind:"cancelled"});return this.recordServerSignals(a),{kind:"done",user:a.user,previous:l?{userId:l.user.id,isAnonymous:l.user.isAnonymous!==!1,held:!!d}:null,reactivated:a.reactivatedFromDeletion===!0}}finally{this.attemptInFlight=!1}}signIn(e,t){return this.serialize(async()=>{let r=await this.performSwitch(()=>this.http.post("/auth-service/login",{email:e,password:t}),"AUTH_ERROR","Login failed");return r.kind==="mfa"?{mfaRequired:!0,mfaChallengeToken:r.challengeToken,userId:r.userId}:r.user})}challengeMfa(e,t){return this.serialize(async()=>{let r=await this.performSwitch(()=>this.http.post("/auth-service/mfa/challenge",{challengeToken:e,code:t}),"MFA_CHALLENGE_FAILED","Invalid MFA code");if(r.kind==="mfa")throw new u("MFA_CHALLENGE_FAILED","MFA challenge returned another challenge");return r.user})}loginSocial(e){return this.serialize(async()=>{let{link:t,onCredentialInUse:r,...n}=e,i=n,o=()=>this.performSwitch(()=>this.http.post("/auth-service/login/social",i),"SOCIAL_LOGIN_FAILED","Social login failed");if(t){if(this.state==="withheld")throw this.withheldError();if(this.state==="unknown"&&await this.settle(),this.state==="anonymous"||this.state==="identified"){let l=await this.performLink("/auth-service/me/link/social",i,"upgrade");if(l.kind==="done")return l.user;if(l.kind==="recent_auth_required")throw new u("RECENT_AUTH_REQUIRED",l.message??"Re-authenticate to link this credential",{status:l.status??403});if(r==="adopt"){let d=await o();if(d.kind==="mfa")throw new u("MFA_REQUIRED","This account requires MFA; use signIn()/challengeMfa()");return d.user}throw new C(l.message,{provider:l.provider,collision:l.collision,status:l.status})}}let a=await o();if(a.kind==="mfa")throw new u("MFA_REQUIRED","This account requires MFA; use signIn()/challengeMfa()");return a.user})}signInWithGoogle(e,t,r){return this.loginSocial({provider:"google",code:e,redirectUri:t,link:r})}signInWithGitHub(e,t){return this.loginSocial({provider:"github",code:e,redirectUri:t})}signInWithApple(e){return this.loginSocial({provider:"apple",...e})}signInWithMicrosoft(e,t){return this.loginSocial({provider:"microsoft",code:e,redirectUri:t})}signInWithLinkedIn(e,t){return this.loginSocial({provider:"linkedin",code:e,redirectUri:t})}signInWithFacebook(e,t){return this.loginSocial({provider:"facebook",code:e,redirectUri:t})}signInWithDiscord(e,t){return this.loginSocial({provider:"discord",code:e,redirectUri:t})}signInWith(e){return this.serialize(async()=>{let{path:t,body:r}=Ye(e),n=await this.performSwitch(()=>this.http.post(t,r),"AUTH_ERROR","Sign-in failed");if(n.kind==="mfa"){let i=n.challengeToken;return{status:"mfa_required",challengeToken:i,verify:o=>this.signInWith({kind:"mfa",challengeToken:i,code:o})}}return{status:"done",user:n.user,previous:n.previous,reactivated:n.reactivated}})}async performLink(e,t,r){if(this.state==="withheld")throw this.withheldError();let n=this.currentSid();this.attemptInFlight=!0;try{await this.refreshInflight;let i=await this.bearerHeaders(),o=await this.http.post(e,t,i);if(!o.success||!o.data?.user){let d=o.error?.code??"LINK_FAILED",h=p(o);if(d==="CREDENTIAL_IN_USE"){let g=Ft(o);return{kind:"credential_in_use",provider:g.provider??"",collision:g.collision??"identity",status:h.status,message:o.error?.message}}if(d==="RECENT_AUTH_REQUIRED")return{kind:"recent_auth_required",status:h.status,message:o.error?.message};throw new u(d,o.error?.message??"Failed to link credential",h)}let a=o.data,l=o.data.user;if(a.upgraded&&Te(a)){if(this.guardMinted(a),await this.refreshInflight,!this.commit({type:"install",reason:r,record:_e(a),expectSid:n}))throw this.revokeFireAndForget(a.tokens.refreshToken),new u("LINK_SUPERSEDED","The session changed while the link was in flight; nothing was installed",{kind:"cancelled"});return{kind:"done",user:a.user,upgraded:!0,alreadyLinked:!1}}return a.alreadyLinked?{kind:"done",user:l,upgraded:!1,alreadyLinked:!0}:(this.commit({type:"user",user:l,cause:"link",expectSid:n}),{kind:"done",user:l,upgraded:!1,alreadyLinked:!1})}finally{this.attemptInFlight=!1}}link(e){return this.serialize(async()=>{if(this.state==="withheld")throw this.withheldError();if(this.state==="unknown"&&await this.settle(),this.status()==="withheld")throw this.withheldError();if(this.state==="signed_out"){let i=await this.signInWithUnserialized(e);if(i.status!=="done")throw new u("MFA_REQUIRED","This account requires MFA; use signInWith() and complete the challenge");return{status:"done",user:i.user,upgraded:!1,alreadyLinked:!1}}let t=Je(e),r=await this.performLink(t.path,t.body,"link");if(r.kind==="done")return{status:"done",user:r.user,upgraded:r.upgraded,alreadyLinked:r.alreadyLinked};if(r.kind==="recent_auth_required")return{status:"recent_auth_required"};let n=Date.now();return{status:"credential_in_use",provider:r.provider,collision:r.collision,switchAccount:()=>Date.now()-n>Ht?Promise.reject(new u("CREDENTIAL_STALE","The refused credential is older than 5 minutes; obtain it again and call signInWith()")):this.signInWith(e),keepCurrent:()=>{}}})}async signInWithUnserialized(e){let{path:t,body:r}=Ye(e),n=await this.performSwitch(()=>this.http.post(t,r),"AUTH_ERROR","Sign-in failed");if(n.kind==="mfa"){let i=n.challengeToken;return{status:"mfa_required",challengeToken:i,verify:o=>this.signInWith({kind:"mfa",challengeToken:i,code:o})}}return{status:"done",user:n.user,previous:n.previous,reactivated:n.reactivated}}signUp(e,t,r){return this.serialize(async()=>{if(this.state==="withheld")throw this.withheldError();if(this.state==="unknown"&&await this.settle(),this.status()==="withheld")throw this.withheldError();if(this.state==="identified")throw new K;if(this.state==="anonymous"){let i=await this.performLink("/auth-service/me/link/email",{email:e,password:t},"upgrade");if(i.kind==="done")return i.user;throw i.kind==="credential_in_use"?new b(i.message):new u("RECENT_AUTH_REQUIRED",i.message??"Re-authenticate first",{status:i.status??403})}let n=await this.performSwitch(async()=>{let i=await this.http.post("/auth-service/signup",{email:e,password:t,name:r?.name,metadata:r?.metadata});if(!i.success&&i.error?.code==="CONFLICT")throw new b(i.error.message);return i},"AUTH_ERROR","Signup failed");if(n.kind==="mfa")throw new u("MFA_REQUIRED","Unexpected MFA challenge on signup");return n.user})}linkEmailPassword(e,t){return this.linkLegacy({kind:"password",email:e,password:t})}linkSocial(e){let{provider:t,...r}=e;return this.linkLegacy({kind:t,...r})}linkGoogle(e){return this.linkSocial({provider:"google",...e})}linkApple(e){return this.linkSocial({provider:"apple",...e})}linkLegacy(e){return this.serialize(async()=>{if(this.state==="withheld")throw this.withheldError();if(this.state==="unknown"&&await this.settle(),this.status()==="withheld")throw this.withheldError();if(this.state==="signed_out")throw new u("NOT_SIGNED_IN","Sign in before linking a credential");let t=Je(e),r=await this.performLink(t.path,t.body,"link");if(r.kind==="done")return r.user;throw r.kind==="recent_auth_required"?new u("RECENT_AUTH_REQUIRED",r.message??"Re-authenticate to link this credential",{status:r.status??403}):new C(r.message,{provider:r.provider,collision:r.collision,status:r.status})})}getHeldGuests(){return this.store.readSlots().slots.filter(e=>e!==null).sort((e,t)=>t.heldAt-e.heldAt).map(({userId:e,heldAt:t,autoRestore:r,project:n})=>({userId:e,heldAt:t,autoRestore:r,project:n}))}getHeldGuest(){return this.getHeldGuests()[0]??null}resolveSlot(e){let{slots:t}=this.store.readSlots(),r=t.map((n,i)=>n?{slot:n,index:i}:null).filter(n=>n!==null);if(r.length===0)throw new u("HELD_GUEST_NOT_FOUND","No guest is held on this device");if(e!==void 0){let n=r.find(i=>i.slot.userId===e);if(!n)throw new u("HELD_GUEST_NOT_FOUND",`No held guest with id ${e}`);return n}if(r.length>1)throw new u(ce,`${r.length} guests are held; pass the userId of the one you mean`);return r[0]}claimHeldGuest(e){return this.serialize(async()=>{if(this.state==="withheld")throw this.withheldError();if(this.state!=="identified"||!this.record)throw new u("NOT_IDENTIFIED","claimHeldGuest() needs a signed-in identified account as the merge target");let{index:t,slot:r}=this.resolveSlot(e),n=this.currentSid();this.attemptInFlight=!0;try{await this.refreshInflight;let i=await this.refreshHeld(t,r);if(i.kind==="dead")throw new u("HELD_GUEST_GONE",`Held guest ${r.userId} is no longer available (${i.endReason})`);let o=this.store.currentRefresh();if(!o)throw new u("NOT_SIGNED_IN","Not signed in");let a=await this.http.post("/auth-service/merge",{anonymousRefreshToken:i.tokens.refreshToken,targetRefreshToken:o});if(!a.success||!a.data)throw new u(a.error?.code??"MERGE_FAILED",a.error?.message??"Merge failed",p(a));let l=X(a.data),d=Xe(a.data,this.record.user.id,r.userId);await this.refreshInflight;let h=this.record;if(!l||!h)throw this.commit({type:"release",index:t,reason:"claimed"}),new u("MERGE_FAILED","Merge succeeded but returned no rotated session; sign in again",{kind:"server"});if(!this.commit({type:"install",reason:"claim",record:{...h,accessToken:l.accessToken,accessExpiresAt:Date.now()+l.expiresIn*1e3,refreshToken:l.refreshToken},expectSid:n,expectRefresh:o,release:{index:t,reason:"claimed"}}))throw this.commit({type:"release",index:t,reason:"claimed"}),new u("CLAIM_SUPERSEDED","The session changed while the claim was in flight",{kind:"cancelled"});return{user:this.record.user,stats:d}}finally{this.attemptInFlight=!1}})}restoreHeldGuest(e){return this.serialize(async()=>{if(this.state==="withheld")throw this.withheldError();if(this.state==="unknown"&&await this.settle(),this.status()==="withheld")throw this.withheldError();let{index:t,slot:r}=this.resolveSlot(e),n=await this.restoreSlot(t,r,"verb");if(!n)throw new u("HELD_GUEST_GONE",`Held guest ${r.userId} is no longer available`);return n})}async restoreSlot(e,t,r){let n=this.slotProjectAnchor;if(n!==void 0&&t.project!==null&&t.project!==n)throw new _(t.userId,n,t.project);let i=this.currentSid();this.attemptInFlight=!0;try{await this.refreshInflight;let o=await this.refreshHeld(e,t);if(o.kind==="dead")return null;if(this.judge(o.tokens.accessToken)!=="match")throw new _(t.userId,this.expectedProjectId??n??"",this.projectClaim(o.tokens.accessToken));let l=o.user??et(o.tokens.accessToken,t.userId);await this.refreshInflight;let d=this.record,h=d&&d.user.isAnonymous&&d.user.id!==l.id?this.buildHeld(d):void 0;if(!this.commit({type:"install",reason:"restore",record:{v:1,user:l,accessToken:o.tokens.accessToken,accessExpiresAt:Date.now()+o.tokens.expiresIn*1e3,refreshToken:o.tokens.refreshToken},expectSid:i,hold:h,release:{index:e,reason:"restored"},revokePrevious:!!d&&!d.user.isAnonymous}))throw new u("SIGN_IN_SUPERSEDED",`The session changed while restoring${r==="mint"?" (auto-restore)":""}; nothing was installed`,{kind:"cancelled"});return l}finally{this.attemptInFlight=!1}}discardHeldGuest(e){return this.serialize(async()=>{if(this.state==="withheld")throw this.withheldError();let{index:t,slot:r}=this.resolveSlot(e);await this.discardSlot(t,r)})}async discardSlot(e,t){let r=await this.http.post("/auth-service/guest/discard",{refreshToken:t.refreshToken}),n=r.error?.status;if(r.success||n===404||r.error?.code==="NOT_FOUND"){this.commit({type:"release",index:e,reason:"discarded"});return}throw new u(r.error?.code??"GUEST_DISCARD_FAILED",r.error?.message??"Could not discard the held guest",p(r))}merge(e){let{slots:t}=this.store.readSlots(),r=t.find(n=>n!==null&&(n.refreshToken===e||n.tokenAtHold===e));return r?this.claimHeldGuest(r.userId).then(n=>n.stats):this.serialize(async()=>{if(this.state==="withheld")throw this.withheldError();if(this.state!=="identified"||!this.record)throw new u("NOT_IDENTIFIED","merge() needs a signed-in identified account as the target");let n=this.currentSid(),i=this.store.currentRefresh();if(!i)throw new u("NOT_SIGNED_IN","Not signed in");let o=await this.http.post("/auth-service/merge",{anonymousRefreshToken:e,targetRefreshToken:i});if(!o.success||!o.data)throw new u(o.error?.code??"MERGE_FAILED",o.error?.message??"Merge failed",p(o));let a=X(o.data),l=Xe(o.data,this.record.user.id,"");await this.refreshInflight;let d=this.record;return a&&d&&this.commit({type:"install",reason:"claim",record:{...d,accessToken:a.accessToken,accessExpiresAt:Date.now()+a.expiresIn*1e3,refreshToken:a.refreshToken},expectSid:n,expectRefresh:i}),l})}getWithheld(){return this.withheld?.info??null}discardWithheld(){return this.serialize(async()=>this.discardWithheldNow())}discardWithheldNow(){return this.state!=="withheld"||!this.withheld?!1:this.commit({type:"clear",reason:"user",expectRefresh:this.withheld.refreshToken,revoke:!0,dropQueue:!1,stampNoAutoRestore:!1,keepAnalyticsIdentity:!0})?!0:(this.hydrateFromDisk("storage_event"),!1)}signOut(){return this.serialize(async()=>{if(this.state==="withheld"){this.discardWithheldNow();return}if(this.state==="signed_out"){this.analytics.reset(!0),this.flags.reset(),this.chatbot.newSession();return}this.commit({type:"clear",reason:"user",revoke:!0,dropQueue:!1,stampNoAutoRestore:!1})})}deleteAccount(e){return this.serialize(async()=>{if(this.state==="withheld")throw this.withheldError();if(this.state==="unknown"&&await this.settle(),this.status()==="withheld")throw this.withheldError();if(this.state==="signed_out")throw new u("NOT_SIGNED_IN","Sign in before deleting your account");let t=await this.bearerHeaders(),r=await this.http.delete("/auth-service/me",t);if(!r.success)throw new u(r.error?.code??"DELETE_ACCOUNT_FAILED",r.error?.message??"Account deletion failed",p(r));let n=r.data??{};this.commit({type:"clear",reason:"account_deleted",revoke:!1,dropQueue:!0,stampNoAutoRestore:!0});let i={status:n.status==="purged"?"purged":"pending",scheduledPurgeAt:n.scheduledPurgeAt??null,graceDays:typeof n.graceDays=="number"?n.graceDays:0,heldGuests:this.heldCount()};if(e?.alsoDiscardHeldGuests){let o=[],{slots:a}=this.store.readSlots();for(let l=0;l<a.length;l++){let d=a[l];if(d)try{await this.discardSlot(l,d)}catch{o.push(d.userId)}}i.heldGuests=this.heldCount(),i.discardFailed=o}return i})}async listLinkedIdentities(){let e=await this.bearerHeaders().catch(()=>{throw new u("NOT_SIGNED_IN","Sign in before listing linked identities")}),t=await this.http.get("/auth-service/me/identities",e);if(!t.success||!t.data)throw new u(t.error?.code??"IDENTITIES_FAILED",t.error?.message??"Failed to list linked identities",p(t));return{identities:t.data.identities??[],hasPassword:!!t.data.hasPassword}}async unlink(e){let t=await this.bearerHeaders().catch(()=>{throw new u("NOT_SIGNED_IN","Sign in before unlinking an identity")}),r=await this.http.delete(`/auth-service/me/identities/${encodeURIComponent(e)}`,t);if(!r.success||!r.data)throw new u(r.error?.code??"UNLINK_FAILED",r.error?.message??"Failed to unlink identity",p(r));return{provider:r.data.provider??e,removed:Number(r.data.removed??0),remaining:Number(r.data.remaining??0)}}async sendMagicLink(e){let t=await this.http.post("/auth-service/magic-link/request",{email:e});if(!t.success)throw new u(t.error?.code??"MAGIC_LINK_REQUEST_FAILED",t.error?.message??"Failed to send link")}async sendEmailOtp(e){let t=await this.http.post("/auth-service/email-otp/request",{email:e});if(!t.success)throw new u(t.error?.code??"EMAIL_OTP_REQUEST_FAILED",t.error?.message??"Failed to send code")}verifyEmailOtp(e,t){return this.serialize(async()=>{let r=await this.performSwitch(()=>this.http.post("/auth-service/email-otp/verify",{email:e,code:t}),"EMAIL_OTP_INVALID","Wrong or expired code");if(r.kind==="mfa")throw new u("MFA_REQUIRED","This account requires MFA; use signIn()/challengeMfa()");return r.user})}verifyMagicLink(e){return this.serialize(async()=>{let t=await this.performSwitch(()=>this.http.post("/auth-service/magic-link/verify",{token:e}),"MAGIC_LINK_INVALID","Invalid or expired magic link");if(t.kind==="mfa")throw new u("MFA_REQUIRED","This account requires MFA; use signIn()/challengeMfa()");return t.user})}async requestPasswordReset(e){let t=await this.http.post("/auth-service/password/forgot",{email:e});if(!t.success)throw new u(t.error?.code??"PASSWORD_RESET_REQUEST_FAILED",t.error?.message??"Failed to send reset email")}async resetPassword(e,t){let r=await this.http.post("/auth-service/password/reset",{token:e,newPassword:t});if(!r.success)throw new u(r.error?.code??"PASSWORD_RESET_FAILED",r.error?.message??"Reset failed")}async verifyEmail(e){let t=await this.http.post("/auth-service/email/verify",{token:e});if(!t.success)throw new u(t.error?.code??"EMAIL_VERIFICATION_FAILED",t.error?.message??"Verification failed")}async sendVerificationEmail(){let e=await this.bearerHeaders().catch(r=>{throw r instanceof u&&r.code===G.SESSION_WITHHELD?r:new u("UNAUTHORIZED","Sign in before requesting a verification email")}),t=await this.http.post("/auth-service/email/verify/resend",{},e);if(!t.success)throw new u(t.error?.code??"VERIFICATION_RESEND_FAILED",t.error?.message??"Failed to send verification email")}async enrollMfa(){let e=await this.http.post("/auth-service/mfa/enroll/start",{},await this.bearerHeaders());if(!e.success||!e.data)throw new u(e.error?.code??"MFA_ENROLL_FAILED",e.error?.message??"MFA enrollment failed");return e.data}async confirmMfa(e){let t=await this.http.post("/auth-service/mfa/enroll/confirm",{code:e},await this.bearerHeaders());return!!(t.success&&t.data?.confirmed)}async disableMfa(){let e=await this.http.post("/auth-service/mfa/disable",{},await this.bearerHeaders());if(!e.success)throw new u(e.error?.code??"MFA_DISABLE_FAILED",e.error?.message??"Failed to disable MFA",p(e))}async registerPasskey(e){if(typeof navigator>"u"||!navigator.credentials)throw new u("PASSKEY_UNSUPPORTED","WebAuthn not supported in this environment");let t=await this.http.post("/auth-service/passkeys/register/start",{},await this.bearerHeaders());if(!t.success||!t.data)throw new u(t.error?.code??"PASSKEY_START_FAILED",t.error?.message??"Passkey start failed");let r=Vt(t.data),n;try{let a=await navigator.credentials.create({publicKey:r});if(!a)throw new Error("create returned null");n=a}catch(a){throw new u("PASSKEY_USER_CANCELLED",a instanceof Error?a.message:"User cancelled passkey registration")}let i=qt(n),o=await this.http.post("/auth-service/passkeys/register/finish",{response:i,name:e},await this.bearerHeaders());if(!o.success||!o.data)throw new u(o.error?.code??"PASSKEY_FINISH_FAILED",o.error?.message??"Passkey verification failed");return o.data}signInWithPasskey(e){return this.serialize(async()=>{if(typeof navigator>"u"||!navigator.credentials)throw new u("PASSKEY_UNSUPPORTED","WebAuthn not supported in this environment");if(this.state==="withheld")throw this.withheldError();let t=await this.http.post("/auth-service/passkeys/authenticate/start",{userId:e??null});if(!t.success||!t.data)throw new u(t.error?.code??"PASSKEY_START_FAILED",t.error?.message??"Passkey start failed",p(t));let r=$t(t.data),n;try{let a=await navigator.credentials.get({publicKey:r});if(!a)throw new Error("get returned null");n=a}catch(a){throw new u("PASSKEY_USER_CANCELLED",a instanceof Error?a.message:"User cancelled passkey signin")}let i=Bt(n),o=await this.performSwitch(()=>this.http.post("/auth-service/passkeys/authenticate/finish",{response:i,userId:e??null}),"PASSKEY_AUTH_FAILED","Passkey signin failed");if(o.kind==="mfa")throw new u("MFA_REQUIRED","This account requires MFA; use signIn()/challengeMfa()");return o.user})}async listPasskeys(){let e=await this.http.get("/auth-service/passkeys",await this.bearerHeaders());return!e.success||!Array.isArray(e.data)?[]:e.data}async deletePasskey(e){let t=await this.http.delete(`/auth-service/passkeys/${encodeURIComponent(e)}`,await this.bearerHeaders());if(!t.success)throw new u(t.error?.code??"PASSKEY_DELETE_FAILED",t.error?.message??"Failed to delete passkey",p(t))}async listMySessions(){let e=await this.http.get("/auth-service/sessions/me",await this.bearerHeaders());return!e.success||!Array.isArray(e.data)?[]:e.data}async revokeSession(e){let t=await this.http.delete(`/auth-service/sessions/me/${encodeURIComponent(e)}`,await this.bearerHeaders());if(!t.success)throw new u(t.error?.code??"SESSION_REVOKE_FAILED",t.error?.message??"Failed to revoke session",p(t))}async revokeAllSessions(){let e=await this.http.delete("/auth-service/sessions/me",await this.bearerHeaders());if(!e.success)throw new u(e.error?.code??"SESSION_REVOKE_ALL_FAILED",e.error?.message??"Failed to sign out other devices",p(e))}async startSso(e){let t=await this.http.post("/auth-service/sso/oidc/start",{returnTo:e});if(!t.success||!t.data)throw new u(t.error?.code??"SSO_START_FAILED",t.error?.message??"SSO start failed");return t.data}async signInWithSso(e){let t=e??(typeof window<"u"?window.location.origin:"");if(!t)throw new u("SSO_NO_RETURN_TO","returnTo required outside browser context");let r=await this.startSso(t);typeof window<"u"&&(window.location.href=r.authorizationUrl)}async startSaml(e){let t=await this.http.post("/auth-service/sso/saml/start",{returnTo:e});if(!t.success||!t.data)throw new u(t.error?.code??"SAML_START_FAILED",t.error?.message??"SAML start failed");return t.data}async signInWithSaml(e){let t=e??(typeof window<"u"?window.location.origin:"");if(!t)throw new u("SAML_NO_RETURN_TO","returnTo required outside browser context");let r=await this.startSaml(t);typeof window<"u"&&(window.location.href=r.authorizationUrl)}consumeSsoTokenFromUrl(){return this.serialize(async()=>{if(typeof window>"u")return null;let e=window.location.hash.replace(/^#/,"");if(!e)return null;let t=new URLSearchParams(e),r=t.get("sendora_oidc_error")??t.get("sendora_saml_error");if(r)throw window.history.replaceState(null,"",window.location.pathname+window.location.search),new u("SSO_FAILED",decodeURIComponent(r));let n=t.get("sendora_oidc_token")??t.get("sendora_saml_token");if(!n)return null;let i=t.get("sendora_retired_anon");window.history.replaceState(null,"",window.location.pathname+window.location.search);let o=await this.performSwitch(async()=>{let a=await this.http.post("/auth-service/token/refresh",{refreshToken:n}),l=a.success?X(a.data):null;return l?{success:!0,data:{user:pe(a.data)??et(l.accessToken,Ze(l.accessToken)??"",!1),tokens:{...l,tokenType:"Bearer"}}}:{success:!1,error:a.error??{code:"SSO_EXCHANGE_FAILED",message:"Could not exchange SSO token"}}},"SSO_EXCHANGE_FAILED","Could not exchange SSO token");if(o.kind==="mfa")throw new u("MFA_REQUIRED","Unexpected MFA challenge on SSO exchange");return i&&this.fireDeviceTakeover(i,o.user.id),o.user})}};function Qe(s){return s?le.includes(s):!1}function _e(s){return{v:1,user:s.user,accessToken:s.tokens.accessToken,accessExpiresAt:Date.now()+s.tokens.expiresIn*1e3,refreshToken:s.tokens.refreshToken}}function Wt(){let s="abcdefghijklmnopqrstuvwxyz0123456789",e=new Uint8Array(32),t=globalThis.crypto;if(t?.getRandomValues)t.getRandomValues(e);else for(let n=0;n<e.length;n++)e[n]=Math.floor(Math.random()*256);let r="mk_";for(let n=0;n<e.length;n++)r+=s[e[n]%s.length];return r}function Ye(s){switch(s.kind){case"password":return{path:"/auth-service/login",body:{email:s.email,password:s.password}};case"gameCenter":{let{kind:e,...t}=s;return{path:"/auth-service/login/game-center",body:t}}case"playGames":return{path:"/auth-service/login/play-games",body:{serverAuthCode:s.serverAuthCode}};case"magicLink":return{path:"/auth-service/magic-link/verify",body:{token:s.token}};case"emailOtp":return{path:"/auth-service/email-otp/verify",body:{email:s.email,code:s.code}};case"passkey":return{path:"/auth-service/passkeys/authenticate/finish",body:{response:s.assertion,userId:s.userId??null}};case"mfa":return{path:"/auth-service/mfa/challenge",body:{challengeToken:s.challengeToken,code:s.code}};default:{let{kind:e,...t}=s;return{path:"/auth-service/login/social",body:{provider:e,...t}}}}}function Je(s){switch(s.kind){case"password":return{path:"/auth-service/me/link/email",body:{email:s.email,password:s.password}};case"gameCenter":{let{kind:e,...t}=s;return{path:"/auth-service/me/link/game-center",body:t}}case"playGames":return{path:"/auth-service/me/link/play-games",body:{serverAuthCode:s.serverAuthCode}};case"magicLink":case"emailOtp":case"passkey":case"mfa":throw new u("UNSUPPORTED_LINK_CREDENTIAL",`A ${s.kind} credential cannot be linked; sign in with it instead`);default:{let{kind:e,...t}=s;return{path:"/auth-service/me/link/social",body:{provider:e,...t}}}}}function Xe(s,e,t){let r=s&&typeof s=="object"?s:{},n=i=>typeof r[i]=="number"?r[i]:0;return{mergedUserId:typeof r.mergedUserId=="string"?r.mergedUserId:e,deletedAnonymousId:typeof r.deletedAnonymousId=="string"?r.deletedAnonymousId:t,eventsReassigned:n("eventsReassigned"),profilesReassigned:n("profilesReassigned"),entitiesReassigned:n("entitiesReassigned"),pushTokensReassigned:n("pushTokensReassigned")}}function Ze(s){let e=E(s)?.sub;return typeof e=="string"&&e.length>0?e:null}function et(s,e,t=!0){let r=E(s)??{},n=typeof r.sub=="string"&&r.sub.length>0?r.sub:e,i=typeof r.is_anonymous=="boolean"?r.is_anonymous:t,o={id:n,email:typeof r.email=="string"?r.email:null,emailVerified:typeof r.email_verified=="boolean"?r.email_verified:!i,name:typeof r.name=="string"?r.name:null,isAnonymous:i};if(Object.prototype.hasOwnProperty.call(r,"project")){let a=r.project;o.project=typeof a=="string"?a:null}return o}function Z(s){let e=(4-s.length%4)%4,t=(s+"===".slice(0,e)).replace(/-/g,"+").replace(/_/g,"/"),r=atob(t),n=new ArrayBuffer(r.length),i=new Uint8Array(n);for(let o=0;o<r.length;o++)i[o]=r.charCodeAt(o);return n}function I(s){let e=s instanceof Uint8Array?s:new Uint8Array(s),t="";for(let r=0;r<e.length;r++)t+=String.fromCharCode(e[r]);return btoa(t).replace(/\+/g,"-").replace(/\//g,"_").replace(/=+$/,"")}function Vt(s){return{challenge:Z(s.challenge),rp:s.rp,user:{id:Z(s.user.id),name:s.user.name,displayName:s.user.displayName},pubKeyCredParams:s.pubKeyCredParams,timeout:s.timeout,attestation:s.attestation,excludeCredentials:s.excludeCredentials?.map(e=>({id:Z(e.id),type:"public-key",transports:e.transports})),authenticatorSelection:s.authenticatorSelection}}function $t(s){return{challenge:Z(s.challenge),timeout:s.timeout,rpId:s.rpId,allowCredentials:s.allowCredentials?.map(e=>({id:Z(e.id),type:"public-key",transports:e.transports})),userVerification:s.userVerification}}function qt(s){let e=s.response;return{id:s.id,rawId:I(s.rawId),type:s.type,response:{clientDataJSON:I(e.clientDataJSON),attestationObject:I(e.attestationObject),transports:typeof e.getTransports=="function"?e.getTransports():void 0},clientExtensionResults:s.getClientExtensionResults()}}function X(s){if(!s||typeof s!="object")return null;let e=s.tokens,t=e&&typeof e=="object"?e:s;return typeof t.accessToken!="string"||!t.accessToken||typeof t.refreshToken!="string"||!t.refreshToken||typeof t.expiresIn!="number"||t.expiresIn<=0?null:{accessToken:t.accessToken,refreshToken:t.refreshToken,expiresIn:t.expiresIn}}function pe(s){if(!s||typeof s!="object")return null;let e=s.user;if(!e||typeof e!="object")return null;let t=e.id;return typeof t!="string"||t.length===0?null:e}function tt(s,e){let t=E(s);if(!t)return!0;let r=t.exp;return typeof r!="number"||!Number.isFinite(r)?!0:e<r*1e3}function Bt(s){let e=s.response;return{id:s.id,rawId:I(s.rawId),type:s.type,response:{clientDataJSON:I(e.clientDataJSON),authenticatorData:I(e.authenticatorData),signature:I(e.signature),userHandle:e.userHandle?I(e.userHandle):null},clientExtensionResults:s.getClientExtensionResults()}}var rt=j;function zt(s){return s===!1?{pageViews:!1,sessionStart:!1,appOpen:!1,appBackground:!1,engagement:!1}:s===!0||s===void 0?{pageViews:!0,sessionStart:!0,appOpen:!0,appBackground:!0,engagement:!0}:{pageViews:s.pageViews??!0,sessionStart:s.sessionStart??!0,appOpen:s.appOpen??!0,appBackground:s.appBackground??!0,engagement:s.engagement??!0}}var Qt=250,st=360*60*1e3;function ot(s,e){if(typeof window>"u")return()=>{};let t=zt(e.autoTrack),r=e.sessionIdleMs??18e5,n=[],i="sendora_session_id",o="sendora_session_last_activity";function a(){return nt(i)??""}function l(c){it(i,c)}function d(){let c=nt(o);return c&&Number(c)||0}function h(c){it(o,String(c))}function g(){return`sess_${Date.now().toString(36)}_${Math.random().toString(36).slice(2,10)}`}function k(c){let A=Date.now(),Q=d();if(!a()||Q&&A-Q>r){let te=g();l(te),c&&t.sessionStart&&s.track("session.start",{sessionId:te})}h(A)}k(t.sessionStart),t.appOpen&&s.track("app.opened",{sessionId:a()||void 0,url:window.location.origin+window.location.pathname,referrer:document.referrer||void 0});let v=window.location.pathname,y=0,w=document.visibilityState==="visible"?Date.now():0;function z(){w>0&&(y+=Date.now()-w,w=0)}function ee(){if(!t.engagement)return;z();let c=y;if(y=0,!(c<Qt)){c>st&&(c=st);try{s.track("app.engagement",{durationMs:Math.round(c),screen:v,sessionId:a()||void 0})}catch{}}}function lt(c){v=c,y=0,w=document.visibilityState==="visible"?Date.now():0}if(t.pageViews||t.engagement){t.pageViews&&s.page();let c=()=>{ee(),k(!0),t.pageViews&&s.page(),lt(window.location.pathname)},A=()=>c();window.addEventListener("popstate",A),n.push(()=>window.removeEventListener("popstate",A));let Q=window;if(!Q.__sendoraHistoryPatched){Q.__sendoraHistoryPatched=!0;let te=history.pushState,ut=history.replaceState;history.pushState=function(...ve){let Ae=te.apply(this,ve);return window.dispatchEvent(new Event("sendora:locationchange")),Ae},history.replaceState=function(...ve){let Ae=ut.apply(this,ve);return window.dispatchEvent(new Event("sendora:locationchange")),Ae}}let ke=()=>c();window.addEventListener("sendora:locationchange",ke),n.push(()=>window.removeEventListener("sendora:locationchange",ke))}if(t.appBackground||t.engagement){let c=()=>{if(document.visibilityState==="hidden"){ee(),t.appBackground&&(k(!0),s.track("app.backgrounded",{sessionId:a()||void 0}));try{s.flush()}catch{}}else document.visibilityState==="visible"&&(t.appBackground&&(k(!0),s.track("app.foregrounded",{sessionId:a()||void 0})),t.engagement&&w===0&&(w=Date.now()))};if(document.addEventListener("visibilitychange",c),n.push(()=>document.removeEventListener("visibilitychange",c)),t.engagement){let A=()=>{ee();try{s.flush()}catch{}};window.addEventListener("pagehide",A),n.push(()=>window.removeEventListener("pagehide",A))}}let De=0,D=()=>{let c=Date.now();c-De<5e3||(De=c,k(!0))};return window.addEventListener("click",D,{passive:!0}),window.addEventListener("keydown",D,{passive:!0}),window.addEventListener("scroll",D,{passive:!0}),n.push(()=>{window.removeEventListener("click",D),window.removeEventListener("keydown",D),window.removeEventListener("scroll",D)}),()=>{ee();for(let c of n)try{c()}catch{}}}function nt(s){try{return window.sessionStorage?.getItem(s)??null}catch{return null}}function it(s,e){try{window.sessionStorage?.setItem(s,e)}catch{}}var $=class s{constructor(e){this.http=e}static isSupported(){return typeof window>"u"?!1:"serviceWorker"in navigator&&"PushManager"in window&&"Notification"in window}static permission(){return typeof Notification>"u"?"denied":Notification.permission}async subscribe(e){if(!s.isSupported())throw new Error("[sendoracloud] Web Push not supported in this browser.");let t=Notification.permission;if(t==="default"&&(t=await Notification.requestPermission()),t!=="granted")throw new Error(`[sendoracloud] Notification permission ${t}.`);let r=await navigator.serviceWorker.getRegistration(e.scope??"/");r||(r=await navigator.serviceWorker.register(e.serviceWorkerPath,{scope:e.scope??"/"})),await navigator.serviceWorker.ready;let i=(await this.http.get("/push/vapid"))?.data?.publicKey;if(!i)throw new Error("[sendoracloud] backend returned no VAPID public key.");let a=await r.pushManager.getSubscription()??await r.pushManager.subscribe({userVisibleOnly:!0,applicationServerKey:Yt(i)}),l=a.toJSON(),d=l.endpoint,h=l.keys?.p256dh??"",g=l.keys?.auth??"",k=await Jt(d),v=await this.http.post("/push/tokens",{platform:"web",token:k,webEndpoint:d,webP256dh:h,webAuth:g,userAgent:typeof navigator<"u"?navigator.userAgent:void 0,locale:typeof navigator<"u"?navigator.language:void 0,timezone:Intl?.DateTimeFormat?.().resolvedOptions?.().timeZone,...e.userId?{userId:e.userId}:{}});if(!v?.data?.tokenId)throw new Error("[sendoracloud] backend returned no tokenId on subscribe.");return{tokenId:v.data.tokenId,subscription:a}}async unsubscribe(e="/"){if(!s.isSupported())return!1;let t=await navigator.serviceWorker.getRegistration(e);if(!t)return!1;let r=await t.pushManager.getSubscription();return r?await r.unsubscribe():!1}async trackOpen(e,t){let r={sendId:e};t!==void 0&&(r.clickAction=t);let n=await this.http.post("/push/track-open",r);if(!n.success)throw new Error(n.error?.message??"push.trackOpen failed")}};function Yt(s){let e="=".repeat((4-s.length%4)%4),t=(s+e).replace(/-/g,"+").replace(/_/g,"/"),r=atob(t),n=new Uint8Array(r.length);for(let i=0;i<r.length;i++)n[i]=r.charCodeAt(i);return n}async function Jt(s){let e=new TextEncoder().encode(s),t=await crypto.subtle.digest("SHA-256",e);return Array.from(new Uint8Array(t)).map(n=>n.toString(16).padStart(2,"0")).join("")}var q=class{constructor(e){}unsupported(){throw new Error("[SendoraCloud] sendora.audiences is not available in the browser SDK. Audiences require a secret (sk_*) key with the audiences:read/write scopes and must be managed from a trusted server, not the browser.")}list(){return this.unsupported()}get(e){return this.unsupported()}create(e){return this.unsupported()}update(e,t){return this.unsupported()}delete(e){return this.unsupported()}};var f=class extends Error{constructor(e,t,r){super(t),this.name="LinkError",this.code=e,this.statusCode=r}};function be(s,e){let t=(s??"").toUpperCase();return t==="NOT_FOUND"?new f("NOT_FOUND",e):t==="FORBIDDEN"||t==="UNAUTHORIZED"?new f("UNAUTHORIZED",e):t==="RATE_LIMITED"?new f("RATE_LIMITED",e):t==="ENTITLEMENT_ERROR"||/plan limit/i.test(e)?new f("PLAN_LIMIT",e):t==="VALIDATION_ERROR"?/iOS bundle|Android package/i.test(e)?new f("BUNDLE_MISMATCH",e):/2KB|10KB|linkData/i.test(e)?new f("DATA_TOO_LARGE",e):/fallbackUrl/i.test(e)&&/apps/i.test(e)?new f("FALLBACK_REQUIRED",e):new f("INVALID_INPUT",e):t==="PARSE_ERROR"||t==="HTTP_ERROR"||/HTTP \d{3}/.test(e)?new f("NETWORK",e):new f("UNKNOWN",e||`Unknown LinkError (code=${s??"none"})`)}var Ce=/^[a-z0-9-]{3,20}$/;function at(s){try{let t=new URL(s).pathname.split("/").filter(Boolean);if(t.length===0)return null;let r=t[t.length-1];return Ce.test(r)?r:null}catch{return null}}var Xt=5*6e4,Zt=50,er=5,B=class{constructor(e){this.http=e;this.prewarmCache=new Map;this.prewarmInflight=0}cacheKey(e,t){if(t)return`k:${t}`;let r={},n=e;for(let i of Object.keys(n).sort())r[i]=n[i];return`s:${JSON.stringify(r)}`}evictExpired(){let e=Date.now();for(let[t,r]of this.prewarmCache)e-r.ts>Xt&&this.prewarmCache.delete(t);for(;this.prewarmCache.size>Zt;){let t=this.prewarmCache.keys().next().value;if(t===void 0)break;this.prewarmCache.delete(t)}}prewarm(e,t){this.evictExpired();let r=this.cacheKey(e,t?.key);if(this.prewarmCache.has(r)||this.prewarmInflight>=er)return;this.prewarmInflight++;let n=this.doCreate(e).catch(i=>{throw this.prewarmCache.delete(r),i}).finally(()=>{this.prewarmInflight--});this.prewarmCache.set(r,{promise:n,ts:Date.now()})}async create(e,t){if(!e.title)throw new f("INVALID_INPUT","links.create: title is required");this.evictExpired();let r=this.cacheKey(e,t?.key),n=this.prewarmCache.get(r);return n?(this.prewarmCache.delete(r),n.promise):this.doCreate(e)}async doCreate(e){let t={title:e.title};e.fallbackUrl&&(t.fallbackUrl=e.fallbackUrl),e.iosDeepLinkPath&&(t.iosDeepLinkPath=e.iosDeepLinkPath),e.androidDeepLinkPath&&(t.androidDeepLinkPath=e.androidDeepLinkPath),e.linkData&&(t.linkData=e.linkData),e.ogTitle&&(t.ogTitle=e.ogTitle),e.ogDescription&&(t.ogDescription=e.ogDescription),e.ogImageUrl&&(t.ogImageUrl=e.ogImageUrl),e.campaign&&(t.campaign=e.campaign),e.source&&(t.source=e.source),e.medium&&(t.medium=e.medium),e.channel&&(t.channel=e.channel),e.tags&&(t.tags=e.tags),e.expiresAt&&(t.expiresAt=e.expiresAt),e.iosBundleId&&(t.iosBundleId=e.iosBundleId),e.androidPackageName&&(t.androidPackageName=e.androidPackageName);let r=await this.http.post("/sdk/links",t);if(!r.success||!r.data)throw be(r.error?.code,r.error?.message??"links.create failed");return r.data}async revoke(e){if(!Ce.test(e))throw new f("INVALID_INPUT",`links.revoke: '${e}' is not a valid shortcode`);let t=await this.http.post(`/sdk/links/${encodeURIComponent(e)}/revoke`,{});if(!t.success||!t.data)throw be(t.error?.code,t.error?.message??"links.revoke failed");return{shortcode:t.data.shortcode,revoked:!0}}async getStats(e){if(!Ce.test(e))throw new f("INVALID_INPUT",`links.getStats: '${e}' is not a valid shortcode`);let t=await this.http.get(`/sdk/links/${encodeURIComponent(e)}/stats`);if(!t.success||!t.data)throw be(t.error?.code,t.error?.message??"links.getStats failed");return t.data}};var fe=class{constructor(e){this.http=e}async reportInstall(e={}){let t=await this.http.post("/attribution/install",e);if(!t.success||!t.data)throw new Error(t.error?.message??"attribution.reportInstall failed");return t.data}async checkDeferred(e={}){let t=await this.http.post("/attribution/deferred",e);if(!t.success)throw new Error(t.error?.message??"attribution.checkDeferred failed");return t.data??null}};var ge=class{constructor(e){this.http=e}async createTicket(e){let t=await this.http.post("/support/tickets",e);if(!t.success||!t.data)throw new Error(t.error?.message??"support.createTicket failed");return t.data}async submitCsat(e){let t=await this.http.post("/support/csat",e);if(!t.success||!t.data)throw new Error(t.error?.message??"support.submitCsat failed");return t.data}};var me=class{constructor(e){this.http=e}async search(e){if(!e.query||e.query.trim().length===0)return[];let t=new URLSearchParams({query:e.query});e.limit&&t.set("limit",String(e.limit));let r=await this.http.get(`/kb/search?${t.toString()}`);if(!r.success||!Array.isArray(r.data))throw new Error(r.error?.message??"kb.search failed");return r.data}};var tr=/^[A-Za-z0-9_.-]{1,64}$/;function rr(s){if(s!==void 0){if(typeof s!="string"||!tr.test(s))throw new Error(`[sendora] init: storagePrefix must be 1-64 chars of A-Z a-z 0-9 _ . - (got ${JSON.stringify(s)}). Changing it signs the browser out, so it is validated rather than ignored.`);return s}}var sr=/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;function nr(s){let e=s.expectedProjectId;if(e!==void 0){if(typeof e!="string"||!sr.test(e))throw new Error(`[sendora] init: expectedProjectId must be a UUID (got ${JSON.stringify(e)}).`);if(s.projectId!==void 0&&s.projectId!==e)throw new Error(`[sendora] init: expectedProjectId (${e}) must equal projectId (${s.projectId}) when both are set \u2014 they name the same project.`)}}var we=class we{constructor(e){this.autoTrackCleanup=null;this.http=new re(e),this.storage=new se(rr(e.storagePrefix),e.tokenStore==="memory"),this.consent=new H(e.defaultConsent===!0,this.http),this.analytics=new L(e,this.http,this.storage,this.consent),this.flags=new U(e,this.http,this.storage),this.surveys=new x(e,this.http,this.storage),this.messages=new N(e,this.http,this.storage),this.chatbot=new O(e,this.http,this.storage),this.auth=new V(e,this.http,this.storage,this.analytics,this.flags,this.chatbot,{onIdentityWithheld:()=>{this.analytics.withholdIdentity(),this.flags.setContext({})}}),this.webPush=new $(this.http),this.audiences=new q(this.http),this.links=new B(this.http),this.attribution=new fe(this.http),this.support=new ge(this.http),this.kb=new me(this.http),e.autoTrack!==!1&&(this.autoTrackCleanup=ot(this.analytics,e))}static init(e){return Oe(e.apiKey),nr(e),new we(e)}static sanitizeHtml(e){return ne(e)}static safeUrl(e){return S(e)}track(e,t){this.analytics.track(e,t)}page(e){this.analytics.page(e)}identify(e,t,r){this.analytics.identify(e,t,r),this.flags.setContext({userId:e})}reset(e){this.analytics.reset(),this.flags.reset(),this.chatbot.newSession()}onIdentityWithheld(e){return this.auth.onIdentityWithheld(e)}async flush(){await this.analytics.flush()}destroy(){this.autoTrackCleanup&&(this.autoTrackCleanup(),this.autoTrackCleanup=null),this.analytics.destroy(),this.flags.destroy(),this.messages.destroy()}};we.version=R;var ye=we,ir=ye;0&&(module.exports={AMBIGUOUS_HELD_GUEST,AUTH_HELD_SLOT_KEYS,AUTH_STATES,AUTH_WITHHELD_CODES,AlreadyIdentifiedError,Analytics,Audiences,Auth,AuthError,Chatbot,Consent,CredentialInUseError,DEAD_CODES,EmailAlreadyTakenError,FeatureFlags,HELD_GUEST_SLOTS,HeldGuestLimitError,HeldGuestProjectMismatch,InAppMessaging,LinkError,Links,REFRESH_END_REASONS,REJECTED_IN_WITHHELD,RELEASE_HELD_ON_END_REASONS,SendoraCloud,Surveys,ValidationError,WebPush,extractShortcodeFromUrl,projectVerdict,safeUrl,sanitizeHtml});
1
+ "use strict";var Se=Object.defineProperty;var dt=Object.getOwnPropertyDescriptor;var ct=Object.getOwnPropertyNames;var ht=Object.prototype.hasOwnProperty;var pt=(s,e)=>{for(var t in e)Se(s,t,{get:e[t],enumerable:!0})},ft=(s,e,t,r)=>{if(e&&typeof e=="object"||typeof e=="function")for(let n of ct(e))!ht.call(s,n)&&n!==t&&Se(s,n,{get:()=>e[n],enumerable:!(r=dt(e,n))||r.enumerable});return s};var gt=s=>ft(Se({},"__esModule",{value:!0}),s);var or={};pt(or,{AMBIGUOUS_HELD_GUEST:()=>he,AUTH_HELD_SLOT_KEYS:()=>rt,AUTH_STATES:()=>Ve,AUTH_WITHHELD_CODES:()=>G,AlreadyIdentifiedError:()=>K,Analytics:()=>L,Audiences:()=>q,Auth:()=>V,AuthError:()=>u,Chatbot:()=>O,Consent:()=>H,CredentialInUseError:()=>C,DEAD_CODES:()=>ue,EmailAlreadyTakenError:()=>b,FeatureFlags:()=>U,HELD_GUEST_SLOTS:()=>R,HeldGuestLimitError:()=>W,HeldGuestProjectMismatch:()=>_,InAppMessaging:()=>N,LinkError:()=>f,Links:()=>B,REFRESH_END_REASONS:()=>de,REJECTED_IN_WITHHELD:()=>$e,RELEASE_HELD_ON_END_REASONS:()=>ce,SendoraCloud:()=>ye,Surveys:()=>x,ValidationError:()=>m,WebPush:()=>$,default:()=>ir,extractShortcodeFromUrl:()=>at,projectVerdict:()=>pe,safeUrl:()=>E,sanitizeHtml:()=>ie});module.exports=gt(or);var Pe=/^[a-zA-Z][a-zA-Z0-9._:-]{0,127}$/;var mt=new Set(["__proto__","constructor","prototype"]),m=class extends Error{constructor(e){super(`[SendoraCloud] ${e}`),this.name="SendoraValidationError"}};function Le(s){if(typeof s!="string"||!Pe.test(s))throw new m(`Invalid event name: must match ${Pe}, got "${String(s)}".`)}function Ue(s){if(s==null)return;if(typeof s!="object"||Array.isArray(s))throw new m("Properties must be a plain object, not an array or primitive.");let e=xe(s);if(e>5)throw new m(`Properties nested too deeply (${e} levels, max 5).`);Ne(s);let t;try{t=JSON.stringify(s).length}catch{throw new m("Properties contain a circular reference or unserializable value.")}if(t>32768)throw new m(`Properties too large (${t} bytes, max 32768).`)}function xe(s,e=0){if(e>6||s==null||typeof s!="object")return e;let t=e;for(let r of Object.keys(s)){let n=xe(s[r],e+1);n>t&&(t=n)}return t}function Ne(s){if(!(s==null||typeof s!="object"))for(let e of Object.keys(s)){if(mt.has(e))throw new m(`Forbidden property key "${e}" (prototype pollution guard).`);Ne(s[e])}}var yt=/^pk_[A-Za-z0-9_-]{16,}$/;function Oe(s){if(!s||typeof s!="string")throw new m("apiKey is required.");if(s.startsWith("sk_")||s.startsWith("sendora_secret_"))throw new m("Secret keys must NEVER be used in browser SDK. Use a publishable key (pk_...).");if(!yt.test(s))throw new m("Invalid publishable key format. Expected pk_... (17+ chars).")}function He(s){let e=s.replace(/\/$/,"");if(!(e.startsWith("http://localhost")||e.startsWith("http://127.0.0.1"))&&!e.startsWith("https://"))throw new m("apiUrl must be https:// (only http://localhost is allowed for dev).")}var Me={name:"@sendoracloud/sdk-web",version:"3.24.2",description:"Sendora Cloud Web SDK \u2014 analytics, feature flags, surveys, in-app messaging, chatbot, auth, deep links (Branch / Firebase parity). Zero dependencies, TypeScript, SSR-safe.",type:"module",main:"./dist/index.cjs",module:"./dist/index.js",types:"./dist/index.d.ts",exports:{".":{types:"./dist/index.d.ts",import:"./dist/index.js",require:"./dist/index.cjs"}},files:["dist","README.md","LICENSE"],keywords:["sendora","analytics","feature-flags","surveys","in-app-messaging","chatbot","tracking","customer-engagement"],homepage:"https://sendoracloud.com/sdks",bugs:{url:"https://github.com/sendoracloud/sdk-web/issues"},author:"Sendora Cloud <hello@sendoracloud.com>",license:"Apache-2.0",publishConfig:{access:"public"},sideEffects:!1,scripts:{build:"tsup src/index.ts --format cjs,esm --dts --clean --minify",typecheck:"tsc --noEmit && tsc --noEmit -p tsconfig.test.json",test:"vitest run",prepublishOnly:"npm run build"},devDependencies:{typescript:"^5.4.0",tsup:"^8.0.0"}};var T=Me.version;var kt="https://api.sendoracloud.com",vt=1e4,At="@sendoracloud/sdk-web",se=class{constructor(e){let t=(e.apiUrl??kt).replace(/\/$/,"");He(t),this.apiKey=e.apiKey,this.baseUrl=t,this.debug=!!e.debug}get(e,t){return this.request("GET",e,void 0,t)}post(e,t,r){return this.request("POST",e,t,r)}patch(e,t,r){return this.request("PATCH",e,t,r)}delete(e,t){return this.request("DELETE",e,void 0,t)}async request(e,t,r,n){let i=`${this.baseUrl}/api/v1${t}`,o=typeof AbortController<"u"?new AbortController:null,a=o?setTimeout(()=>o.abort(),vt):null;try{let l=await fetch(i,{method:e,headers:{"Content-Type":"application/json","X-API-Key":this.apiKey,"X-Sendora-SDK-Name":At,"X-Sendora-SDK-Version":T,...n??{}},body:r?JSON.stringify(r):void 0,signal:o?o.signal:void 0});a&&clearTimeout(a);let d;try{d=await l.json()}catch{d={success:!1,error:{code:"PARSE_ERROR",message:`HTTP ${l.status}`}}}if(this.debug&&console.debug(`[SendoraCloud] ${e} ${t} \u2192 ${l.status}`),!l.ok){if(t.startsWith("/auth-service/")&&!this.debug)console.warn(`[SendoraCloud] ${e} ${t} \u2192 HTTP ${l.status}`);else{let g=d?.error?.code??"HTTP_ERROR",k=d?.error?.message??`HTTP ${l.status}`,v=d?.error?.details?.fieldErrors,y=v?` (${Object.entries(v).map(([w,z])=>`${w}: ${(z??[]).join(", ")}`).join("; ")})`:"";console.warn(`[SendoraCloud] ${e} ${t} \u2192 HTTP ${l.status} \u2014 ${g}: ${k}${y}`)}d&&d.error&&(d.error={...d.error,status:l.status})}return d}catch(l){a&&clearTimeout(a);let d=l instanceof Error&&l.name==="AbortError"?"timeout":"error";return console.warn(`[SendoraCloud] ${e} ${t} network ${d}`),{success:!1,error:{code:"NETWORK_ERROR",message:d}}}}};var St="sendora_",ne=class{constructor(e,t=!1){this.memoryStore=new Map;this.useLocalStorage=t?!1:this.checkLocalStorage(),this.prefix=e??St}get(e){let t=this.prefix+e;if(this.useLocalStorage)try{return localStorage.getItem(t)}catch{return this.memoryStore.get(t)??null}return this.memoryStore.get(t)??null}set(e,t){let r=this.prefix+e;if(this.useLocalStorage)try{localStorage.setItem(r,t);return}catch{}this.memoryStore.set(r,t)}remove(e){let t=this.prefix+e;if(this.useLocalStorage)try{localStorage.removeItem(t)}catch{}this.memoryStore.delete(t)}isPersistent(){return this.useLocalStorage}relativeKey(e){return e.startsWith(this.prefix)?e.slice(this.prefix.length):null}clearPrefix(e){let t=this.prefix+e;if(this.useLocalStorage)try{for(let r=localStorage.length-1;r>=0;r--){let n=localStorage.key(r);n&&n.startsWith(t)&&localStorage.removeItem(n)}}catch{}for(let r of Array.from(this.memoryStore.keys()))r.startsWith(t)&&this.memoryStore.delete(r)}checkLocalStorage(){try{if(typeof localStorage>"u")return!1;let e="__sendora_test__";return localStorage.setItem(e,"1"),localStorage.removeItem(e),!0}catch{return!1}}};function P(s=""){let e=new Uint8Array(16),t=typeof globalThis<"u"&&"crypto"in globalThis?globalThis.crypto:void 0;if(!t||typeof t.getRandomValues!="function")throw new Error("[SendoraCloud] crypto.getRandomValues unavailable \u2014 refusing to mint IDs without a CSPRNG");t.getRandomValues(e);let r="";for(let n of e)r+=n.toString(16).padStart(2,"0");return s+r}var Fe=500,Ee=10,Ie=6e4,L=class{constructor(e,t,r,n){this.queue=[];this.timer=null;this.userId=null;this.identityToken=null;this.consecutiveFailures=0;this.nextFlushAfter=0;this.breakerOpenAt=0;this.breakerWarned=!1;this.http=t,this.storage=r,this.consent=n,this.projectId=e.projectId,this.flushInterval=e.flushInterval??5e3,this.maxQueueSize=e.maxQueueSize??20,this.persistUserId=!!e.persistUserId,this.stripQueryParams=e.stripQueryParams!==!1,this.appVersion=e.appVersion,this.storage.get("schema_version")===null&&this.storage.set("schema_version","1");let i=this.storage.get("anonymous_id");if(i?this.anonymousId=i:(this.anonymousId=P("anon_"),this.storage.set("anonymous_id",this.anonymousId)),this.persistUserId){let o=this.storage.get("user_id");o&&(this.userId=o)}this.timer=setInterval(()=>this.flush(),this.flushInterval),typeof window<"u"&&window.addEventListener("beforeunload",()=>this.flush()),this.consent.subscribe(o=>{o&&this.flush()})}track(e,t){Le(e),t&&Ue(t),this.queue.length>=Fe&&this.queue.shift(),this.queue.push({eventType:e,properties:t??{},userId:this.userId??void 0,anonymousId:this.anonymousId,timestamp:new Date().toISOString(),identityToken:this.identityToken??void 0}),this.queue.length>=this.maxQueueSize&&this.flush()}page(e){if(typeof window>"u")return;let t=this.stripQueryParams?window.location.origin+window.location.pathname:window.location.href;this.track("page.viewed",{url:t,path:window.location.pathname,title:document.title,referrer:document.referrer||void 0,...e})}identify(e,t,r){if(typeof e!="string"||e.length===0||e.length>256)throw new Error("[SendoraCloud] userId must be a 1-256 char string.");this.userId=e,this.identityToken=r?.identityToken??null,this.persistUserId&&this.storage.set("user_id",e),this.track("user.identified",{...t})}reset(e=!0){this.userId=null,this.identityToken=null,this.storage.remove("user_id"),e&&(this.anonymousId=P("anon_"),this.storage.set("anonymous_id",this.anonymousId)),this.storage.clearPrefix("iam_shown_"),this.storage.clearPrefix("survey_shown_")}withholdIdentity(){this.userId=null,this.identityToken=null}dropQueue(){this.queue=[]}async flush(){if(this.queue.length===0||!this.consent.isGranted()||Date.now()<this.nextFlushAfter)return;this.consecutiveFailures>Ee&&Date.now()-this.breakerOpenAt>=Ie&&(this.consecutiveFailures=0,this.breakerOpenAt=0,this.breakerWarned=!1);let e=this.queue.splice(0,100),t=this.getSessionId(),r=e.map(a=>({projectId:this.projectId,module:"custom",eventType:a.eventType,userId:a.userId,anonymousId:a.anonymousId,identityToken:a.identityToken,timestamp:a.timestamp??new Date().toISOString(),properties:a.properties??{},context:this.getContext(),...t?{sessionId:t}:{},consent:["analytics"]}));if((await this.http.post("/events/batch",{events:r})).success){this.consecutiveFailures=0,this.breakerOpenAt=0,this.breakerWarned=!1;return}if(this.consecutiveFailures++,this.consecutiveFailures>Ee){this.breakerWarned||(this.breakerOpenAt=Date.now(),this.breakerWarned=!0,console.warn(`[SendoraCloud] Analytics circuit breaker open after ${Ee} consecutive failed flushes \u2014 events will be dropped until a flush succeeds or ${Ie}ms elapse.`));return}let i=Math.min(Ie,1e3*2**this.consecutiveFailures);this.nextFlushAfter=Date.now()+i;let o=Math.max(0,Fe-this.queue.length);o>0&&this.queue.unshift(...e.slice(0,o))}destroy(){this.timer&&clearInterval(this.timer),this.timer=null,this.flush()}getSessionId(){try{return typeof sessionStorage>"u"?void 0:sessionStorage.getItem("sendora_session_id")||void 0}catch{return}}getContext(){return typeof window>"u"?{sdk:{name:"@sendoracloud/sdk-web",version:T}}:{page:{url:this.stripQueryParams?window.location.origin+window.location.pathname:window.location.href,path:window.location.pathname,title:document.title},referrer:document.referrer||void 0,locale:typeof navigator<"u"?navigator.language:void 0,device:this.buildDevice(),sdk:{name:"@sendoracloud/sdk-web",version:T}}}buildDevice(){if(typeof navigator>"u")return;let e=navigator.userAgent||"",r=navigator.userAgentData?.mobile??/Mobi|Android|iPhone|iPod/i.test(e);return{type:/iPad|Tablet|(?:Android(?!.*Mobile))/i.test(e)?"tablet":r?"mobile":"desktop",os:"Web",osVersion:"",model:"",appVersion:this.resolveAppVersion(),browser:Et(e)}}resolveAppVersion(){if(this.appVersion)return this.appVersion;if(typeof document<"u"){let r=document.querySelector('meta[name="sendora:app-version"]')?.getAttribute("content");if(r)return r}let e=globalThis.__SENDORA_APP_VERSION__;return typeof e=="string"?e:""}};function Et(s){let e=[["Edge",/Edg\/(\d+)/],["Opera",/OPR\/(\d+)/],["Firefox",/Firefox\/(\d+)/],["Samsung Internet",/SamsungBrowser\/(\d+)/],["Chrome",/Chrome\/(\d+)/],["Safari",/Version\/(\d+)[^ ]* Safari/]];for(let[t,r]of e){let n=r.exec(s);if(n)return`${t} ${n[1]}`}return"Unknown"}var U=class{constructor(e,t,r){this.cache=new Map;this.refreshInterval=null;this.http=t,this.storage=r;let n=this.storage.get("flags");if(n)try{let i=JSON.parse(n);if(Array.isArray(i))for(let o of i)Te(o)&&this.cache.set(o.key,o)}catch{}}setContext(e){this.userId=e.userId,this.entityId=e.entityId,this.environment=e.environment}async getFlag(e){if(typeof e!="string"||e.length===0||e.length>128)return null;let t=this.cache.get(e);if(t)return t.value;let r=await this.http.post("/feature-flags/evaluate",{key:e,userId:this.userId,entityId:this.entityId,environment:this.environment});return r.success&&r.data&&Te(r.data)?(this.cache.set(e,r.data),this.persistCache(),r.data.value):null}async isEnabled(e,t=!1){let r=await this.getFlag(e);return typeof r=="boolean"?r:t}async refreshAll(){let e=await this.http.post("/feature-flags/evaluate-all",{userId:this.userId,entityId:this.entityId,environment:this.environment});if(e.success&&Array.isArray(e.data)){this.cache.clear();for(let t of e.data)Te(t)&&this.cache.set(t.key,t);this.persistCache()}}startAutoRefresh(e=6e4){this.stopAutoRefresh(),this.refreshAll(),this.refreshInterval=setInterval(()=>this.refreshAll(),e)}stopAutoRefresh(){this.refreshInterval&&clearInterval(this.refreshInterval),this.refreshInterval=null}getAllFlags(){let e={};for(let[t,r]of this.cache)e[t]=r.value;return e}reset(){this.cache.clear(),this.storage.remove("flags"),this.userId=void 0,this.entityId=void 0,this.environment=void 0}destroy(){this.stopAutoRefresh()}persistCache(){this.storage.set("flags",JSON.stringify(Array.from(this.cache.values())))}};function Te(s){if(s==null||typeof s!="object")return!1;let e=s;return Object.prototype.hasOwnProperty.call(e,"__proto__")||Object.prototype.hasOwnProperty.call(e,"constructor")?!1:typeof e.key=="string"&&"value"in e}var It=32*1024,x=class{constructor(e,t,r){this.activeSurvey=null;this.http=t,this.storage=r}onDisplay(e){this.onSurveyDisplay=e}async showSurvey(e){if(typeof e!="string"||!/^[A-Za-z0-9_-]{6,64}$/.test(e))return null;let t=`survey_shown_${e}`;if(this.storage.get(t))return null;let r=await this.http.get(`/surveys/${encodeURIComponent(e)}/config`);return!r.success||!r.data||!Tt(r.data)?null:(this.activeSurvey=r.data,this.storage.set(t,"1"),this.onSurveyDisplay&&this.onSurveyDisplay(r.data),r.data)}async submitResponse(e,t,r=!0){let n=0;try{n=JSON.stringify(t).length}catch{return!1}if(n>It)return!1;let i=await this.http.post("/surveys/responses",{surveyId:e,answers:t,completed:r});return i.success&&(this.activeSurvey=null),i.success}dismiss(){this.activeSurvey=null}getActiveSurvey(){return this.activeSurvey}};function Tt(s){if(s==null||typeof s!="object")return!1;let e=s;return typeof e.id!="string"||typeof e.name!="string"||!Array.isArray(e.questions)?!1:e.questions.every(Rt)}function Rt(s){if(s==null||typeof s!="object")return!1;let e=s;return typeof e.id=="string"&&typeof e.text=="string"}function E(s){if(!(!s||typeof s!="string"))try{let e=typeof window<"u"?window.location.href:"https://local/",t=new URL(s,e);return t.protocol==="http:"||t.protocol==="https:"?t.href:void 0}catch{return}}var _t=new Set(["b","i","u","em","strong","a","p","br","span","ul","ol","li","h1","h2","h3","h4"]),bt={a:new Set(["href","target","rel"])};function ie(s){if(typeof DOMParser>"u")return"";let t=new DOMParser().parseFromString(`<div>${s}</div>`,"text/html").body.firstElementChild;return t?(je(t),t.innerHTML):""}function je(s){let e=Array.from(s.children);for(let t of e){let r=t.tagName.toLowerCase();if(!_t.has(r)){let i=document.createTextNode(t.textContent??"");t.replaceWith(i);continue}let n=bt[r]??new Set;for(let i of Array.from(t.attributes)){if(!n.has(i.name.toLowerCase())){t.removeAttribute(i.name);continue}if(i.name.toLowerCase()==="href"){let o=E(i.value);o?t.setAttribute("href",o):t.removeAttribute(i.name)}}r==="a"&&(t.setAttribute("rel","noopener noreferrer"),t.setAttribute("target","_blank")),je(t)}}var N=class{constructor(e,t,r){this.messages=[];this.pollInterval=null;this.http=t,this.storage=r}onDisplay(e){this.onMessageDisplay=e}async checkMessages(){let e=await this.http.get("/in-app-messages/active");if(!e.success||!Array.isArray(e.data))return null;this.messages=e.data.map(Ct);for(let t of this.messages){let r=`iam_shown_${t.id}`;if(!this.storage.get(r))return this.storage.set(r,"1"),this.onMessageDisplay&&this.onMessageDisplay(t),t}return null}async recordAction(e,t){await this.http.post("/in-app-messages/impressions",{messageId:e,action:t})}startPolling(e=3e5){this.stopPolling(),this.checkMessages(),this.pollInterval=setInterval(()=>this.checkMessages(),e)}stopPolling(){this.pollInterval&&clearInterval(this.pollInterval),this.pollInterval=null}getMessages(){return this.messages}destroy(){this.stopPolling()}};function Ct(s){return{...s,content:{...s.content,ctaUrl:E(s.content.ctaUrl),imageUrl:E(s.content.imageUrl)}}}var Dt=4e3,O=class{constructor(e,t,r){this.chatbotId=null;this.messages=[];this.http=t,this.storage=r;let n=this.storage.get("chat_session_id");this.sessionId=n??P("chat_"),n||this.storage.set("chat_session_id",this.sessionId)}init(e){if(typeof e!="string"||!/^[A-Za-z0-9_-]{6,64}$/.test(e))throw new Error("[SendoraCloud] Invalid chatbotId.");this.chatbotId=e}onNewMessage(e){this.onMessage=e}async sendMessage(e,t){if(!this.chatbotId||typeof e!="string"||e.length===0||e.length>Dt)return null;let r={role:"user",content:e,timestamp:new Date().toISOString()};this.messages.push(r);let n=await this.http.post("/chatbot/message",{chatbotId:this.chatbotId,sessionId:this.sessionId,message:e,userId:t});if(n.success&&n.data&&typeof n.data.reply=="string"){let i={role:"assistant",content:n.data.reply,timestamp:new Date().toISOString()};return this.messages.push(i),this.onMessage&&this.onMessage(i),i}return null}getMessages(){return[...this.messages]}newSession(){this.messages=[],this.sessionId=P("chat_"),this.storage.set("chat_session_id",this.sessionId)}getSessionId(){return this.sessionId}};var H=class{constructor(e,t){this.listeners=new Set;this.granted=e,this.http=t}isGranted(){return this.granted}grant(){this.granted||(this.granted=!0,this.emit())}revoke(){this.granted&&(this.granted=!1,this.emit())}subscribe(e){return this.listeners.add(e),()=>this.listeners.delete(e)}async record(e){if(!this.http)throw new Error("consent.record requires SDK init (HttpClient unavailable)");let t=await this.http.post("/consent/record",e);if(!t.success||!t.data)throw new Error(t.error?.message??"consent.record failed");return t.data}async requestDeletion(e){if(!this.http)throw new Error("consent.requestDeletion requires SDK init (HttpClient unavailable)");let t=await this.http.post("/consent/deletion-request",e);if(!t.success||!t.data)throw new Error(t.error?.message??"consent.requestDeletion failed");return t.data}emit(){for(let e of this.listeners)try{e(this.granted)}catch{}}};var M="auth_access_token",F="auth_access_expires",oe="auth_refresh_token",ae="auth_user",Y="auth_session",j=["auth_held_0","auth_held_1","auth_held_2","auth_held_3","auth_held_4"],le="auth_mint_key",Ge="schema_version";var We=[M,F,oe,ae,Y],Pt=[...We,...j],Cr=[...Pt,le];function Lt(s){if(s===null)return{user:null,unreadable:!1};try{let e=JSON.parse(s);return!e||typeof e!="object"||typeof e.id!="string"||e.id.length===0?{user:null,unreadable:!0}:{user:e,unreadable:!1}}catch{return{user:null,unreadable:!0}}}function Ut(s){if(s===null)return{record:null,unreadable:!1};try{let e=JSON.parse(s);if(!e||typeof e!="object"||e.v!==1)return{record:null,unreadable:!0};if(!e.user||typeof e.user!="object"||typeof e.user.id!="string"||e.user.id.length===0)return{record:null,unreadable:!0};if(typeof e.refreshToken!="string"||e.refreshToken.length===0)return{record:null,unreadable:!0};let t=typeof e.accessToken=="string"&&e.accessToken.length>0?e.accessToken:null,r=typeof e.accessExpiresAt=="number"&&Number.isFinite(e.accessExpiresAt)?e.accessExpiresAt:0,n=Array.isArray(e.heldReportPending)?e.heldReportPending.filter(i=>typeof i=="string"):void 0;return{record:{v:1,user:e.user,accessToken:t,accessExpiresAt:r,refreshToken:e.refreshToken,...n&&n.length>0?{heldReportPending:n}:{}},unreadable:!1}}catch{return{record:null,unreadable:!0}}}function Ke(s){if(s===null)return{slot:null,unreadable:!1};try{let e=JSON.parse(s);return!e||typeof e!="object"||e.v!==1||typeof e.userId!="string"||e.userId.length===0||typeof e.refreshToken!="string"||e.refreshToken.length===0?{slot:null,unreadable:!0}:{slot:{v:1,userId:e.userId,sid:typeof e.sid=="string"?e.sid:"",refreshToken:e.refreshToken,tokenAtHold:typeof e.tokenAtHold=="string"?e.tokenAtHold:e.refreshToken,heldAt:typeof e.heldAt=="number"&&Number.isFinite(e.heldAt)?e.heldAt:0,project:typeof e.project=="string"?e.project:null,autoRestore:e.autoRestore!==!1},unreadable:!1}}catch{return{slot:null,unreadable:!0}}}var J=class{constructor(e){this.storage=e}readDisk(){let{record:e,unreadable:t}=Ut(this.storage.get(Y)),{user:r,unreadable:n}=Lt(this.storage.get(ae)),i=this.storage.get(F),o=i?Number(i):0;return{record:e,recordUnreadable:t,legacy:{user:r,userUnreadable:n,accessToken:this.storage.get(M),accessExpiresAt:Number.isFinite(o)?o:0,refreshToken:this.storage.get(oe)}}}currentRefresh(){return this.readDisk().legacy.refreshToken}static recordTrusted(e){return!!e.record&&!!e.legacy.refreshToken&&e.record.refreshToken===e.legacy.refreshToken}writeSession(e){this.storage.set(ae,JSON.stringify(e.user)),e.accessToken?(this.storage.set(M,e.accessToken),this.storage.set(F,String(e.accessExpiresAt))):(this.storage.remove(M),this.storage.remove(F)),this.storage.set(oe,e.refreshToken),this.storage.set(Y,JSON.stringify(e)),this.storage.get(Ge)!=="2"&&this.storage.set(Ge,"2")}clearRecord(){this.storage.remove(Y)}writeLimboTokens(e){this.storage.set(M,e.accessToken),this.storage.set(F,String(e.accessExpiresAt)),this.storage.set(oe,e.refreshToken)}clearSession(){for(let e of We)this.storage.remove(e)}clearStaleBlob(){this.storage.remove(ae),this.storage.remove(M),this.storage.remove(F),this.storage.remove(Y)}readSlots(){let e=[],t=[];return j.forEach((r,n)=>{let{slot:i,unreadable:o}=Ke(this.storage.get(r));e.push(i),o&&t.push(n)}),{slots:e,unreadable:t}}readSlot(e){return Ke(this.storage.get(j[e])).slot}writeSlot(e,t){let r=j[e];t===null?this.storage.remove(r):this.storage.set(r,JSON.stringify(t))}freeSlot(){let{slots:e,unreadable:t}=this.readSlots();for(let r=0;r<e.length;r++)if(e[r]===null&&!t.includes(r))return r;return null}readMintKey(){return this.storage.get(le)}writeMintKey(e){this.storage.set(le,e)}clearMintKey(){this.storage.remove(le)}};var Ve=["unknown","signed_out","anonymous","identified","withheld"],R=5,ue=["INVALID_REFRESH_TOKEN"],de=["expired","revoked","evicted","deleted","reuse","unknown"],ce=["deleted","revoked","expired"],he="AMBIGUOUS_HELD_GUEST",$e=["MINT","SIGN_IN","LINK","CLAIM","RESTORE","DISCARD","DELETE","SESSION_VERB"],G={SESSION_WITHHELD:"SESSION_WITHHELD",PROJECT_MISMATCH:"PROJECT_MISMATCH"};var qe="project";function pe(s,e){if(s===void 0)return"match";let t=A(e);if(t===null||!Object.prototype.hasOwnProperty.call(t,qe))return"unknown";let r=t[qe];return r===null?"mismatch":typeof r=="string"&&r===s?"match":"mismatch"}function A(s){if(typeof s!="string"||s.length===0)return null;let e=s.split(".");if(e.length!==3)return null;let t=Nt(e[1]);if(t===null)return null;let r=Ot(t);if(r===null)return null;let n;try{n=JSON.parse(r)}catch{return null}return n===null||typeof n!="object"||Array.isArray(n)?null:n}var xt=(()=>{let s=new Int16Array(128).fill(-1),e="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";for(let t=0;t<e.length;t++)s[e.charCodeAt(t)]=t;return s[45]=62,s[95]=63,s[43]=62,s[47]=63,s})();function Nt(s){let e=s.length;for(;e>0&&s.charCodeAt(e-1)===61;)e--;if(e%4===1)return null;let t=new Uint8Array(Math.floor(e*3/4)),r=0,n=0,i=0;for(let o=0;o<e;o++){let a=s.charCodeAt(o),l=a<128?xt[a]:-1;if(l<0)return null;r=r<<6|l,n+=6,n>=8&&(n-=8,t[i++]=r>>n&255)}return i===t.length?t:t.subarray(0,i)}function Ot(s){let e="",t=0,r=s.length;for(;t<r;){let n=s[t],i,o;if(n<128)i=n,o=0;else if(n>=194&&n<=223)i=n&31,o=1;else if(n>=224&&n<=239)i=n&15,o=2;else if(n>=240&&n<=244)i=n&7,o=3;else return null;if(t+o>=r)return null;for(let a=1;a<=o;a++){let l=s[t+a];if((l&192)!==128)return null;i=i<<6|l&63}if(o===2&&i<2048||o===3&&(i<65536||i>1114111)||i>=55296&&i<=57343)return null;if(i>65535){let a=i-65536;e+=String.fromCharCode(55296+(a>>10),56320+(a&1023))}else e+=String.fromCharCode(i);t+=o+1}return e}var Be=3e4,Ht=5*6e4,Mt=/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;function Re(s){if(!s||typeof s!="object")return!1;let e=s,t=e.user,r=e.tokens;return!(!t||typeof t.id!="string"||t.id.length===0||!r||typeof r.accessToken!="string"||r.accessToken.length===0||typeof r.refreshToken!="string"||r.refreshToken.length===0||typeof r.expiresIn!="number"||r.expiresIn<=0||t.isAnonymous!==void 0&&typeof t.isAnonymous!="boolean"||t.email!==void 0&&t.email!==null&&typeof t.email!="string"||t.emailVerified!==void 0&&typeof t.emailVerified!="boolean"||t.name!==void 0&&t.name!==null&&typeof t.name!="string"||t.signupMethod!==void 0&&t.signupMethod!==null&&typeof t.signupMethod!="string"||t.lastLoginMethod!==void 0&&t.lastLoginMethod!==null&&typeof t.lastLoginMethod!="string"||t.project!==void 0&&t.project!==null&&typeof t.project!="string"||e.retiredAnonUserId!==void 0&&typeof e.retiredAnonUserId!="string")}var b=class extends Error{constructor(e="An account with this email already exists"){super(e),this.name="EmailAlreadyTakenError"}},K=class extends Error{constructor(e="Already signed in with an identity; use link*() to add a credential, or sign out first"){super(e),this.name="AlreadyIdentifiedError"}},C=class extends Error{constructor(t="This credential is already linked to a different account",r){super(t);this.code="CREDENTIAL_IN_USE";this.kind="credential_in_use";this.retryable=!1;this.name="CredentialInUseError",this.provider=r?.provider,this.collision=r?.collision,this.status=r?.status}};function Ft(s){let e=s?.error?.details;if(!e||typeof e!="object")return{};let t=e;return{provider:typeof t.provider=="string"?t.provider:void 0,collision:t.collision==="identity"||t.collision==="email"?t.collision:void 0}}function ze(s){let e=s?.error?.details;if(!e||typeof e!="object")return;let t=e.endReason;return typeof t=="string"&&de.includes(t)?t:void 0}var jt=new Set(["network","server","rate_limited","account_locked"]);function Gt(s,e){switch(s){case"NETWORK_ERROR":case"NETWORK_TIMEOUT":return"network";case"PARSE_ERROR":case"RESTORE_FAILED":return"server";case"RATE_LIMITED":case"RATE_LIMIT":case"RATE_LIMIT_EXCEEDED":case"QUOTA_EXCEEDED":return"rate_limited";case"ACCOUNT_LOCKED":return"account_locked";case"CREDENTIAL_IN_USE":return"credential_in_use";case"LAST_CREDENTIAL":return"last_credential";case"RECENT_AUTH_REQUIRED":return"recent_auth_required";case"NOT_ANONYMOUS":case"FORBIDDEN_NON_ANONYMOUS":return"already_identified";case"PASSKEY_USER_CANCELLED":case"GAME_CENTER_CANCELLED":case"PLAY_GAMES_CANCELLED":case"SSO_CANCELLED":case"SIGN_IN_SUPERSEDED":case"LINK_SUPERSEDED":case"CLAIM_SUPERSEDED":case"HELD_GUEST_CHANGED":return"cancelled";case"GAME_CENTER_UNAVAILABLE":case"PLAY_GAMES_UNAVAILABLE":case"ENTITLEMENT_ERROR":case"tier_required":case"SESSION_WITHHELD":case"PROJECT_MISMATCH":case"HELD_GUEST_LIMIT":case"HELD_GUEST_PROJECT_MISMATCH":case"UNSUPPORTED_LINK_CREDENTIAL":return"config";case"UNAUTHORIZED":case"INVALID_CREDENTIALS":case"INVALID_REFRESH_TOKEN":case"EMAIL_OTP_INVALID":case"MAGIC_LINK_INVALID":case"PASSKEY_RP_MISMATCH":case"NOT_SIGNED_IN":case"AMBIGUOUS_HELD_GUEST":case"HELD_GUEST_NOT_FOUND":case"HELD_GUEST_GONE":case"NOT_IDENTIFIED":case"CREDENTIAL_STALE":case"MFA_REQUIRED":return"invalid_credential";default:break}if(typeof e=="number"){if(e===429)return"rate_limited";if(e>=500)return"server";if(e>=400)return"invalid_credential"}return"unknown"}var u=class extends Error{constructor(e,t,r){super(t),this.name="AuthError",this.code=e,this.kind=r?.kind??Gt(e,r?.status),this.retryable=jt.has(this.kind),this.retryAfterSeconds=r?.retryAfterSeconds,this.status=r?.status}},W=class extends u{constructor(e,t=`Every held-guest slot is occupied (${5}); restore or discard one first`){super("HELD_GUEST_LIMIT",t,{kind:"config"}),this.name="HeldGuestLimitError",this.heldGuests=e}},_=class extends u{constructor(e,t,r){super("HELD_GUEST_PROJECT_MISMATCH",`Held guest ${e} belongs to project ${r??"null"}, not ${t}`,{kind:"config"}),this.name="HeldGuestProjectMismatch",this.userId=e,this.expectedProjectId=t,this.actualProjectId=r}};function Kt(s){if(s instanceof u||s instanceof b||s instanceof K||s instanceof C)return s;let e=s?.name;return e==="AbortError"||e==="TimeoutError"||e==="NetworkTimeoutError"?new u("NETWORK_TIMEOUT",s instanceof Error?s.message:"timeout",{kind:"network"}):new u("UNKNOWN_ERROR",s instanceof Error?s.message:String(s),{kind:"unknown"})}function p(s){let e=s.error?.status,t=s.error?.details?.retryAfterSeconds;return{status:typeof e=="number"?e:void 0,retryAfterSeconds:typeof t=="number"&&Number.isFinite(t)&&t>0?t:void 0}}var V=class{constructor(e,t,r,n,i,o,a={}){this.state="unknown";this.record=null;this.user=null;this.accessToken=null;this.accessExpiresAt=0;this.withheld=null;this.clockSkewConfirmed=!1;this.inflight=Promise.resolve();this.refreshInflight=null;this.attemptInFlight=!1;this.refreshFailureCount=0;this.refreshCooldownUntil=0;this.visibilityResetUnsub=null;this.proactiveRefreshTimer=null;this.proactiveRefreshCleanup=null;this.storageEventUnsub=null;this.rehydrateScheduled=!1;this.takeoverListeners=new Set;this.lastTakeover=null;this.deletionCancelledListeners=new Set;this.lastDeletionCancelled=null;this.lastAnonRetirement=null;this.authStateListeners=new Set;this.identityWithheldListeners=new Set;this.hydrated=!1;this.http=t,this.storage=r,this.store=new J(r),this.analytics=n,this.flags=i,this.chatbot=o,this.hooks=a,this.expectedProjectId=e.expectedProjectId,this.slotProjectAnchor=e.expectedProjectId??e.projectId,this.autoRestoreHeldGuest=e.autoRestoreHeldGuest!==!1,this.hydrateFromDisk("boot"),this.hydrated=!0,this.startStorageEventRehydrate()}status(){return this.state}authStateReady(){return Promise.resolve(this.state)}getCurrentUser(){return this.user}getUserSync(){return this.user}isReady(){return this.hydrated}onDeviceTakeover(e){return this.takeoverListeners.add(e),()=>{this.takeoverListeners.delete(e)}}getLastDeviceTakeover(){return this.lastTakeover}onAuthStateChanged(e){if(this.authStateListeners.add(e),this.hydrated){let t=this.user,r={event:"initial",status:this.state,user:t,...this.withheld?{withheld:this.withheld.info}:{}};try{e(r)}catch{}if(t)try{e({event:"signed_in",user:t})}catch{}}return()=>{this.authStateListeners.delete(e)}}onIdentityWithheld(e){return this.identityWithheldListeners.add(e),()=>{this.identityWithheldListeners.delete(e)}}emitAuthState(e){for(let t of this.authStateListeners)try{t(e)}catch{}}fireDeviceTakeover(e,t){if(!e||!Mt.test(e))return;let r={retiredAnonUserId:e,identifiedUserId:t,at:new Date};this.lastTakeover=r;for(let n of this.takeoverListeners)try{n(r)}catch{}this.emitAuthState({event:"device_takeover",user:this.user,retiredAnonUserId:e})}onDeletionCancelled(e){return this.deletionCancelledListeners.add(e),()=>{this.deletionCancelledListeners.delete(e)}}getLastDeletionCancelled(){return this.lastDeletionCancelled}getLastAnonRetirement(){return this.lastAnonRetirement}fireDeletionCancelled(e){let t={userId:e,at:new Date};this.lastDeletionCancelled=t;for(let r of this.deletionCancelledListeners)try{r(t)}catch{}this.emitAuthState({event:"deletion_cancelled",user:this.user})}recordServerSignals(e){e.anonRetirement&&(this.lastAnonRetirement=e.anonRetirement),e.retiredAnonUserId&&this.fireDeviceTakeover(e.retiredAnonUserId,e.user.id),e.reactivatedFromDeletion&&this.fireDeletionCancelled(e.user.id)}commit(e){switch(e.type){case"install":return this.commitInstall(e);case"clear":return this.commitClear(e);case"user":{if(this.currentSid()!==e.expectSid||!this.record)return!1;let t={...this.record,user:e.user};return this.record=t,this.user=e.user,this.store.writeSession(t),this.analytics.identify(e.user.id),this.flags.setContext({userId:e.user.id}),this.emitAuthState({event:"user_updated",user:e.user,cause:e.cause}),!0}case"release":{let t=this.store.readSlot(e.index);return t?(this.store.writeSlot(e.index,null),this.emitAuthState({event:"guest_released",userId:t.userId,reason:e.reason,...e.endReason?{endReason:e.endReason}:{}}),!0):!1}case"slot_tokens":{let t=this.store.readSlot(e.index);return!t||t.refreshToken!==e.sent?!1:(this.store.writeSlot(e.index,{...t,refreshToken:e.refreshToken,...e.project!==void 0&&t.project===null?{project:e.project}:{}}),!0)}case"withhold":return this.commitWithhold(e);case"unknown":return this.state="unknown",this.record=null,this.user=null,this.withheld=null,this.accessToken=e.accessToken,this.accessExpiresAt=e.accessExpiresAt,this.startProactiveRefreshCron(),this.startVisibilityRefreshReset(),!0;case"held_reported":{if(!this.record?.heldReportPending?.includes(e.userId))return!1;let t=this.record.heldReportPending.filter(n=>n!==e.userId),r={...this.record};return t.length>0?r.heldReportPending=t:delete r.heldReportPending,this.record=r,this.store.writeSession(r),!0}default:return!1}}commitInstall(e){if(e.expectSid!==void 0&&this.currentSid()!==e.expectSid||e.expectRefresh!==void 0&&this.store.currentRefresh()!==e.expectRefresh)return!1;let t=this.record,r=t?.user??null,n=r?.id!==e.record.user.id,i=null,o={...e.record};if(e.hold){let a=this.store.freeSlot();if(a===null)return!1;this.store.writeSlot(a,e.hold),i=this.heldCount();let l=new Set(t?.heldReportPending??[]);l.add(e.hold.userId),o.heldReportPending=[...l]}else t?.heldReportPending&&!o.heldReportPending&&!n&&(o.heldReportPending=t.heldReportPending);switch(r&&n&&(this.analytics.reset(!1),this.flags.reset(),this.chatbot.newSession(),e.revokePrevious&&t&&!r.isAnonymous&&this.revokeFireAndForget(t.refreshToken)),this.state=o.user.isAnonymous===!1?"identified":"anonymous",this.record=o,this.user=o.user,this.accessToken=o.accessToken,this.accessExpiresAt=o.accessExpiresAt,this.withheld=null,n&&(this.clockSkewConfirmed=!1,this.lastTakeover=null,this.lastDeletionCancelled=null,this.lastAnonRetirement=null),(e.reason!=="hydrate"||e.persist!==!1)&&this.store.writeSession(o),this.analytics.identify(o.user.id),this.flags.setContext({userId:o.user.id}),this.startProactiveRefreshCron(),this.startVisibilityRefreshReset(),this.refreshFailureCount=0,this.refreshCooldownUntil=0,e.hold&&i!==null&&this.emitAuthState({event:"guest_held",userId:e.hold.userId,count:i}),e.reason){case"mint":this.emitAuthState({event:"signed_in",user:o.user,cause:"mint"});break;case"sign_in":this.emitAuthState({event:"signed_in",user:o.user,cause:"sign_in"});break;case"upgrade":this.emitAuthState({event:"signed_in",user:o.user,cause:"link"});break;case"link":this.emitAuthState({event:"user_updated",user:o.user,cause:"link"});break;case"restore":this.emitAuthState({event:"signed_in",user:o.user,cause:"restore"});break;case"claim":this.emitAuthState({event:"user_updated",user:o.user,cause:"merge"});break;case"recover":this.emitAuthState({event:"signed_in",user:o.user});break;case"rehydrate":n&&this.emitAuthState({event:"signed_in",user:o.user});break;case"refresh":r&&JSON.stringify(r)!==JSON.stringify(o.user)&&this.emitAuthState({event:"user_updated",user:o.user,cause:"refresh"});break;case"hydrate":break;default:break}return e.release&&this.commit({type:"release",index:e.release.index,reason:e.release.reason}),e.hold&&this.reportHeld(e.hold.userId,e.hold.refreshToken),!0}commitClear(e){let t=this.record?.refreshToken??this.withheld?.refreshToken??this.store.currentRefresh();if(e.expectRefresh!==void 0&&this.store.currentRefresh()!==e.expectRefresh)return!1;let r=this.state!=="signed_out";if(this.state="signed_out",this.record=null,this.user=null,this.accessToken=null,this.accessExpiresAt=0,this.withheld=null,this.clockSkewConfirmed=!1,this.lastTakeover=null,this.lastDeletionCancelled=null,this.lastAnonRetirement=null,this.store.clearSession(),e.stampNoAutoRestore){let{slots:n}=this.store.readSlots();n.forEach((i,o)=>{i&&i.autoRestore&&this.store.writeSlot(o,{...i,autoRestore:!1})})}return e.keepAnalyticsIdentity||this.analytics.reset(e.reason==="user"||e.reason==="account_deleted"),e.dropQueue&&this.analytics.dropQueue(),this.flags.reset(),this.chatbot.newSession(),this.stopProactiveRefreshCron(),this.stopVisibilityRefreshReset(),this.refreshFailureCount=0,this.refreshCooldownUntil=0,e.revoke&&t&&this.revokeFireAndForget(t),r&&this.emitAuthState(e.endReason!==void 0?{event:"signed_out",user:null,reason:e.reason,endReason:e.endReason}:{event:"signed_out",user:null,reason:e.reason}),!0}commitWithhold(e){if(e.from==="refresh"){if(!e.rotation||this.store.currentRefresh()!==e.rotation.sent)return!1;this.record?this.store.writeSession({...this.record,accessToken:e.rotation.accessToken,accessExpiresAt:e.rotation.accessExpiresAt,refreshToken:e.rotation.refreshToken}):this.store.writeLimboTokens(e.rotation)}this.state="withheld",this.record=null,this.user=null,this.accessToken=null,this.accessExpiresAt=0,this.withheld={info:e.info,refreshToken:e.rotation?.refreshToken??e.refreshToken},this.stopProactiveRefreshCron(),this.stopVisibilityRefreshReset();try{this.hooks.onIdentityWithheld?.()}catch{}for(let t of this.identityWithheldListeners)try{t()}catch{}return e.from==="refresh"&&this.emitAuthState({event:"session_withheld",reason:"project_mismatch",expectedProjectId:e.info.expectedProjectId,actualProjectId:e.info.actualProjectId,userId:e.info.userId}),!0}hydrateFromDisk(e){let t=this.store.readDisk(),r=t.legacy.refreshToken,n=J.recordTrusted(t),i=t.record!==null&&!n,o=t.legacy.user,a=n?o&&o.id===t.record.user.id?o:t.record.user:o,l=t.legacy.accessToken??(n?t.record.accessToken:null),d=t.legacy.accessToken?t.legacy.accessExpiresAt:n?t.record.accessExpiresAt:0;if(!r){if((a||i||t.legacy.userUnreadable||t.recordUnreadable)&&this.store.clearStaleBlob(),e==="boot"){this.state="signed_out";return}this.state!=="signed_out"&&this.commit({type:"clear",reason:"user",revoke:!1,dropQueue:!1,stampNoAutoRestore:!1});return}if(!a){if(e==="storage_event"&&this.record&&this.record.refreshToken===r)return;i&&this.store.clearRecord(),this.commit({type:"unknown",accessToken:l,accessExpiresAt:d});return}let h=this.judge(l);if(h==="mismatch"){this.commit({type:"withhold",from:"hydrate",info:this.withheldInfo(a,l),refreshToken:r});return}if(h==="unknown"){this.commit({type:"unknown",accessToken:l,accessExpiresAt:d});return}let g={v:1,user:a,accessToken:l,accessExpiresAt:d,refreshToken:r,...t.record?.heldReportPending?{heldReportPending:t.record.heldReportPending}:{}};if(e==="storage_event"&&this.record&&this.record.refreshToken===r&&this.record.user.id===a.id)return;let k=!n||JSON.stringify(t.record.user)!==JSON.stringify(a)||t.record.accessToken!==l;if(this.commit({type:"install",reason:e==="boot"?"hydrate":"rehydrate",record:g,persist:k}),e==="boot"){let{slots:v}=this.store.readSlots();v.forEach((y,w)=>{y&&y.userId===a.id&&this.store.writeSlot(w,null)});for(let y of g.heldReportPending??[]){let w=this.store.readSlots().slots.find(z=>z?.userId===y);w?this.reportHeld(y,w.refreshToken):this.commit({type:"held_reported",userId:y})}}}startStorageEventRehydrate(){if(typeof window>"u"||typeof window.addEventListener!="function"||!this.storage.isPersistent())return;let e=t=>{let r=t.key===null?null:this.storage.relativeKey(t.key);t.key!==null&&(r===null||!r.startsWith("auth_"))||this.rehydrateScheduled||(this.rehydrateScheduled=!0,setTimeout(()=>{this.rehydrateScheduled=!1,this.hydrateFromDisk("storage_event")},0))};window.addEventListener("storage",e),this.storageEventUnsub=()=>window.removeEventListener("storage",e)}stopStorageEventRehydrate(){this.storageEventUnsub&&(this.storageEventUnsub(),this.storageEventUnsub=null)}currentSid(){let e=this.record?.accessToken;if(!e)return null;let t=A(e)?.sid;return typeof t=="string"?t:null}judge(e){return pe(this.expectedProjectId,e)}projectClaim(e){let t=A(e)?.project;return typeof t=="string"?t:null}withheldInfo(e,t){return{reason:"project_mismatch",expectedProjectId:this.expectedProjectId??"",actualProjectId:this.projectClaim(t),userId:e.id,isAnonymous:e.isAnonymous!==!1}}heldCount(){return this.store.readSlots().slots.filter(e=>e!==null).length}buildHeld(e){let t=A(e.accessToken)?.sid;return{v:1,userId:e.user.id,sid:typeof t=="string"?t:"",refreshToken:e.refreshToken,tokenAtHold:e.refreshToken,heldAt:Math.max(Date.now(),...this.store.readSlots().slots.map(r=>r?r.heldAt+1:0)),project:this.projectClaim(e.accessToken),autoRestore:!0}}revokeFireAndForget(e){this.http.post("/auth-service/token/revoke",{refreshToken:e}).catch(()=>{})}reportHeld(e,t){this.http.post("/auth-service/guest/held",{refreshToken:t}).then(r=>{r.success&&this.commit({type:"held_reported",userId:e})}).catch(()=>{})}withheldError(){return new u(G.SESSION_WITHHELD,"The stored session belongs to a different project and is withheld; call discardWithheld() or re-init with the matching expectedProjectId",{kind:"config"})}canServeToken(e,t,r){return!e||!t||r>=t-Be?!1:this.clockSkewConfirmed?!0:tt(e,r)}canServeCachedToken(e){return this.canServeToken(this.accessToken,this.accessExpiresAt,e)}trackedDeadlineAlive(e){return!!this.accessToken&&!!this.accessExpiresAt&&e<this.accessExpiresAt-Be}deadlinesDisagree(e){return this.trackedDeadlineAlive(e)&&!this.canServeCachedToken(e)}learnClockSkewFrom(e,t){tt(e,t)||(this.clockSkewConfirmed=!0)}async refreshAndReconcile(e){let t=this.deadlinesDisagree(e),r=await this.refreshAccessToken();return t&&r&&this.learnClockSkewFrom(r,Date.now()),r}async getAccessToken(e){return this.state==="withheld"?null:!e?.forceRefresh&&this.state!=="unknown"&&this.canServeCachedToken(Date.now())?this.accessToken:this.store.currentRefresh()?this.refreshInflight?this.refreshInflight:Date.now()<this.refreshCooldownUntil?null:this.refreshAndReconcile(Date.now()):null}getAccessTokenSync(){return this.accessToken}getRefreshToken(){return this.state==="withheld"?null:this.store.currentRefresh()}async refreshAccessToken(){if(this.refreshInflight)return this.refreshInflight;let e=this.store.currentRefresh();return e?(this.refreshInflight=(async()=>{try{return await this.performRefresh(e)}finally{this.refreshInflight=null}})(),this.refreshInflight):null}async performRefresh(e){try{let t=await this.http.post("/auth-service/token/refresh",{refreshToken:e});if(!t.success)return Qe(t.error?.code)?(this.store.currentRefresh()===e&&this.commit({type:"clear",reason:"session_expired",endReason:ze(t),expectRefresh:e,revoke:!1,dropQueue:!1,stampNoAutoRestore:!1}),this.refreshFailureCount=0,this.refreshCooldownUntil=0,null):(this.armBackoff(),null);let r=X(t.data);if(!r)return this.armBackoff(),null;if(this.store.currentRefresh()!==e)return null;let n=Date.now()+r.expiresIn*1e3,i=this.judge(r.accessToken);if(i==="mismatch"){let a=this.record?.user??Z(t.data);return this.commit({type:"withhold",from:"refresh",info:this.withheldInfo(a??{id:Ze(r.accessToken)??"",email:null,emailVerified:!1,name:null,isAnonymous:!0},r.accessToken),refreshToken:r.refreshToken,rotation:{sent:e,accessToken:r.accessToken,refreshToken:r.refreshToken,accessExpiresAt:n}}),null}let o=Z(t.data);return this.record?this.commit({type:"install",reason:"refresh",record:{...this.record,user:o??this.record.user,accessToken:r.accessToken,accessExpiresAt:n,refreshToken:r.refreshToken},expectRefresh:e}):i==="match"&&o?this.commit({type:"install",reason:"recover",record:{v:1,user:o,accessToken:r.accessToken,accessExpiresAt:n,refreshToken:r.refreshToken},expectRefresh:e}):(this.store.writeLimboTokens({accessToken:r.accessToken,refreshToken:r.refreshToken,accessExpiresAt:n}),this.accessToken=r.accessToken,this.accessExpiresAt=n),this.refreshFailureCount=0,this.refreshCooldownUntil=0,r.accessToken}catch{return this.armBackoff(),null}}async refreshHeld(e,t){let r=t.refreshToken,n=await this.http.post("/auth-service/token/refresh",{refreshToken:r});if(!n.success){if(Qe(n.error?.code)){let l=ze(n);if(l&&ce.includes(l))return this.commit({type:"release",index:e,reason:"dead",endReason:l}),{kind:"dead",endReason:l};throw new u("RESTORE_FAILED",`The held guest's token was refused${l?` (${l})`:" with no end reason"}; the slot is kept \u2014 retry later`,{status:p(n).status,kind:"server"})}throw new u(n.error?.code??"RESTORE_FAILED",n.error?.message??"Could not refresh the held guest",p(n))}let i=X(n.data);if(!i)throw new u("RESTORE_FAILED","Malformed refresh response for the held guest; the slot is kept",{kind:"server"});let o=Z(n.data)?.id??A(i.accessToken)?.sub;if(typeof o=="string"&&o&&o!==t.userId)throw new u("HELD_GUEST_IDENTITY_MISMATCH","The held guest's refresh was answered for a different account; nothing was changed",{kind:"unknown"});if(!this.commit({type:"slot_tokens",index:e,sent:r,refreshToken:i.refreshToken,...t.project===null?{project:this.projectClaim(i.accessToken)}:{}}))throw new u("HELD_GUEST_CHANGED","The held slot changed while its token was in flight",{kind:"cancelled"});return{kind:"ok",tokens:i,user:Z(n.data)}}async settle(){for(;this.state==="unknown";){if(!this.store.currentRefresh()){this.commit({type:"clear",reason:"user",revoke:!1,dropQueue:!1,stampNoAutoRestore:!1});return}if(await this.refreshAccessToken(),this.state!=="unknown")return;let e=Math.min(3e4,Math.max(250,this.refreshCooldownUntil-Date.now()));await new Promise(t=>setTimeout(t,e))}}armBackoff(){this.refreshFailureCount+=1;let e=Math.min(3e4,1e3*Math.pow(2,this.refreshFailureCount-1));this.refreshCooldownUntil=Date.now()+e}resetRefreshState(){this.refreshFailureCount=0,this.refreshCooldownUntil=0}startVisibilityRefreshReset(){if(this.visibilityResetUnsub||typeof document>"u")return;let e=()=>{document.visibilityState==="visible"&&this.resetRefreshState()};document.addEventListener("visibilitychange",e),this.visibilityResetUnsub=()=>document.removeEventListener("visibilitychange",e)}stopVisibilityRefreshReset(){this.visibilityResetUnsub&&(this.visibilityResetUnsub(),this.visibilityResetUnsub=null)}startProactiveRefreshCron(){if(typeof window>"u"||this.proactiveRefreshTimer)return;let e=.8,t=6e4,r=3e4,n=async()=>{if(this.attemptInFlight||this.state==="withheld")return;if(this.state==="unknown"){Date.now()>=this.refreshCooldownUntil&&await this.refreshAccessToken();return}if(!this.accessToken||!this.accessExpiresAt)return;let o=Date.now();if(!this.canServeCachedToken(o)){await this.refreshAndReconcile(o);return}let a=this.accessExpiresAt-o;if(a<=0)return;let d=Math.max(a,5*6e4)*(1-e)+(Math.random()*r*2-r);a<=d&&await this.refreshAccessToken()};this.proactiveRefreshTimer=window.setInterval(()=>{n()},t);let i=()=>{typeof document<"u"&&document.visibilityState==="visible"&&n()};typeof document<"u"&&document.addEventListener("visibilitychange",i),this.proactiveRefreshCleanup=()=>{this.proactiveRefreshTimer&&(window.clearInterval(this.proactiveRefreshTimer),this.proactiveRefreshTimer=null),typeof document<"u"&&document.removeEventListener("visibilitychange",i)}}stopProactiveRefreshCron(){this.proactiveRefreshCleanup&&(this.proactiveRefreshCleanup(),this.proactiveRefreshCleanup=null)}serialize(e){let t=async()=>{try{return await e()}catch(n){throw Kt(n)}},r=this.inflight.then(t,t);return this.inflight=r.catch(()=>{}),r}async bearerHeaders(){if(this.state==="withheld")throw this.withheldError();let e=await this.getAccessToken();if(!e)throw new u("NOT_SIGNED_IN","Not signed in");return{Authorization:`Bearer ${e}`}}signInAnonymously(e){return this.serialize(async()=>{if(this.state==="withheld")throw this.withheldError();if(this.state==="unknown"&&await this.settle(),this.status()==="withheld")throw this.withheldError();let{slots:t}=this.store.readSlots(),r=t.filter(l=>l!==null),n=this.record;if(n&&!e?.forceNew)return n.user;let i=r.length+(n&&n.user.isAnonymous?1:0);if(e?.forceNew){if(i>=5)throw new W(r.length);return this.mintFresh(e,n)}let o=r.map(l=>({slot:l,index:t.indexOf(l)})).filter(({slot:l})=>l.autoRestore&&!this.slotProjectMismatches(l)).sort((l,d)=>d.slot.heldAt-l.slot.heldAt);if(o.length>0&&(this.autoRestoreHeldGuest||i>=5))for(let{slot:l,index:d}of o)try{let h=await this.restoreSlot(d,l,"mint");if(h)return h}catch(h){if(h instanceof _)continue;throw h}let a=this.heldCount();if(a>=5)throw new W(a);return this.mintFresh(e,null)})}ensureSession(){return this.signInAnonymously()}slotProjectMismatches(e){let t=this.slotProjectAnchor;return t!==void 0&&e.project!==null&&e.project!==t}async mintFresh(e,t){let r=this.currentSid(),n=this.store.readMintKey()??Wt();this.store.writeMintKey(n),this.attemptInFlight=!0;try{await this.refreshInflight;let i=await this.http.post("/auth-service/anonymous",{name:e?.name,metadata:e?.metadata,mintKey:n});if(!i.success||!Re(i.data))throw new u(i.error?.code??"AUTH_ERROR",i.error?.message??"Anonymous signup failed",p(i));let o=i.data;this.guardMinted(o),await this.refreshInflight;let a=this.record,l=a&&a.user.isAnonymous&&t?this.buildHeld(a):void 0;if(!this.commit({type:"install",reason:"mint",record:_e(o),expectSid:r,hold:l,revokePrevious:!!a&&!a.user.isAnonymous}))throw this.revokeFireAndForget(o.tokens.refreshToken),new u("SIGN_IN_SUPERSEDED","The session changed while the mint was in flight; nothing was installed",{kind:"cancelled"});return this.store.clearMintKey(),this.recordServerSignals(o),o.user}finally{this.attemptInFlight=!1}}guardMinted(e){if(this.judge(e.tokens.accessToken)!=="match")throw this.revokeFireAndForget(e.tokens.refreshToken),new u(G.PROJECT_MISMATCH,`The server answered for project ${this.projectClaim(e.tokens.accessToken)??"null"}, not expectedProjectId ${this.expectedProjectId??""}; nothing was installed`,{kind:"config"})}async performSwitch(e,t,r){if(this.state==="withheld")throw this.withheldError();if(this.state==="unknown"&&await this.settle(),this.status()==="withheld")throw this.withheldError();let n=this.currentSid();this.attemptInFlight=!0;try{await this.refreshInflight;let i=await e();if(!i.success||!i.data)throw new u(i.error?.code??t,i.error?.message??r,p(i));let o=i.data;if(o.mfaRequired===!0&&typeof o.mfaChallengeToken=="string"){let g=o.user;return{kind:"mfa",challengeToken:o.mfaChallengeToken,userId:g?.id??""}}if(!Re(i.data))throw new u(i.error?.code??t,i.error?.message??r,p(i));let a=i.data;this.guardMinted(a),this.record&&await this.analytics.flush().catch(()=>{}),await this.refreshInflight;let l=this.record,d=l&&l.user.isAnonymous&&l.user.id!==a.user.id?this.buildHeld(l):void 0;if(!this.commit({type:"install",reason:"sign_in",record:_e(a),expectSid:n,hold:d,revokePrevious:!!l&&!l.user.isAnonymous&&l.user.id!==a.user.id}))throw this.revokeFireAndForget(a.tokens.refreshToken),new u("SIGN_IN_SUPERSEDED","The session changed while the sign-in was in flight; nothing was installed",{kind:"cancelled"});return this.recordServerSignals(a),{kind:"done",user:a.user,previous:l?{userId:l.user.id,isAnonymous:l.user.isAnonymous!==!1,held:!!d}:null,reactivated:a.reactivatedFromDeletion===!0}}finally{this.attemptInFlight=!1}}signIn(e,t){return this.serialize(async()=>{let r=await this.performSwitch(()=>this.http.post("/auth-service/login",{email:e,password:t}),"AUTH_ERROR","Login failed");return r.kind==="mfa"?{mfaRequired:!0,mfaChallengeToken:r.challengeToken,userId:r.userId}:r.user})}challengeMfa(e,t){return this.serialize(async()=>{let r=await this.performSwitch(()=>this.http.post("/auth-service/mfa/challenge",{challengeToken:e,code:t}),"MFA_CHALLENGE_FAILED","Invalid MFA code");if(r.kind==="mfa")throw new u("MFA_CHALLENGE_FAILED","MFA challenge returned another challenge");return r.user})}loginSocial(e){return this.serialize(async()=>{let{link:t,onCredentialInUse:r,...n}=e,i=n,o=()=>this.performSwitch(()=>this.http.post("/auth-service/login/social",i),"SOCIAL_LOGIN_FAILED","Social login failed");if(t){if(this.state==="withheld")throw this.withheldError();if(this.state==="unknown"&&await this.settle(),this.state==="anonymous"||this.state==="identified"){let l=await this.performLink("/auth-service/me/link/social",i,"upgrade");if(l.kind==="done")return l.user;if(l.kind==="recent_auth_required")throw new u("RECENT_AUTH_REQUIRED",l.message??"Re-authenticate to link this credential",{status:l.status??403});if(r==="adopt"){let d=await o();if(d.kind==="mfa")throw new u("MFA_REQUIRED","This account requires MFA; use signIn()/challengeMfa()");return d.user}throw new C(l.message,{provider:l.provider,collision:l.collision,status:l.status})}}let a=await o();if(a.kind==="mfa")throw new u("MFA_REQUIRED","This account requires MFA; use signIn()/challengeMfa()");return a.user})}signInWithGoogle(e,t,r){return this.loginSocial({provider:"google",code:e,redirectUri:t,link:r})}signInWithGitHub(e,t){return this.loginSocial({provider:"github",code:e,redirectUri:t})}signInWithApple(e){return this.loginSocial({provider:"apple",...e})}signInWithMicrosoft(e,t){return this.loginSocial({provider:"microsoft",code:e,redirectUri:t})}signInWithLinkedIn(e,t){return this.loginSocial({provider:"linkedin",code:e,redirectUri:t})}signInWithFacebook(e,t){return this.loginSocial({provider:"facebook",code:e,redirectUri:t})}signInWithDiscord(e,t){return this.loginSocial({provider:"discord",code:e,redirectUri:t})}signInWith(e){return this.serialize(async()=>{let{path:t,body:r}=Ye(e),n=await this.performSwitch(()=>this.http.post(t,r),"AUTH_ERROR","Sign-in failed");if(n.kind==="mfa"){let i=n.challengeToken;return{status:"mfa_required",challengeToken:i,verify:o=>this.signInWith({kind:"mfa",challengeToken:i,code:o})}}return{status:"done",user:n.user,previous:n.previous,reactivated:n.reactivated}})}async performLink(e,t,r){if(this.state==="withheld")throw this.withheldError();let n=this.currentSid();this.attemptInFlight=!0;try{await this.refreshInflight;let i=await this.bearerHeaders(),o=await this.http.post(e,t,i);if(!o.success||!o.data?.user){let d=o.error?.code??"LINK_FAILED",h=p(o);if(d==="CREDENTIAL_IN_USE"){let g=Ft(o);return{kind:"credential_in_use",provider:g.provider??"",collision:g.collision??"identity",status:h.status,message:o.error?.message}}if(d==="RECENT_AUTH_REQUIRED")return{kind:"recent_auth_required",status:h.status,message:o.error?.message};throw new u(d,o.error?.message??"Failed to link credential",h)}let a=o.data,l=o.data.user;if(a.upgraded&&Re(a)){if(this.guardMinted(a),await this.refreshInflight,!this.commit({type:"install",reason:r,record:_e(a),expectSid:n}))throw this.revokeFireAndForget(a.tokens.refreshToken),new u("LINK_SUPERSEDED","The session changed while the link was in flight; nothing was installed",{kind:"cancelled"});return{kind:"done",user:a.user,upgraded:!0,alreadyLinked:!1}}return a.alreadyLinked?{kind:"done",user:l,upgraded:!1,alreadyLinked:!0}:(this.commit({type:"user",user:l,cause:"link",expectSid:n}),{kind:"done",user:l,upgraded:!1,alreadyLinked:!1})}finally{this.attemptInFlight=!1}}link(e){return this.serialize(async()=>{if(this.state==="withheld")throw this.withheldError();if(this.state==="unknown"&&await this.settle(),this.status()==="withheld")throw this.withheldError();if(this.state==="signed_out"){let i=await this.signInWithUnserialized(e);if(i.status!=="done")throw new u("MFA_REQUIRED","This account requires MFA; use signInWith() and complete the challenge");return{status:"done",user:i.user,upgraded:!1,alreadyLinked:!1}}let t=Je(e),r=await this.performLink(t.path,t.body,"link");if(r.kind==="done")return{status:"done",user:r.user,upgraded:r.upgraded,alreadyLinked:r.alreadyLinked};if(r.kind==="recent_auth_required")return{status:"recent_auth_required"};let n=Date.now();return{status:"credential_in_use",provider:r.provider,collision:r.collision,switchAccount:()=>Date.now()-n>Ht?Promise.reject(new u("CREDENTIAL_STALE","The refused credential is older than 5 minutes; obtain it again and call signInWith()")):this.signInWith(e),keepCurrent:()=>{}}})}async signInWithUnserialized(e){let{path:t,body:r}=Ye(e),n=await this.performSwitch(()=>this.http.post(t,r),"AUTH_ERROR","Sign-in failed");if(n.kind==="mfa"){let i=n.challengeToken;return{status:"mfa_required",challengeToken:i,verify:o=>this.signInWith({kind:"mfa",challengeToken:i,code:o})}}return{status:"done",user:n.user,previous:n.previous,reactivated:n.reactivated}}signUp(e,t,r){return this.serialize(async()=>{if(this.state==="withheld")throw this.withheldError();if(this.state==="unknown"&&await this.settle(),this.status()==="withheld")throw this.withheldError();if(this.state==="identified")throw new K;if(this.state==="anonymous"){let i=await this.performLink("/auth-service/me/link/email",{email:e,password:t},"upgrade");if(i.kind==="done")return i.user;throw i.kind==="credential_in_use"?new b(i.message):new u("RECENT_AUTH_REQUIRED",i.message??"Re-authenticate first",{status:i.status??403})}let n=await this.performSwitch(async()=>{let i=await this.http.post("/auth-service/signup",{email:e,password:t,name:r?.name,metadata:r?.metadata});if(!i.success&&i.error?.code==="CONFLICT")throw new b(i.error.message);return i},"AUTH_ERROR","Signup failed");if(n.kind==="mfa")throw new u("MFA_REQUIRED","Unexpected MFA challenge on signup");return n.user})}linkEmailPassword(e,t){return this.linkLegacy({kind:"password",email:e,password:t})}linkSocial(e){let{provider:t,...r}=e;return this.linkLegacy({kind:t,...r})}linkGoogle(e){return this.linkSocial({provider:"google",...e})}linkApple(e){return this.linkSocial({provider:"apple",...e})}linkLegacy(e){return this.serialize(async()=>{if(this.state==="withheld")throw this.withheldError();if(this.state==="unknown"&&await this.settle(),this.status()==="withheld")throw this.withheldError();if(this.state==="signed_out")throw new u("NOT_SIGNED_IN","Sign in before linking a credential");let t=Je(e),r=await this.performLink(t.path,t.body,"link");if(r.kind==="done")return r.user;throw r.kind==="recent_auth_required"?new u("RECENT_AUTH_REQUIRED",r.message??"Re-authenticate to link this credential",{status:r.status??403}):new C(r.message,{provider:r.provider,collision:r.collision,status:r.status})})}getHeldGuests(){return this.store.readSlots().slots.filter(e=>e!==null).sort((e,t)=>t.heldAt-e.heldAt).map(({userId:e,heldAt:t,autoRestore:r,project:n})=>({userId:e,heldAt:t,autoRestore:r,project:n}))}getHeldGuest(){return this.getHeldGuests()[0]??null}resolveSlot(e){let{slots:t}=this.store.readSlots(),r=t.map((n,i)=>n?{slot:n,index:i}:null).filter(n=>n!==null);if(r.length===0)throw new u("HELD_GUEST_NOT_FOUND","No guest is held on this device");if(e!==void 0){let n=r.find(i=>i.slot.userId===e);if(!n)throw new u("HELD_GUEST_NOT_FOUND",`No held guest with id ${e}`);return n}if(r.length>1)throw new u(he,`${r.length} guests are held; pass the userId of the one you mean`);return r[0]}claimHeldGuest(e){return this.serialize(async()=>{if(this.state==="withheld")throw this.withheldError();if(this.state!=="identified"||!this.record)throw new u("NOT_IDENTIFIED","claimHeldGuest() needs a signed-in identified account as the merge target");let{index:t,slot:r}=this.resolveSlot(e),n=this.currentSid();this.attemptInFlight=!0;try{await this.refreshInflight;let i=await this.refreshHeld(t,r);if(i.kind==="dead")throw new u("HELD_GUEST_GONE",`Held guest ${r.userId} is no longer available (${i.endReason})`);let o=this.store.currentRefresh();if(!o)throw new u("NOT_SIGNED_IN","Not signed in");let a=await this.http.post("/auth-service/merge",{anonymousRefreshToken:i.tokens.refreshToken,targetRefreshToken:o});if(!a.success||!a.data)throw new u(a.error?.code??"MERGE_FAILED",a.error?.message??"Merge failed",p(a));let l=X(a.data),d=Xe(a.data,this.record.user.id,r.userId);await this.refreshInflight;let h=this.record;if(!l||!h)throw this.commit({type:"release",index:t,reason:"claimed"}),new u("MERGE_FAILED","Merge succeeded but returned no rotated session; sign in again",{kind:"server"});if(!this.commit({type:"install",reason:"claim",record:{...h,accessToken:l.accessToken,accessExpiresAt:Date.now()+l.expiresIn*1e3,refreshToken:l.refreshToken},expectSid:n,expectRefresh:o,release:{index:t,reason:"claimed"}}))throw this.commit({type:"release",index:t,reason:"claimed"}),new u("CLAIM_SUPERSEDED","The session changed while the claim was in flight",{kind:"cancelled"});return{user:this.record.user,stats:d}}finally{this.attemptInFlight=!1}})}restoreHeldGuest(e){return this.serialize(async()=>{if(this.state==="withheld")throw this.withheldError();if(this.state==="unknown"&&await this.settle(),this.status()==="withheld")throw this.withheldError();let{index:t,slot:r}=this.resolveSlot(e),n=await this.restoreSlot(t,r,"verb");if(!n)throw new u("HELD_GUEST_GONE",`Held guest ${r.userId} is no longer available`);return n})}async restoreSlot(e,t,r){let n=this.slotProjectAnchor;if(n!==void 0&&t.project!==null&&t.project!==n)throw new _(t.userId,n,t.project);let i=this.currentSid();this.attemptInFlight=!0;try{await this.refreshInflight;let o=await this.refreshHeld(e,t);if(o.kind==="dead")return null;if(this.judge(o.tokens.accessToken)!=="match")throw new _(t.userId,this.expectedProjectId??n??"",this.projectClaim(o.tokens.accessToken));let l=o.user??et(o.tokens.accessToken,t.userId);await this.refreshInflight;let d=this.record,h=d&&d.user.isAnonymous&&d.user.id!==l.id?this.buildHeld(d):void 0;if(!this.commit({type:"install",reason:"restore",record:{v:1,user:l,accessToken:o.tokens.accessToken,accessExpiresAt:Date.now()+o.tokens.expiresIn*1e3,refreshToken:o.tokens.refreshToken},expectSid:i,hold:h,release:{index:e,reason:"restored"},revokePrevious:!!d&&!d.user.isAnonymous}))throw new u("SIGN_IN_SUPERSEDED",`The session changed while restoring${r==="mint"?" (auto-restore)":""}; nothing was installed`,{kind:"cancelled"});return l}finally{this.attemptInFlight=!1}}discardHeldGuest(e){return this.serialize(async()=>{if(this.state==="withheld")throw this.withheldError();let{index:t,slot:r}=this.resolveSlot(e);await this.discardSlot(t,r)})}async discardSlot(e,t){let r=await this.http.post("/auth-service/guest/discard",{refreshToken:t.refreshToken}),n=r.error?.status;if(r.success||n===404||r.error?.code==="NOT_FOUND"){this.commit({type:"release",index:e,reason:"discarded"});return}throw new u(r.error?.code??"GUEST_DISCARD_FAILED",r.error?.message??"Could not discard the held guest",p(r))}merge(e){let{slots:t}=this.store.readSlots(),r=t.find(n=>n!==null&&(n.refreshToken===e||n.tokenAtHold===e));return r?this.claimHeldGuest(r.userId).then(n=>n.stats):this.serialize(async()=>{if(this.state==="withheld")throw this.withheldError();if(this.state!=="identified"||!this.record)throw new u("NOT_IDENTIFIED","merge() needs a signed-in identified account as the target");let n=this.currentSid(),i=this.store.currentRefresh();if(!i)throw new u("NOT_SIGNED_IN","Not signed in");let o=await this.http.post("/auth-service/merge",{anonymousRefreshToken:e,targetRefreshToken:i});if(!o.success||!o.data)throw new u(o.error?.code??"MERGE_FAILED",o.error?.message??"Merge failed",p(o));let a=X(o.data),l=Xe(o.data,this.record.user.id,"");await this.refreshInflight;let d=this.record;return a&&d&&this.commit({type:"install",reason:"claim",record:{...d,accessToken:a.accessToken,accessExpiresAt:Date.now()+a.expiresIn*1e3,refreshToken:a.refreshToken},expectSid:n,expectRefresh:i}),l})}getWithheld(){return this.withheld?.info??null}discardWithheld(){return this.serialize(async()=>this.discardWithheldNow())}discardWithheldNow(){return this.state!=="withheld"||!this.withheld?!1:this.commit({type:"clear",reason:"user",expectRefresh:this.withheld.refreshToken,revoke:!0,dropQueue:!1,stampNoAutoRestore:!1,keepAnalyticsIdentity:!0})?!0:(this.hydrateFromDisk("storage_event"),!1)}signOut(){return this.serialize(async()=>{if(this.state==="withheld"){this.discardWithheldNow();return}if(this.state==="signed_out"){this.analytics.reset(!0),this.flags.reset(),this.chatbot.newSession();return}this.commit({type:"clear",reason:"user",revoke:!0,dropQueue:!1,stampNoAutoRestore:!1})})}deleteAccount(e){return this.serialize(async()=>{if(this.state==="withheld")throw this.withheldError();if(this.state==="unknown"&&await this.settle(),this.status()==="withheld")throw this.withheldError();if(this.state==="signed_out")throw new u("NOT_SIGNED_IN","Sign in before deleting your account");let t=await this.bearerHeaders(),r=await this.http.delete("/auth-service/me",t);if(!r.success)throw new u(r.error?.code??"DELETE_ACCOUNT_FAILED",r.error?.message??"Account deletion failed",p(r));let n=r.data??{};this.commit({type:"clear",reason:"account_deleted",revoke:!1,dropQueue:!0,stampNoAutoRestore:!0});let i={status:n.status==="purged"?"purged":"pending",scheduledPurgeAt:n.scheduledPurgeAt??null,graceDays:typeof n.graceDays=="number"?n.graceDays:0,heldGuests:this.heldCount()};if(e?.alsoDiscardHeldGuests){let o=[],{slots:a}=this.store.readSlots();for(let l=0;l<a.length;l++){let d=a[l];if(d)try{await this.discardSlot(l,d)}catch{o.push(d.userId)}}i.heldGuests=this.heldCount(),i.discardFailed=o}return i})}async listLinkedIdentities(){let e=await this.bearerHeaders().catch(()=>{throw new u("NOT_SIGNED_IN","Sign in before listing linked identities")}),t=await this.http.get("/auth-service/me/identities",e);if(!t.success||!t.data)throw new u(t.error?.code??"IDENTITIES_FAILED",t.error?.message??"Failed to list linked identities",p(t));return{identities:t.data.identities??[],hasPassword:!!t.data.hasPassword}}async unlink(e){let t=await this.bearerHeaders().catch(()=>{throw new u("NOT_SIGNED_IN","Sign in before unlinking an identity")}),r=await this.http.delete(`/auth-service/me/identities/${encodeURIComponent(e)}`,t);if(!r.success||!r.data)throw new u(r.error?.code??"UNLINK_FAILED",r.error?.message??"Failed to unlink identity",p(r));return{provider:r.data.provider??e,removed:Number(r.data.removed??0),remaining:Number(r.data.remaining??0)}}async sendMagicLink(e){let t=await this.http.post("/auth-service/magic-link/request",{email:e});if(!t.success)throw new u(t.error?.code??"MAGIC_LINK_REQUEST_FAILED",t.error?.message??"Failed to send link")}async sendEmailOtp(e){let t=await this.http.post("/auth-service/email-otp/request",{email:e});if(!t.success)throw new u(t.error?.code??"EMAIL_OTP_REQUEST_FAILED",t.error?.message??"Failed to send code")}verifyEmailOtp(e,t){return this.serialize(async()=>{let r=await this.performSwitch(()=>this.http.post("/auth-service/email-otp/verify",{email:e,code:t}),"EMAIL_OTP_INVALID","Wrong or expired code");if(r.kind==="mfa")throw new u("MFA_REQUIRED","This account requires MFA; use signIn()/challengeMfa()");return r.user})}verifyMagicLink(e){return this.serialize(async()=>{let t=await this.performSwitch(()=>this.http.post("/auth-service/magic-link/verify",{token:e}),"MAGIC_LINK_INVALID","Invalid or expired magic link");if(t.kind==="mfa")throw new u("MFA_REQUIRED","This account requires MFA; use signIn()/challengeMfa()");return t.user})}async requestPasswordReset(e){let t=await this.http.post("/auth-service/password/forgot",{email:e});if(!t.success)throw new u(t.error?.code??"PASSWORD_RESET_REQUEST_FAILED",t.error?.message??"Failed to send reset email")}async resetPassword(e,t){let r=await this.http.post("/auth-service/password/reset",{token:e,newPassword:t});if(!r.success)throw new u(r.error?.code??"PASSWORD_RESET_FAILED",r.error?.message??"Reset failed")}async verifyEmail(e){let t=await this.http.post("/auth-service/email/verify",{token:e});if(!t.success)throw new u(t.error?.code??"EMAIL_VERIFICATION_FAILED",t.error?.message??"Verification failed")}async sendVerificationEmail(){let e=await this.bearerHeaders().catch(r=>{throw r instanceof u&&r.code===G.SESSION_WITHHELD?r:new u("UNAUTHORIZED","Sign in before requesting a verification email")}),t=await this.http.post("/auth-service/email/verify/resend",{},e);if(!t.success)throw new u(t.error?.code??"VERIFICATION_RESEND_FAILED",t.error?.message??"Failed to send verification email")}async enrollMfa(){let e=await this.http.post("/auth-service/mfa/enroll/start",{},await this.bearerHeaders());if(!e.success||!e.data)throw new u(e.error?.code??"MFA_ENROLL_FAILED",e.error?.message??"MFA enrollment failed");return e.data}async confirmMfa(e){let t=await this.http.post("/auth-service/mfa/enroll/confirm",{code:e},await this.bearerHeaders());return!!(t.success&&t.data?.confirmed)}async disableMfa(){let e=await this.http.post("/auth-service/mfa/disable",{},await this.bearerHeaders());if(!e.success)throw new u(e.error?.code??"MFA_DISABLE_FAILED",e.error?.message??"Failed to disable MFA",p(e))}async registerPasskey(e){if(typeof navigator>"u"||!navigator.credentials)throw new u("PASSKEY_UNSUPPORTED","WebAuthn not supported in this environment");let t=await this.http.post("/auth-service/passkeys/register/start",{},await this.bearerHeaders());if(!t.success||!t.data)throw new u(t.error?.code??"PASSKEY_START_FAILED",t.error?.message??"Passkey start failed");let r=Vt(t.data),n;try{let a=await navigator.credentials.create({publicKey:r});if(!a)throw new Error("create returned null");n=a}catch(a){throw new u("PASSKEY_USER_CANCELLED",a instanceof Error?a.message:"User cancelled passkey registration")}let i=qt(n),o=await this.http.post("/auth-service/passkeys/register/finish",{response:i,name:e},await this.bearerHeaders());if(!o.success||!o.data)throw new u(o.error?.code??"PASSKEY_FINISH_FAILED",o.error?.message??"Passkey verification failed");return o.data}signInWithPasskey(e){return this.serialize(async()=>{if(typeof navigator>"u"||!navigator.credentials)throw new u("PASSKEY_UNSUPPORTED","WebAuthn not supported in this environment");if(this.state==="withheld")throw this.withheldError();let t=await this.http.post("/auth-service/passkeys/authenticate/start",{userId:e??null});if(!t.success||!t.data)throw new u(t.error?.code??"PASSKEY_START_FAILED",t.error?.message??"Passkey start failed",p(t));let r=$t(t.data),n;try{let a=await navigator.credentials.get({publicKey:r});if(!a)throw new Error("get returned null");n=a}catch(a){throw new u("PASSKEY_USER_CANCELLED",a instanceof Error?a.message:"User cancelled passkey signin")}let i=Bt(n),o=await this.performSwitch(()=>this.http.post("/auth-service/passkeys/authenticate/finish",{response:i,userId:e??null}),"PASSKEY_AUTH_FAILED","Passkey signin failed");if(o.kind==="mfa")throw new u("MFA_REQUIRED","This account requires MFA; use signIn()/challengeMfa()");return o.user})}async listPasskeys(){let e=await this.http.get("/auth-service/passkeys",await this.bearerHeaders());return!e.success||!Array.isArray(e.data)?[]:e.data}async deletePasskey(e){let t=await this.http.delete(`/auth-service/passkeys/${encodeURIComponent(e)}`,await this.bearerHeaders());if(!t.success)throw new u(t.error?.code??"PASSKEY_DELETE_FAILED",t.error?.message??"Failed to delete passkey",p(t))}async listMySessions(){let e=await this.http.get("/auth-service/sessions/me",await this.bearerHeaders());return!e.success||!Array.isArray(e.data)?[]:e.data}async revokeSession(e){let t=await this.http.delete(`/auth-service/sessions/me/${encodeURIComponent(e)}`,await this.bearerHeaders());if(!t.success)throw new u(t.error?.code??"SESSION_REVOKE_FAILED",t.error?.message??"Failed to revoke session",p(t))}async revokeAllSessions(){let e=await this.http.delete("/auth-service/sessions/me",await this.bearerHeaders());if(!e.success)throw new u(e.error?.code??"SESSION_REVOKE_ALL_FAILED",e.error?.message??"Failed to sign out other devices",p(e))}async startSso(e){let t=await this.http.post("/auth-service/sso/oidc/start",{returnTo:e});if(!t.success||!t.data)throw new u(t.error?.code??"SSO_START_FAILED",t.error?.message??"SSO start failed");return t.data}async signInWithSso(e){let t=e??(typeof window<"u"?window.location.origin:"");if(!t)throw new u("SSO_NO_RETURN_TO","returnTo required outside browser context");let r=await this.startSso(t);typeof window<"u"&&(window.location.href=r.authorizationUrl)}async startSaml(e){let t=await this.http.post("/auth-service/sso/saml/start",{returnTo:e});if(!t.success||!t.data)throw new u(t.error?.code??"SAML_START_FAILED",t.error?.message??"SAML start failed");return t.data}async signInWithSaml(e){let t=e??(typeof window<"u"?window.location.origin:"");if(!t)throw new u("SAML_NO_RETURN_TO","returnTo required outside browser context");let r=await this.startSaml(t);typeof window<"u"&&(window.location.href=r.authorizationUrl)}consumeSsoTokenFromUrl(){return this.serialize(async()=>{if(typeof window>"u")return null;let e=window.location.hash.replace(/^#/,"");if(!e)return null;let t=new URLSearchParams(e),r=t.get("sendora_oidc_error")??t.get("sendora_saml_error");if(r)throw window.history.replaceState(null,"",window.location.pathname+window.location.search),new u("SSO_FAILED",decodeURIComponent(r));let n=t.get("sendora_oidc_token")??t.get("sendora_saml_token");if(!n)return null;let i=t.get("sendora_retired_anon");window.history.replaceState(null,"",window.location.pathname+window.location.search);let o=await this.performSwitch(async()=>{let a=await this.http.post("/auth-service/token/refresh",{refreshToken:n}),l=a.success?X(a.data):null;return l?{success:!0,data:{user:Z(a.data)??et(l.accessToken,Ze(l.accessToken)??"",!1),tokens:{...l,tokenType:"Bearer"}}}:{success:!1,error:a.error??{code:"SSO_EXCHANGE_FAILED",message:"Could not exchange SSO token"}}},"SSO_EXCHANGE_FAILED","Could not exchange SSO token");if(o.kind==="mfa")throw new u("MFA_REQUIRED","Unexpected MFA challenge on SSO exchange");return i&&this.fireDeviceTakeover(i,o.user.id),o.user})}};function Qe(s){return s?ue.includes(s):!1}function _e(s){return{v:1,user:s.user,accessToken:s.tokens.accessToken,accessExpiresAt:Date.now()+s.tokens.expiresIn*1e3,refreshToken:s.tokens.refreshToken}}function Wt(){let s="abcdefghijklmnopqrstuvwxyz0123456789",e=new Uint8Array(32),t=globalThis.crypto;if(t?.getRandomValues)t.getRandomValues(e);else for(let n=0;n<e.length;n++)e[n]=Math.floor(Math.random()*256);let r="mk_";for(let n=0;n<e.length;n++)r+=s[e[n]%s.length];return r}function Ye(s){switch(s.kind){case"password":return{path:"/auth-service/login",body:{email:s.email,password:s.password}};case"gameCenter":{let{kind:e,...t}=s;return{path:"/auth-service/login/game-center",body:t}}case"playGames":return{path:"/auth-service/login/play-games",body:{serverAuthCode:s.serverAuthCode}};case"magicLink":return{path:"/auth-service/magic-link/verify",body:{token:s.token}};case"emailOtp":return{path:"/auth-service/email-otp/verify",body:{email:s.email,code:s.code}};case"passkey":return{path:"/auth-service/passkeys/authenticate/finish",body:{response:s.assertion,userId:s.userId??null}};case"mfa":return{path:"/auth-service/mfa/challenge",body:{challengeToken:s.challengeToken,code:s.code}};default:{let{kind:e,...t}=s;return{path:"/auth-service/login/social",body:{provider:e,...t}}}}}function Je(s){switch(s.kind){case"password":return{path:"/auth-service/me/link/email",body:{email:s.email,password:s.password}};case"gameCenter":{let{kind:e,...t}=s;return{path:"/auth-service/me/link/game-center",body:t}}case"playGames":return{path:"/auth-service/me/link/play-games",body:{serverAuthCode:s.serverAuthCode}};case"magicLink":case"emailOtp":case"passkey":case"mfa":throw new u("UNSUPPORTED_LINK_CREDENTIAL",`A ${s.kind} credential cannot be linked; sign in with it instead`);default:{let{kind:e,...t}=s;return{path:"/auth-service/me/link/social",body:{provider:e,...t}}}}}function Xe(s,e,t){let r=s&&typeof s=="object"?s:{},n=i=>typeof r[i]=="number"?r[i]:0;return{mergedUserId:typeof r.mergedUserId=="string"?r.mergedUserId:e,deletedAnonymousId:typeof r.deletedAnonymousId=="string"?r.deletedAnonymousId:t,eventsReassigned:n("eventsReassigned"),profilesReassigned:n("profilesReassigned"),entitiesReassigned:n("entitiesReassigned"),pushTokensReassigned:n("pushTokensReassigned")}}function Ze(s){let e=A(s)?.sub;return typeof e=="string"&&e.length>0?e:null}function et(s,e,t=!0){let r=A(s)??{},n=typeof r.sub=="string"&&r.sub.length>0?r.sub:e,i=typeof r.is_anonymous=="boolean"?r.is_anonymous:t,o={id:n,email:typeof r.email=="string"?r.email:null,emailVerified:typeof r.email_verified=="boolean"?r.email_verified:!i,name:typeof r.name=="string"?r.name:null,isAnonymous:i};if(Object.prototype.hasOwnProperty.call(r,"project")){let a=r.project;o.project=typeof a=="string"?a:null}return o}function ee(s){let e=(4-s.length%4)%4,t=(s+"===".slice(0,e)).replace(/-/g,"+").replace(/_/g,"/"),r=atob(t),n=new ArrayBuffer(r.length),i=new Uint8Array(n);for(let o=0;o<r.length;o++)i[o]=r.charCodeAt(o);return n}function I(s){let e=s instanceof Uint8Array?s:new Uint8Array(s),t="";for(let r=0;r<e.length;r++)t+=String.fromCharCode(e[r]);return btoa(t).replace(/\+/g,"-").replace(/\//g,"_").replace(/=+$/,"")}function Vt(s){return{challenge:ee(s.challenge),rp:s.rp,user:{id:ee(s.user.id),name:s.user.name,displayName:s.user.displayName},pubKeyCredParams:s.pubKeyCredParams,timeout:s.timeout,attestation:s.attestation,excludeCredentials:s.excludeCredentials?.map(e=>({id:ee(e.id),type:"public-key",transports:e.transports})),authenticatorSelection:s.authenticatorSelection}}function $t(s){return{challenge:ee(s.challenge),timeout:s.timeout,rpId:s.rpId,allowCredentials:s.allowCredentials?.map(e=>({id:ee(e.id),type:"public-key",transports:e.transports})),userVerification:s.userVerification}}function qt(s){let e=s.response;return{id:s.id,rawId:I(s.rawId),type:s.type,response:{clientDataJSON:I(e.clientDataJSON),attestationObject:I(e.attestationObject),transports:typeof e.getTransports=="function"?e.getTransports():void 0},clientExtensionResults:s.getClientExtensionResults()}}function X(s){if(!s||typeof s!="object")return null;let e=s.tokens,t=e&&typeof e=="object"?e:s;return typeof t.accessToken!="string"||!t.accessToken||typeof t.refreshToken!="string"||!t.refreshToken||typeof t.expiresIn!="number"||t.expiresIn<=0?null:{accessToken:t.accessToken,refreshToken:t.refreshToken,expiresIn:t.expiresIn}}function Z(s){if(!s||typeof s!="object")return null;let e=s.user;if(!e||typeof e!="object")return null;let t=e.id;return typeof t!="string"||t.length===0?null:e}function tt(s,e){let t=A(s);if(!t)return!0;let r=t.exp;return typeof r!="number"||!Number.isFinite(r)?!0:e<r*1e3}function Bt(s){let e=s.response;return{id:s.id,rawId:I(s.rawId),type:s.type,response:{clientDataJSON:I(e.clientDataJSON),authenticatorData:I(e.authenticatorData),signature:I(e.signature),userHandle:e.userHandle?I(e.userHandle):null},clientExtensionResults:s.getClientExtensionResults()}}var rt=j;function zt(s){return s===!1?{pageViews:!1,sessionStart:!1,appOpen:!1,appBackground:!1,engagement:!1}:s===!0||s===void 0?{pageViews:!0,sessionStart:!0,appOpen:!0,appBackground:!0,engagement:!0}:{pageViews:s.pageViews??!0,sessionStart:s.sessionStart??!0,appOpen:s.appOpen??!0,appBackground:s.appBackground??!0,engagement:s.engagement??!0}}var Qt=250,st=360*60*1e3;function ot(s,e){if(typeof window>"u")return()=>{};let t=zt(e.autoTrack),r=e.sessionIdleMs??18e5,n=[],i="sendora_session_id",o="sendora_session_last_activity";function a(){return nt(i)??""}function l(c){it(i,c)}function d(){let c=nt(o);return c&&Number(c)||0}function h(c){it(o,String(c))}function g(){return`sess_${Date.now().toString(36)}_${Math.random().toString(36).slice(2,10)}`}function k(c){let S=Date.now(),Q=d();if(!a()||Q&&S-Q>r){let re=g();l(re),c&&t.sessionStart&&s.track("session.start",{sessionId:re})}h(S)}k(t.sessionStart),t.appOpen&&s.track("app.opened",{sessionId:a()||void 0,url:window.location.origin+window.location.pathname,referrer:document.referrer||void 0});let v=window.location.pathname,y=0,w=document.visibilityState==="visible"?Date.now():0;function z(){w>0&&(y+=Date.now()-w,w=0)}function te(){if(!t.engagement)return;z();let c=y;if(y=0,!(c<Qt)){c>st&&(c=st);try{s.track("app.engagement",{durationMs:Math.round(c),screen:v,sessionId:a()||void 0})}catch{}}}function lt(c){v=c,y=0,w=document.visibilityState==="visible"?Date.now():0}if(t.pageViews||t.engagement){t.pageViews&&s.page();let c=()=>{te(),k(!0),t.pageViews&&s.page(),lt(window.location.pathname)},S=()=>c();window.addEventListener("popstate",S),n.push(()=>window.removeEventListener("popstate",S));let Q=window;if(!Q.__sendoraHistoryPatched){Q.__sendoraHistoryPatched=!0;let re=history.pushState,ut=history.replaceState;history.pushState=function(...ve){let Ae=re.apply(this,ve);return window.dispatchEvent(new Event("sendora:locationchange")),Ae},history.replaceState=function(...ve){let Ae=ut.apply(this,ve);return window.dispatchEvent(new Event("sendora:locationchange")),Ae}}let ke=()=>c();window.addEventListener("sendora:locationchange",ke),n.push(()=>window.removeEventListener("sendora:locationchange",ke))}if(t.appBackground||t.engagement){let c=()=>{if(document.visibilityState==="hidden"){te(),t.appBackground&&(k(!0),s.track("app.backgrounded",{sessionId:a()||void 0}));try{s.flush()}catch{}}else document.visibilityState==="visible"&&(t.appBackground&&(k(!0),s.track("app.foregrounded",{sessionId:a()||void 0})),t.engagement&&w===0&&(w=Date.now()))};if(document.addEventListener("visibilitychange",c),n.push(()=>document.removeEventListener("visibilitychange",c)),t.engagement){let S=()=>{te();try{s.flush()}catch{}};window.addEventListener("pagehide",S),n.push(()=>window.removeEventListener("pagehide",S))}}let De=0,D=()=>{let c=Date.now();c-De<5e3||(De=c,k(!0))};return window.addEventListener("click",D,{passive:!0}),window.addEventListener("keydown",D,{passive:!0}),window.addEventListener("scroll",D,{passive:!0}),n.push(()=>{window.removeEventListener("click",D),window.removeEventListener("keydown",D),window.removeEventListener("scroll",D)}),()=>{te();for(let c of n)try{c()}catch{}}}function nt(s){try{return window.sessionStorage?.getItem(s)??null}catch{return null}}function it(s,e){try{window.sessionStorage?.setItem(s,e)}catch{}}var $=class s{constructor(e){this.http=e}static isSupported(){return typeof window>"u"?!1:"serviceWorker"in navigator&&"PushManager"in window&&"Notification"in window}static permission(){return typeof Notification>"u"?"denied":Notification.permission}async subscribe(e){if(!s.isSupported())throw new Error("[sendoracloud] Web Push not supported in this browser.");let t=Notification.permission;if(t==="default"&&(t=await Notification.requestPermission()),t!=="granted")throw new Error(`[sendoracloud] Notification permission ${t}.`);let r=await navigator.serviceWorker.getRegistration(e.scope??"/");r||(r=await navigator.serviceWorker.register(e.serviceWorkerPath,{scope:e.scope??"/"})),await navigator.serviceWorker.ready;let i=(await this.http.get("/push/vapid"))?.data?.publicKey;if(!i)throw new Error("[sendoracloud] backend returned no VAPID public key.");let a=await r.pushManager.getSubscription()??await r.pushManager.subscribe({userVisibleOnly:!0,applicationServerKey:Yt(i)}),l=a.toJSON(),d=l.endpoint,h=l.keys?.p256dh??"",g=l.keys?.auth??"",k=await Jt(d),v=await this.http.post("/push/tokens",{platform:"web",token:k,webEndpoint:d,webP256dh:h,webAuth:g,userAgent:typeof navigator<"u"?navigator.userAgent:void 0,locale:typeof navigator<"u"?navigator.language:void 0,timezone:Intl?.DateTimeFormat?.().resolvedOptions?.().timeZone,...e.userId?{userId:e.userId}:{}});if(!v?.data?.tokenId)throw new Error("[sendoracloud] backend returned no tokenId on subscribe.");return{tokenId:v.data.tokenId,subscription:a}}async unsubscribe(e="/"){if(!s.isSupported())return!1;let t=await navigator.serviceWorker.getRegistration(e);if(!t)return!1;let r=await t.pushManager.getSubscription();return r?await r.unsubscribe():!1}async trackOpen(e,t){let r={sendId:e};t!==void 0&&(r.clickAction=t);let n=await this.http.post("/push/track-open",r);if(!n.success)throw new Error(n.error?.message??"push.trackOpen failed")}};function Yt(s){let e="=".repeat((4-s.length%4)%4),t=(s+e).replace(/-/g,"+").replace(/_/g,"/"),r=atob(t),n=new Uint8Array(r.length);for(let i=0;i<r.length;i++)n[i]=r.charCodeAt(i);return n}async function Jt(s){let e=new TextEncoder().encode(s),t=await crypto.subtle.digest("SHA-256",e);return Array.from(new Uint8Array(t)).map(n=>n.toString(16).padStart(2,"0")).join("")}var q=class{constructor(e){}unsupported(){throw new Error("[SendoraCloud] sendora.audiences is not available in the browser SDK. Audiences require a secret (sk_*) key with the audiences:read/write scopes and must be managed from a trusted server, not the browser.")}list(){return this.unsupported()}get(e){return this.unsupported()}create(e){return this.unsupported()}update(e,t){return this.unsupported()}delete(e){return this.unsupported()}};var f=class extends Error{constructor(e,t,r){super(t),this.name="LinkError",this.code=e,this.statusCode=r}};function be(s,e){let t=(s??"").toUpperCase();return t==="NOT_FOUND"?new f("NOT_FOUND",e):t==="FORBIDDEN"||t==="UNAUTHORIZED"?new f("UNAUTHORIZED",e):t==="RATE_LIMITED"?new f("RATE_LIMITED",e):t==="ENTITLEMENT_ERROR"||/plan limit/i.test(e)?new f("PLAN_LIMIT",e):t==="VALIDATION_ERROR"?/iOS bundle|Android package/i.test(e)?new f("BUNDLE_MISMATCH",e):/2KB|10KB|linkData/i.test(e)?new f("DATA_TOO_LARGE",e):/fallbackUrl/i.test(e)&&/apps/i.test(e)?new f("FALLBACK_REQUIRED",e):new f("INVALID_INPUT",e):t==="PARSE_ERROR"||t==="HTTP_ERROR"||/HTTP \d{3}/.test(e)?new f("NETWORK",e):new f("UNKNOWN",e||`Unknown LinkError (code=${s??"none"})`)}var Ce=/^[a-z0-9-]{3,20}$/;function at(s){try{let t=new URL(s).pathname.split("/").filter(Boolean);if(t.length===0)return null;let r=t[t.length-1];return Ce.test(r)?r:null}catch{return null}}var Xt=5*6e4,Zt=50,er=5,B=class{constructor(e){this.http=e;this.prewarmCache=new Map;this.prewarmInflight=0}cacheKey(e,t){if(t)return`k:${t}`;let r={},n=e;for(let i of Object.keys(n).sort())r[i]=n[i];return`s:${JSON.stringify(r)}`}evictExpired(){let e=Date.now();for(let[t,r]of this.prewarmCache)e-r.ts>Xt&&this.prewarmCache.delete(t);for(;this.prewarmCache.size>Zt;){let t=this.prewarmCache.keys().next().value;if(t===void 0)break;this.prewarmCache.delete(t)}}prewarm(e,t){this.evictExpired();let r=this.cacheKey(e,t?.key);if(this.prewarmCache.has(r)||this.prewarmInflight>=er)return;this.prewarmInflight++;let n=this.doCreate(e).catch(i=>{throw this.prewarmCache.delete(r),i}).finally(()=>{this.prewarmInflight--});this.prewarmCache.set(r,{promise:n,ts:Date.now()})}async create(e,t){if(!e.title)throw new f("INVALID_INPUT","links.create: title is required");this.evictExpired();let r=this.cacheKey(e,t?.key),n=this.prewarmCache.get(r);return n?(this.prewarmCache.delete(r),n.promise):this.doCreate(e)}async doCreate(e){let t={title:e.title};e.fallbackUrl&&(t.fallbackUrl=e.fallbackUrl),e.iosDeepLinkPath&&(t.iosDeepLinkPath=e.iosDeepLinkPath),e.androidDeepLinkPath&&(t.androidDeepLinkPath=e.androidDeepLinkPath),e.linkData&&(t.linkData=e.linkData),e.ogTitle&&(t.ogTitle=e.ogTitle),e.ogDescription&&(t.ogDescription=e.ogDescription),e.ogImageUrl&&(t.ogImageUrl=e.ogImageUrl),e.campaign&&(t.campaign=e.campaign),e.source&&(t.source=e.source),e.medium&&(t.medium=e.medium),e.channel&&(t.channel=e.channel),e.tags&&(t.tags=e.tags),e.expiresAt&&(t.expiresAt=e.expiresAt),e.iosBundleId&&(t.iosBundleId=e.iosBundleId),e.androidPackageName&&(t.androidPackageName=e.androidPackageName);let r=await this.http.post("/sdk/links",t);if(!r.success||!r.data)throw be(r.error?.code,r.error?.message??"links.create failed");return r.data}async revoke(e){if(!Ce.test(e))throw new f("INVALID_INPUT",`links.revoke: '${e}' is not a valid shortcode`);let t=await this.http.post(`/sdk/links/${encodeURIComponent(e)}/revoke`,{});if(!t.success||!t.data)throw be(t.error?.code,t.error?.message??"links.revoke failed");return{shortcode:t.data.shortcode,revoked:!0}}async getStats(e){if(!Ce.test(e))throw new f("INVALID_INPUT",`links.getStats: '${e}' is not a valid shortcode`);let t=await this.http.get(`/sdk/links/${encodeURIComponent(e)}/stats`);if(!t.success||!t.data)throw be(t.error?.code,t.error?.message??"links.getStats failed");return t.data}};var fe=class{constructor(e){this.http=e}async reportInstall(e={}){let t=await this.http.post("/attribution/install",e);if(!t.success||!t.data)throw new Error(t.error?.message??"attribution.reportInstall failed");return t.data}async checkDeferred(e={}){let t=await this.http.post("/attribution/deferred",e);if(!t.success)throw new Error(t.error?.message??"attribution.checkDeferred failed");return t.data??null}};var ge=class{constructor(e){this.http=e}async createTicket(e){let t=await this.http.post("/support/tickets",e);if(!t.success||!t.data)throw new Error(t.error?.message??"support.createTicket failed");return t.data}async submitCsat(e){let t=await this.http.post("/support/csat",e);if(!t.success||!t.data)throw new Error(t.error?.message??"support.submitCsat failed");return t.data}};var me=class{constructor(e){this.http=e}async search(e){if(!e.query||e.query.trim().length===0)return[];let t=new URLSearchParams({query:e.query});e.limit&&t.set("limit",String(e.limit));let r=await this.http.get(`/kb/search?${t.toString()}`);if(!r.success||!Array.isArray(r.data))throw new Error(r.error?.message??"kb.search failed");return r.data}};var tr=/^[A-Za-z0-9_.-]{1,64}$/;function rr(s){if(s!==void 0){if(typeof s!="string"||!tr.test(s))throw new Error(`[sendora] init: storagePrefix must be 1-64 chars of A-Z a-z 0-9 _ . - (got ${JSON.stringify(s)}). Changing it signs the browser out, so it is validated rather than ignored.`);return s}}var sr=/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;function nr(s){let e=s.expectedProjectId;if(e!==void 0){if(typeof e!="string"||!sr.test(e))throw new Error(`[sendora] init: expectedProjectId must be a UUID (got ${JSON.stringify(e)}).`);if(s.projectId!==void 0&&s.projectId!==e)throw new Error(`[sendora] init: expectedProjectId (${e}) must equal projectId (${s.projectId}) when both are set \u2014 they name the same project.`)}}var we=class we{constructor(e){this.autoTrackCleanup=null;this.http=new se(e),this.storage=new ne(rr(e.storagePrefix),e.tokenStore==="memory"),this.consent=new H(e.defaultConsent===!0,this.http),this.analytics=new L(e,this.http,this.storage,this.consent),this.flags=new U(e,this.http,this.storage),this.surveys=new x(e,this.http,this.storage),this.messages=new N(e,this.http,this.storage),this.chatbot=new O(e,this.http,this.storage),this.auth=new V(e,this.http,this.storage,this.analytics,this.flags,this.chatbot,{onIdentityWithheld:()=>{this.analytics.withholdIdentity(),this.flags.setContext({})}}),this.webPush=new $(this.http),this.audiences=new q(this.http),this.links=new B(this.http),this.attribution=new fe(this.http),this.support=new ge(this.http),this.kb=new me(this.http),e.autoTrack!==!1&&(this.autoTrackCleanup=ot(this.analytics,e))}static init(e){return Oe(e.apiKey),nr(e),new we(e)}static sanitizeHtml(e){return ie(e)}static safeUrl(e){return E(e)}track(e,t){this.analytics.track(e,t)}page(e){this.analytics.page(e)}identify(e,t,r){this.analytics.identify(e,t,r),this.flags.setContext({userId:e})}reset(e){this.analytics.reset(),this.flags.reset(),this.chatbot.newSession()}onIdentityWithheld(e){return this.auth.onIdentityWithheld(e)}async flush(){await this.analytics.flush()}destroy(){this.autoTrackCleanup&&(this.autoTrackCleanup(),this.autoTrackCleanup=null),this.analytics.destroy(),this.flags.destroy(),this.messages.destroy()}};we.version=T;var ye=we,ir=ye;0&&(module.exports={AMBIGUOUS_HELD_GUEST,AUTH_HELD_SLOT_KEYS,AUTH_STATES,AUTH_WITHHELD_CODES,AlreadyIdentifiedError,Analytics,Audiences,Auth,AuthError,Chatbot,Consent,CredentialInUseError,DEAD_CODES,EmailAlreadyTakenError,FeatureFlags,HELD_GUEST_SLOTS,HeldGuestLimitError,HeldGuestProjectMismatch,InAppMessaging,LinkError,Links,REFRESH_END_REASONS,REJECTED_IN_WITHHELD,RELEASE_HELD_ON_END_REASONS,SendoraCloud,Surveys,ValidationError,WebPush,extractShortcodeFromUrl,projectVerdict,safeUrl,sanitizeHtml});
package/dist/index.js CHANGED
@@ -1 +1 @@
1
- var De=/^[a-zA-Z][a-zA-Z0-9._:-]{0,127}$/;var it=new Set(["__proto__","constructor","prototype"]),w=class extends Error{constructor(e){super(`[SendoraCloud] ${e}`),this.name="SendoraValidationError"}};function Pe(s){if(typeof s!="string"||!De.test(s))throw new w(`Invalid event name: must match ${De}, got "${String(s)}".`)}function Le(s){if(s==null)return;if(typeof s!="object"||Array.isArray(s))throw new w("Properties must be a plain object, not an array or primitive.");let e=Ue(s);if(e>5)throw new w(`Properties nested too deeply (${e} levels, max 5).`);xe(s);let t;try{t=JSON.stringify(s).length}catch{throw new w("Properties contain a circular reference or unserializable value.")}if(t>32768)throw new w(`Properties too large (${t} bytes, max 32768).`)}function Ue(s,e=0){if(e>6||s==null||typeof s!="object")return e;let t=e;for(let r of Object.keys(s)){let n=Ue(s[r],e+1);n>t&&(t=n)}return t}function xe(s){if(!(s==null||typeof s!="object"))for(let e of Object.keys(s)){if(it.has(e))throw new w(`Forbidden property key "${e}" (prototype pollution guard).`);xe(s[e])}}var ot=/^pk_[A-Za-z0-9_-]{16,}$/;function Ne(s){if(!s||typeof s!="string")throw new w("apiKey is required.");if(s.startsWith("sk_")||s.startsWith("sendora_secret_"))throw new w("Secret keys must NEVER be used in browser SDK. Use a publishable key (pk_...).");if(!ot.test(s))throw new w("Invalid publishable key format. Expected pk_... (17+ chars).")}function Oe(s){let e=s.replace(/\/$/,"");if(!(e.startsWith("http://localhost")||e.startsWith("http://127.0.0.1"))&&!e.startsWith("https://"))throw new w("apiUrl must be https:// (only http://localhost is allowed for dev).")}var He={name:"@sendoracloud/sdk-web",version:"3.24.1",description:"Sendora Cloud Web SDK \u2014 analytics, feature flags, surveys, in-app messaging, chatbot, auth, deep links (Branch / Firebase parity). Zero dependencies, TypeScript, SSR-safe.",type:"module",main:"./dist/index.cjs",module:"./dist/index.js",types:"./dist/index.d.ts",exports:{".":{types:"./dist/index.d.ts",import:"./dist/index.js",require:"./dist/index.cjs"}},files:["dist","README.md","LICENSE"],keywords:["sendora","analytics","feature-flags","surveys","in-app-messaging","chatbot","tracking","customer-engagement"],homepage:"https://sendoracloud.com/sdks",bugs:{url:"https://github.com/sendoracloud/sdk-web/issues"},author:"Sendora Cloud <hello@sendoracloud.com>",license:"Apache-2.0",publishConfig:{access:"public"},sideEffects:!1,scripts:{build:"tsup src/index.ts --format cjs,esm --dts --clean --minify",typecheck:"tsc --noEmit && tsc --noEmit -p tsconfig.test.json",test:"vitest run",prepublishOnly:"npm run build"},devDependencies:{typescript:"^5.4.0",tsup:"^8.0.0"}};var I=He.version;var lt="https://api.sendoracloud.com",ut=1e4,dt="@sendoracloud/sdk-web",re=class{constructor(e){let t=(e.apiUrl??lt).replace(/\/$/,"");Oe(t),this.apiKey=e.apiKey,this.baseUrl=t,this.debug=!!e.debug}get(e,t){return this.request("GET",e,void 0,t)}post(e,t,r){return this.request("POST",e,t,r)}patch(e,t,r){return this.request("PATCH",e,t,r)}delete(e,t){return this.request("DELETE",e,void 0,t)}async request(e,t,r,n){let i=`${this.baseUrl}/api/v1${t}`,o=typeof AbortController<"u"?new AbortController:null,a=o?setTimeout(()=>o.abort(),ut):null;try{let l=await fetch(i,{method:e,headers:{"Content-Type":"application/json","X-API-Key":this.apiKey,"X-Sendora-SDK-Name":dt,"X-Sendora-SDK-Version":I,...n??{}},body:r?JSON.stringify(r):void 0,signal:o?o.signal:void 0});a&&clearTimeout(a);let d;try{d=await l.json()}catch{d={success:!1,error:{code:"PARSE_ERROR",message:`HTTP ${l.status}`}}}if(this.debug&&console.debug(`[SendoraCloud] ${e} ${t} \u2192 ${l.status}`),!l.ok){if(t.startsWith("/auth-service/")&&!this.debug)console.warn(`[SendoraCloud] ${e} ${t} \u2192 HTTP ${l.status}`);else{let g=d?.error?.code??"HTTP_ERROR",k=d?.error?.message??`HTTP ${l.status}`,v=d?.error?.details?.fieldErrors,m=v?` (${Object.entries(v).map(([y,N])=>`${y}: ${(N??[]).join(", ")}`).join("; ")})`:"";console.warn(`[SendoraCloud] ${e} ${t} \u2192 HTTP ${l.status} \u2014 ${g}: ${k}${m}`)}d&&d.error&&(d.error={...d.error,status:l.status})}return d}catch(l){a&&clearTimeout(a);let d=l instanceof Error&&l.name==="AbortError"?"timeout":"error";return console.warn(`[SendoraCloud] ${e} ${t} network ${d}`),{success:!1,error:{code:"NETWORK_ERROR",message:d}}}}};var ct="sendora_",se=class{constructor(e,t=!1){this.memoryStore=new Map;this.useLocalStorage=t?!1:this.checkLocalStorage(),this.prefix=e??ct}get(e){let t=this.prefix+e;if(this.useLocalStorage)try{return localStorage.getItem(t)}catch{return this.memoryStore.get(t)??null}return this.memoryStore.get(t)??null}set(e,t){let r=this.prefix+e;if(this.useLocalStorage)try{localStorage.setItem(r,t);return}catch{}this.memoryStore.set(r,t)}remove(e){let t=this.prefix+e;if(this.useLocalStorage)try{localStorage.removeItem(t)}catch{}this.memoryStore.delete(t)}isPersistent(){return this.useLocalStorage}relativeKey(e){return e.startsWith(this.prefix)?e.slice(this.prefix.length):null}clearPrefix(e){let t=this.prefix+e;if(this.useLocalStorage)try{for(let r=localStorage.length-1;r>=0;r--){let n=localStorage.key(r);n&&n.startsWith(t)&&localStorage.removeItem(n)}}catch{}for(let r of Array.from(this.memoryStore.keys()))r.startsWith(t)&&this.memoryStore.delete(r)}checkLocalStorage(){try{if(typeof localStorage>"u")return!1;let e="__sendora_test__";return localStorage.setItem(e,"1"),localStorage.removeItem(e),!0}catch{return!1}}};function _(s=""){let e=new Uint8Array(16),t=typeof globalThis<"u"&&"crypto"in globalThis?globalThis.crypto:void 0;if(!t||typeof t.getRandomValues!="function")throw new Error("[SendoraCloud] crypto.getRandomValues unavailable \u2014 refusing to mint IDs without a CSPRNG");t.getRandomValues(e);let r="";for(let n of e)r+=n.toString(16).padStart(2,"0");return s+r}var Me=500,ge=10,me=6e4,H=class{constructor(e,t,r,n){this.queue=[];this.timer=null;this.userId=null;this.identityToken=null;this.consecutiveFailures=0;this.nextFlushAfter=0;this.breakerOpenAt=0;this.breakerWarned=!1;this.http=t,this.storage=r,this.consent=n,this.projectId=e.projectId,this.flushInterval=e.flushInterval??5e3,this.maxQueueSize=e.maxQueueSize??20,this.persistUserId=!!e.persistUserId,this.stripQueryParams=e.stripQueryParams!==!1,this.appVersion=e.appVersion,this.storage.get("schema_version")===null&&this.storage.set("schema_version","1");let i=this.storage.get("anonymous_id");if(i?this.anonymousId=i:(this.anonymousId=_("anon_"),this.storage.set("anonymous_id",this.anonymousId)),this.persistUserId){let o=this.storage.get("user_id");o&&(this.userId=o)}this.timer=setInterval(()=>this.flush(),this.flushInterval),typeof window<"u"&&window.addEventListener("beforeunload",()=>this.flush()),this.consent.subscribe(o=>{o&&this.flush()})}track(e,t){Pe(e),t&&Le(t),this.queue.length>=Me&&this.queue.shift(),this.queue.push({eventType:e,properties:t??{},userId:this.userId??void 0,anonymousId:this.anonymousId,timestamp:new Date().toISOString(),identityToken:this.identityToken??void 0}),this.queue.length>=this.maxQueueSize&&this.flush()}page(e){if(typeof window>"u")return;let t=this.stripQueryParams?window.location.origin+window.location.pathname:window.location.href;this.track("page.viewed",{url:t,path:window.location.pathname,title:document.title,referrer:document.referrer||void 0,...e})}identify(e,t,r){if(typeof e!="string"||e.length===0||e.length>256)throw new Error("[SendoraCloud] userId must be a 1-256 char string.");this.userId=e,this.identityToken=r?.identityToken??null,this.persistUserId&&this.storage.set("user_id",e),this.track("user.identified",{...t})}reset(e=!0){this.userId=null,this.identityToken=null,this.storage.remove("user_id"),e&&(this.anonymousId=_("anon_"),this.storage.set("anonymous_id",this.anonymousId)),this.storage.clearPrefix("iam_shown_"),this.storage.clearPrefix("survey_shown_")}withholdIdentity(){this.userId=null,this.identityToken=null}dropQueue(){this.queue=[]}async flush(){if(this.queue.length===0||!this.consent.isGranted()||Date.now()<this.nextFlushAfter)return;this.consecutiveFailures>ge&&Date.now()-this.breakerOpenAt>=me&&(this.consecutiveFailures=0,this.breakerOpenAt=0,this.breakerWarned=!1);let e=this.queue.splice(0,100),t=this.getSessionId(),r=e.map(a=>({projectId:this.projectId,module:"custom",eventType:a.eventType,userId:a.userId,anonymousId:a.anonymousId,identityToken:a.identityToken,timestamp:a.timestamp??new Date().toISOString(),properties:a.properties??{},context:this.getContext(),...t?{sessionId:t}:{},consent:["analytics"]}));if((await this.http.post("/events/batch",{events:r})).success){this.consecutiveFailures=0,this.breakerOpenAt=0,this.breakerWarned=!1;return}if(this.consecutiveFailures++,this.consecutiveFailures>ge){this.breakerWarned||(this.breakerOpenAt=Date.now(),this.breakerWarned=!0,console.warn(`[SendoraCloud] Analytics circuit breaker open after ${ge} consecutive failed flushes \u2014 events will be dropped until a flush succeeds or ${me}ms elapse.`));return}let i=Math.min(me,1e3*2**this.consecutiveFailures);this.nextFlushAfter=Date.now()+i;let o=Math.max(0,Me-this.queue.length);o>0&&this.queue.unshift(...e.slice(0,o))}destroy(){this.timer&&clearInterval(this.timer),this.timer=null,this.flush()}getSessionId(){try{return typeof sessionStorage>"u"?void 0:sessionStorage.getItem("sendora_session_id")||void 0}catch{return}}getContext(){return typeof window>"u"?{sdk:{name:"@sendoracloud/sdk-web",version:I}}:{page:{url:this.stripQueryParams?window.location.origin+window.location.pathname:window.location.href,path:window.location.pathname,title:document.title},referrer:document.referrer||void 0,locale:typeof navigator<"u"?navigator.language:void 0,device:this.buildDevice(),sdk:{name:"@sendoracloud/sdk-web",version:I}}}buildDevice(){if(typeof navigator>"u")return;let e=navigator.userAgent||"",r=navigator.userAgentData?.mobile??/Mobi|Android|iPhone|iPod/i.test(e);return{type:/iPad|Tablet|(?:Android(?!.*Mobile))/i.test(e)?"tablet":r?"mobile":"desktop",os:"Web",osVersion:"",model:"",appVersion:this.resolveAppVersion(),browser:ht(e)}}resolveAppVersion(){if(this.appVersion)return this.appVersion;if(typeof document<"u"){let r=document.querySelector('meta[name="sendora:app-version"]')?.getAttribute("content");if(r)return r}let e=globalThis.__SENDORA_APP_VERSION__;return typeof e=="string"?e:""}};function ht(s){let e=[["Edge",/Edg\/(\d+)/],["Opera",/OPR\/(\d+)/],["Firefox",/Firefox\/(\d+)/],["Samsung Internet",/SamsungBrowser\/(\d+)/],["Chrome",/Chrome\/(\d+)/],["Safari",/Version\/(\d+)[^ ]* Safari/]];for(let[t,r]of e){let n=r.exec(s);if(n)return`${t} ${n[1]}`}return"Unknown"}var M=class{constructor(e,t,r){this.cache=new Map;this.refreshInterval=null;this.http=t,this.storage=r;let n=this.storage.get("flags");if(n)try{let i=JSON.parse(n);if(Array.isArray(i))for(let o of i)ye(o)&&this.cache.set(o.key,o)}catch{}}setContext(e){this.userId=e.userId,this.entityId=e.entityId,this.environment=e.environment}async getFlag(e){if(typeof e!="string"||e.length===0||e.length>128)return null;let t=this.cache.get(e);if(t)return t.value;let r=await this.http.post("/feature-flags/evaluate",{key:e,userId:this.userId,entityId:this.entityId,environment:this.environment});return r.success&&r.data&&ye(r.data)?(this.cache.set(e,r.data),this.persistCache(),r.data.value):null}async isEnabled(e,t=!1){let r=await this.getFlag(e);return typeof r=="boolean"?r:t}async refreshAll(){let e=await this.http.post("/feature-flags/evaluate-all",{userId:this.userId,entityId:this.entityId,environment:this.environment});if(e.success&&Array.isArray(e.data)){this.cache.clear();for(let t of e.data)ye(t)&&this.cache.set(t.key,t);this.persistCache()}}startAutoRefresh(e=6e4){this.stopAutoRefresh(),this.refreshAll(),this.refreshInterval=setInterval(()=>this.refreshAll(),e)}stopAutoRefresh(){this.refreshInterval&&clearInterval(this.refreshInterval),this.refreshInterval=null}getAllFlags(){let e={};for(let[t,r]of this.cache)e[t]=r.value;return e}reset(){this.cache.clear(),this.storage.remove("flags"),this.userId=void 0,this.entityId=void 0,this.environment=void 0}destroy(){this.stopAutoRefresh()}persistCache(){this.storage.set("flags",JSON.stringify(Array.from(this.cache.values())))}};function ye(s){if(s==null||typeof s!="object")return!1;let e=s;return Object.prototype.hasOwnProperty.call(e,"__proto__")||Object.prototype.hasOwnProperty.call(e,"constructor")?!1:typeof e.key=="string"&&"value"in e}var pt=32*1024,F=class{constructor(e,t,r){this.activeSurvey=null;this.http=t,this.storage=r}onDisplay(e){this.onSurveyDisplay=e}async showSurvey(e){if(typeof e!="string"||!/^[A-Za-z0-9_-]{6,64}$/.test(e))return null;let t=`survey_shown_${e}`;if(this.storage.get(t))return null;let r=await this.http.get(`/surveys/${encodeURIComponent(e)}/config`);return!r.success||!r.data||!ft(r.data)?null:(this.activeSurvey=r.data,this.storage.set(t,"1"),this.onSurveyDisplay&&this.onSurveyDisplay(r.data),r.data)}async submitResponse(e,t,r=!0){let n=0;try{n=JSON.stringify(t).length}catch{return!1}if(n>pt)return!1;let i=await this.http.post("/surveys/responses",{surveyId:e,answers:t,completed:r});return i.success&&(this.activeSurvey=null),i.success}dismiss(){this.activeSurvey=null}getActiveSurvey(){return this.activeSurvey}};function ft(s){if(s==null||typeof s!="object")return!1;let e=s;return typeof e.id!="string"||typeof e.name!="string"||!Array.isArray(e.questions)?!1:e.questions.every(gt)}function gt(s){if(s==null||typeof s!="object")return!1;let e=s;return typeof e.id=="string"&&typeof e.text=="string"}function R(s){if(!(!s||typeof s!="string"))try{let e=typeof window<"u"?window.location.href:"https://local/",t=new URL(s,e);return t.protocol==="http:"||t.protocol==="https:"?t.href:void 0}catch{return}}var mt=new Set(["b","i","u","em","strong","a","p","br","span","ul","ol","li","h1","h2","h3","h4"]),yt={a:new Set(["href","target","rel"])};function we(s){if(typeof DOMParser>"u")return"";let t=new DOMParser().parseFromString(`<div>${s}</div>`,"text/html").body.firstElementChild;return t?(Fe(t),t.innerHTML):""}function Fe(s){let e=Array.from(s.children);for(let t of e){let r=t.tagName.toLowerCase();if(!mt.has(r)){let i=document.createTextNode(t.textContent??"");t.replaceWith(i);continue}let n=yt[r]??new Set;for(let i of Array.from(t.attributes)){if(!n.has(i.name.toLowerCase())){t.removeAttribute(i.name);continue}if(i.name.toLowerCase()==="href"){let o=R(i.value);o?t.setAttribute("href",o):t.removeAttribute(i.name)}}r==="a"&&(t.setAttribute("rel","noopener noreferrer"),t.setAttribute("target","_blank")),Fe(t)}}var j=class{constructor(e,t,r){this.messages=[];this.pollInterval=null;this.http=t,this.storage=r}onDisplay(e){this.onMessageDisplay=e}async checkMessages(){let e=await this.http.get("/in-app-messages/active");if(!e.success||!Array.isArray(e.data))return null;this.messages=e.data.map(wt);for(let t of this.messages){let r=`iam_shown_${t.id}`;if(!this.storage.get(r))return this.storage.set(r,"1"),this.onMessageDisplay&&this.onMessageDisplay(t),t}return null}async recordAction(e,t){await this.http.post("/in-app-messages/impressions",{messageId:e,action:t})}startPolling(e=3e5){this.stopPolling(),this.checkMessages(),this.pollInterval=setInterval(()=>this.checkMessages(),e)}stopPolling(){this.pollInterval&&clearInterval(this.pollInterval),this.pollInterval=null}getMessages(){return this.messages}destroy(){this.stopPolling()}};function wt(s){return{...s,content:{...s.content,ctaUrl:R(s.content.ctaUrl),imageUrl:R(s.content.imageUrl)}}}var kt=4e3,G=class{constructor(e,t,r){this.chatbotId=null;this.messages=[];this.http=t,this.storage=r;let n=this.storage.get("chat_session_id");this.sessionId=n??_("chat_"),n||this.storage.set("chat_session_id",this.sessionId)}init(e){if(typeof e!="string"||!/^[A-Za-z0-9_-]{6,64}$/.test(e))throw new Error("[SendoraCloud] Invalid chatbotId.");this.chatbotId=e}onNewMessage(e){this.onMessage=e}async sendMessage(e,t){if(!this.chatbotId||typeof e!="string"||e.length===0||e.length>kt)return null;let r={role:"user",content:e,timestamp:new Date().toISOString()};this.messages.push(r);let n=await this.http.post("/chatbot/message",{chatbotId:this.chatbotId,sessionId:this.sessionId,message:e,userId:t});if(n.success&&n.data&&typeof n.data.reply=="string"){let i={role:"assistant",content:n.data.reply,timestamp:new Date().toISOString()};return this.messages.push(i),this.onMessage&&this.onMessage(i),i}return null}getMessages(){return[...this.messages]}newSession(){this.messages=[],this.sessionId=_("chat_"),this.storage.set("chat_session_id",this.sessionId)}getSessionId(){return this.sessionId}};var K=class{constructor(e,t){this.listeners=new Set;this.granted=e,this.http=t}isGranted(){return this.granted}grant(){this.granted||(this.granted=!0,this.emit())}revoke(){this.granted&&(this.granted=!1,this.emit())}subscribe(e){return this.listeners.add(e),()=>this.listeners.delete(e)}async record(e){if(!this.http)throw new Error("consent.record requires SDK init (HttpClient unavailable)");let t=await this.http.post("/consent/record",e);if(!t.success||!t.data)throw new Error(t.error?.message??"consent.record failed");return t.data}async requestDeletion(e){if(!this.http)throw new Error("consent.requestDeletion requires SDK init (HttpClient unavailable)");let t=await this.http.post("/consent/deletion-request",e);if(!t.success||!t.data)throw new Error(t.error?.message??"consent.requestDeletion failed");return t.data}emit(){for(let e of this.listeners)try{e(this.granted)}catch{}}};var b="auth_access_token",C="auth_access_expires",ne="auth_refresh_token",ie="auth_user",W="auth_session",D=["auth_held_0","auth_held_1","auth_held_2","auth_held_3","auth_held_4"],oe="auth_mint_key",je="schema_version";var Ke=[b,C,ne,ie,W],vt=[...Ke,...D],kr=[...vt,oe];function At(s){if(s===null)return{user:null,unreadable:!1};try{let e=JSON.parse(s);return!e||typeof e!="object"||typeof e.id!="string"||e.id.length===0?{user:null,unreadable:!0}:{user:e,unreadable:!1}}catch{return{user:null,unreadable:!0}}}function St(s){if(s===null)return{record:null,unreadable:!1};try{let e=JSON.parse(s);if(!e||typeof e!="object"||e.v!==1)return{record:null,unreadable:!0};if(!e.user||typeof e.user!="object"||typeof e.user.id!="string"||e.user.id.length===0)return{record:null,unreadable:!0};if(typeof e.refreshToken!="string"||e.refreshToken.length===0)return{record:null,unreadable:!0};let t=typeof e.accessToken=="string"&&e.accessToken.length>0?e.accessToken:null,r=typeof e.accessExpiresAt=="number"&&Number.isFinite(e.accessExpiresAt)?e.accessExpiresAt:0,n=Array.isArray(e.heldReportPending)?e.heldReportPending.filter(i=>typeof i=="string"):void 0;return{record:{v:1,user:e.user,accessToken:t,accessExpiresAt:r,refreshToken:e.refreshToken,...n&&n.length>0?{heldReportPending:n}:{}},unreadable:!1}}catch{return{record:null,unreadable:!0}}}function Ge(s){if(s===null)return{slot:null,unreadable:!1};try{let e=JSON.parse(s);return!e||typeof e!="object"||e.v!==1||typeof e.userId!="string"||e.userId.length===0||typeof e.refreshToken!="string"||e.refreshToken.length===0?{slot:null,unreadable:!0}:{slot:{v:1,userId:e.userId,sid:typeof e.sid=="string"?e.sid:"",refreshToken:e.refreshToken,tokenAtHold:typeof e.tokenAtHold=="string"?e.tokenAtHold:e.refreshToken,heldAt:typeof e.heldAt=="number"&&Number.isFinite(e.heldAt)?e.heldAt:0,project:typeof e.project=="string"?e.project:null,autoRestore:e.autoRestore!==!1},unreadable:!1}}catch{return{slot:null,unreadable:!0}}}var V=class{constructor(e){this.storage=e}readDisk(){let{record:e,unreadable:t}=St(this.storage.get(W)),{user:r,unreadable:n}=At(this.storage.get(ie)),i=this.storage.get(C),o=i?Number(i):0;return{record:e,recordUnreadable:t,legacy:{user:r,userUnreadable:n,accessToken:this.storage.get(b),accessExpiresAt:Number.isFinite(o)?o:0,refreshToken:this.storage.get(ne)}}}currentRefresh(){return this.readDisk().legacy.refreshToken}static recordTrusted(e){return!!e.record&&!!e.legacy.refreshToken&&e.record.refreshToken===e.legacy.refreshToken}writeSession(e){this.storage.set(ie,JSON.stringify(e.user)),e.accessToken?(this.storage.set(b,e.accessToken),this.storage.set(C,String(e.accessExpiresAt))):(this.storage.remove(b),this.storage.remove(C)),this.storage.set(ne,e.refreshToken),this.storage.set(W,JSON.stringify(e)),this.storage.get(je)!=="2"&&this.storage.set(je,"2")}clearRecord(){this.storage.remove(W)}writeLimboTokens(e){this.storage.set(b,e.accessToken),this.storage.set(C,String(e.accessExpiresAt)),this.storage.set(ne,e.refreshToken)}clearSession(){for(let e of Ke)this.storage.remove(e)}clearStaleBlob(){this.storage.remove(ie),this.storage.remove(b),this.storage.remove(C),this.storage.remove(W)}readSlots(){let e=[],t=[];return D.forEach((r,n)=>{let{slot:i,unreadable:o}=Ge(this.storage.get(r));e.push(i),o&&t.push(n)}),{slots:e,unreadable:t}}readSlot(e){return Ge(this.storage.get(D[e])).slot}writeSlot(e,t){let r=D[e];t===null?this.storage.remove(r):this.storage.set(r,JSON.stringify(t))}freeSlot(){let{slots:e,unreadable:t}=this.readSlots();for(let r=0;r<e.length;r++)if(e[r]===null&&!t.includes(r))return r;return null}readMintKey(){return this.storage.get(oe)}writeMintKey(e){this.storage.set(oe,e)}clearMintKey(){this.storage.remove(oe)}};var Et=["unknown","signed_out","anonymous","identified","withheld"],P=5,ke=["INVALID_REFRESH_TOKEN"],ve=["expired","revoked","evicted","deleted","reuse","unknown"],Ae=["deleted","revoked","expired"],Se="AMBIGUOUS_HELD_GUEST",It=["MINT","SIGN_IN","LINK","CLAIM","RESTORE","DISCARD","DELETE","SESSION_VERB"],$={SESSION_WITHHELD:"SESSION_WITHHELD",PROJECT_MISMATCH:"PROJECT_MISMATCH"};var We="project";function Ee(s,e){if(s===void 0)return"match";let t=S(e);if(t===null||!Object.prototype.hasOwnProperty.call(t,We))return"unknown";let r=t[We];return r===null?"mismatch":typeof r=="string"&&r===s?"match":"mismatch"}function S(s){if(typeof s!="string"||s.length===0)return null;let e=s.split(".");if(e.length!==3)return null;let t=Tt(e[1]);if(t===null)return null;let r=_t(t);if(r===null)return null;let n;try{n=JSON.parse(r)}catch{return null}return n===null||typeof n!="object"||Array.isArray(n)?null:n}var Rt=(()=>{let s=new Int16Array(128).fill(-1),e="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";for(let t=0;t<e.length;t++)s[e.charCodeAt(t)]=t;return s[45]=62,s[95]=63,s[43]=62,s[47]=63,s})();function Tt(s){let e=s.length;for(;e>0&&s.charCodeAt(e-1)===61;)e--;if(e%4===1)return null;let t=new Uint8Array(Math.floor(e*3/4)),r=0,n=0,i=0;for(let o=0;o<e;o++){let a=s.charCodeAt(o),l=a<128?Rt[a]:-1;if(l<0)return null;r=r<<6|l,n+=6,n>=8&&(n-=8,t[i++]=r>>n&255)}return i===t.length?t:t.subarray(0,i)}function _t(s){let e="",t=0,r=s.length;for(;t<r;){let n=s[t],i,o;if(n<128)i=n,o=0;else if(n>=194&&n<=223)i=n&31,o=1;else if(n>=224&&n<=239)i=n&15,o=2;else if(n>=240&&n<=244)i=n&7,o=3;else return null;if(t+o>=r)return null;for(let a=1;a<=o;a++){let l=s[t+a];if((l&192)!==128)return null;i=i<<6|l&63}if(o===2&&i<2048||o===3&&(i<65536||i>1114111)||i>=55296&&i<=57343)return null;if(i>65535){let a=i-65536;e+=String.fromCharCode(55296+(a>>10),56320+(a&1023))}else e+=String.fromCharCode(i);t+=o+1}return e}var Ve=3e4,bt=5*6e4,Ct=/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;function Ie(s){if(!s||typeof s!="object")return!1;let e=s,t=e.user,r=e.tokens;return!(!t||typeof t.id!="string"||t.id.length===0||!r||typeof r.accessToken!="string"||r.accessToken.length===0||typeof r.refreshToken!="string"||r.refreshToken.length===0||typeof r.expiresIn!="number"||r.expiresIn<=0||t.isAnonymous!==void 0&&typeof t.isAnonymous!="boolean"||t.email!==void 0&&t.email!==null&&typeof t.email!="string"||t.emailVerified!==void 0&&typeof t.emailVerified!="boolean"||t.name!==void 0&&t.name!==null&&typeof t.name!="string"||t.signupMethod!==void 0&&t.signupMethod!==null&&typeof t.signupMethod!="string"||t.lastLoginMethod!==void 0&&t.lastLoginMethod!==null&&typeof t.lastLoginMethod!="string"||t.project!==void 0&&t.project!==null&&typeof t.project!="string"||e.retiredAnonUserId!==void 0&&typeof e.retiredAnonUserId!="string")}var U=class extends Error{constructor(e="An account with this email already exists"){super(e),this.name="EmailAlreadyTakenError"}},z=class extends Error{constructor(e="Already signed in with an identity; use link*() to add a credential, or sign out first"){super(e),this.name="AlreadyIdentifiedError"}},x=class extends Error{constructor(t="This credential is already linked to a different account",r){super(t);this.code="CREDENTIAL_IN_USE";this.kind="credential_in_use";this.retryable=!1;this.name="CredentialInUseError",this.provider=r?.provider,this.collision=r?.collision,this.status=r?.status}};function Dt(s){let e=s?.error?.details;if(!e||typeof e!="object")return{};let t=e;return{provider:typeof t.provider=="string"?t.provider:void 0,collision:t.collision==="identity"||t.collision==="email"?t.collision:void 0}}function $e(s){let e=s?.error?.details;if(!e||typeof e!="object")return;let t=e.endReason;return typeof t=="string"&&ve.includes(t)?t:void 0}var Pt=new Set(["network","server","rate_limited","account_locked"]);function Lt(s,e){switch(s){case"NETWORK_ERROR":case"NETWORK_TIMEOUT":return"network";case"PARSE_ERROR":case"RESTORE_FAILED":return"server";case"RATE_LIMITED":case"RATE_LIMIT":case"RATE_LIMIT_EXCEEDED":case"QUOTA_EXCEEDED":return"rate_limited";case"ACCOUNT_LOCKED":return"account_locked";case"CREDENTIAL_IN_USE":return"credential_in_use";case"LAST_CREDENTIAL":return"last_credential";case"RECENT_AUTH_REQUIRED":return"recent_auth_required";case"NOT_ANONYMOUS":case"FORBIDDEN_NON_ANONYMOUS":return"already_identified";case"PASSKEY_USER_CANCELLED":case"GAME_CENTER_CANCELLED":case"PLAY_GAMES_CANCELLED":case"SSO_CANCELLED":case"SIGN_IN_SUPERSEDED":case"LINK_SUPERSEDED":case"CLAIM_SUPERSEDED":case"HELD_GUEST_CHANGED":return"cancelled";case"GAME_CENTER_UNAVAILABLE":case"PLAY_GAMES_UNAVAILABLE":case"ENTITLEMENT_ERROR":case"tier_required":case"SESSION_WITHHELD":case"PROJECT_MISMATCH":case"HELD_GUEST_LIMIT":case"HELD_GUEST_PROJECT_MISMATCH":case"UNSUPPORTED_LINK_CREDENTIAL":return"config";case"UNAUTHORIZED":case"INVALID_CREDENTIALS":case"INVALID_REFRESH_TOKEN":case"EMAIL_OTP_INVALID":case"MAGIC_LINK_INVALID":case"PASSKEY_RP_MISMATCH":case"NOT_SIGNED_IN":case"AMBIGUOUS_HELD_GUEST":case"HELD_GUEST_NOT_FOUND":case"HELD_GUEST_GONE":case"NOT_IDENTIFIED":case"CREDENTIAL_STALE":case"MFA_REQUIRED":return"invalid_credential";default:break}if(typeof e=="number"){if(e===429)return"rate_limited";if(e>=500)return"server";if(e>=400)return"invalid_credential"}return"unknown"}var u=class extends Error{constructor(e,t,r){super(t),this.name="AuthError",this.code=e,this.kind=r?.kind??Lt(e,r?.status),this.retryable=Pt.has(this.kind),this.retryAfterSeconds=r?.retryAfterSeconds,this.status=r?.status}},Q=class extends u{constructor(e,t=`Every held-guest slot is occupied (${5}); restore or discard one first`){super("HELD_GUEST_LIMIT",t,{kind:"config"}),this.name="HeldGuestLimitError",this.heldGuests=e}},L=class extends u{constructor(e,t,r){super("HELD_GUEST_PROJECT_MISMATCH",`Held guest ${e} belongs to project ${r??"null"}, not ${t}`,{kind:"config"}),this.name="HeldGuestProjectMismatch",this.userId=e,this.expectedProjectId=t,this.actualProjectId=r}};function Ut(s){if(s instanceof u||s instanceof U||s instanceof z||s instanceof x)return s;let e=s?.name;return e==="AbortError"||e==="TimeoutError"||e==="NetworkTimeoutError"?new u("NETWORK_TIMEOUT",s instanceof Error?s.message:"timeout",{kind:"network"}):new u("UNKNOWN_ERROR",s instanceof Error?s.message:String(s),{kind:"unknown"})}function p(s){let e=s.error?.status,t=s.error?.details?.retryAfterSeconds;return{status:typeof e=="number"?e:void 0,retryAfterSeconds:typeof t=="number"&&Number.isFinite(t)&&t>0?t:void 0}}var Y=class{constructor(e,t,r,n,i,o,a={}){this.state="unknown";this.record=null;this.user=null;this.accessToken=null;this.accessExpiresAt=0;this.withheld=null;this.clockSkewConfirmed=!1;this.inflight=Promise.resolve();this.refreshInflight=null;this.attemptInFlight=!1;this.refreshFailureCount=0;this.refreshCooldownUntil=0;this.visibilityResetUnsub=null;this.proactiveRefreshTimer=null;this.proactiveRefreshCleanup=null;this.storageEventUnsub=null;this.rehydrateScheduled=!1;this.takeoverListeners=new Set;this.lastTakeover=null;this.deletionCancelledListeners=new Set;this.lastDeletionCancelled=null;this.lastAnonRetirement=null;this.authStateListeners=new Set;this.identityWithheldListeners=new Set;this.hydrated=!1;this.http=t,this.storage=r,this.store=new V(r),this.analytics=n,this.flags=i,this.chatbot=o,this.hooks=a,this.expectedProjectId=e.expectedProjectId,this.slotProjectAnchor=e.expectedProjectId??e.projectId,this.autoRestoreHeldGuest=e.autoRestoreHeldGuest!==!1,this.hydrateFromDisk("boot"),this.hydrated=!0,this.startStorageEventRehydrate()}status(){return this.state}authStateReady(){return Promise.resolve(this.state)}getCurrentUser(){return this.user}getUserSync(){return this.user}isReady(){return this.hydrated}onDeviceTakeover(e){return this.takeoverListeners.add(e),()=>{this.takeoverListeners.delete(e)}}getLastDeviceTakeover(){return this.lastTakeover}onAuthStateChanged(e){if(this.authStateListeners.add(e),this.hydrated){let t=this.user,r={event:"initial",status:this.state,user:t,...this.withheld?{withheld:this.withheld.info}:{}};try{e(r)}catch{}if(t)try{e({event:"signed_in",user:t})}catch{}}return()=>{this.authStateListeners.delete(e)}}onIdentityWithheld(e){return this.identityWithheldListeners.add(e),()=>{this.identityWithheldListeners.delete(e)}}emitAuthState(e){for(let t of this.authStateListeners)try{t(e)}catch{}}fireDeviceTakeover(e,t){if(!e||!Ct.test(e))return;let r={retiredAnonUserId:e,identifiedUserId:t,at:new Date};this.lastTakeover=r;for(let n of this.takeoverListeners)try{n(r)}catch{}this.emitAuthState({event:"device_takeover",user:this.user,retiredAnonUserId:e})}onDeletionCancelled(e){return this.deletionCancelledListeners.add(e),()=>{this.deletionCancelledListeners.delete(e)}}getLastDeletionCancelled(){return this.lastDeletionCancelled}getLastAnonRetirement(){return this.lastAnonRetirement}fireDeletionCancelled(e){let t={userId:e,at:new Date};this.lastDeletionCancelled=t;for(let r of this.deletionCancelledListeners)try{r(t)}catch{}this.emitAuthState({event:"deletion_cancelled",user:this.user})}recordServerSignals(e){e.anonRetirement&&(this.lastAnonRetirement=e.anonRetirement),e.retiredAnonUserId&&this.fireDeviceTakeover(e.retiredAnonUserId,e.user.id),e.reactivatedFromDeletion&&this.fireDeletionCancelled(e.user.id)}commit(e){switch(e.type){case"install":return this.commitInstall(e);case"clear":return this.commitClear(e);case"user":{if(this.currentSid()!==e.expectSid||!this.record)return!1;let t={...this.record,user:e.user};return this.record=t,this.user=e.user,this.store.writeSession(t),this.analytics.identify(e.user.id),this.flags.setContext({userId:e.user.id}),this.emitAuthState({event:"user_updated",user:e.user,cause:e.cause}),!0}case"release":{let t=this.store.readSlot(e.index);return t?(this.store.writeSlot(e.index,null),this.emitAuthState({event:"guest_released",userId:t.userId,reason:e.reason,...e.endReason?{endReason:e.endReason}:{}}),!0):!1}case"slot_tokens":{let t=this.store.readSlot(e.index);return!t||t.refreshToken!==e.sent?!1:(this.store.writeSlot(e.index,{...t,refreshToken:e.refreshToken,...e.project!==void 0&&t.project===null?{project:e.project}:{}}),!0)}case"withhold":return this.commitWithhold(e);case"unknown":return this.state="unknown",this.record=null,this.user=null,this.withheld=null,this.accessToken=e.accessToken,this.accessExpiresAt=e.accessExpiresAt,this.startProactiveRefreshCron(),this.startVisibilityRefreshReset(),!0;case"held_reported":{if(!this.record?.heldReportPending?.includes(e.userId))return!1;let t=this.record.heldReportPending.filter(n=>n!==e.userId),r={...this.record};return t.length>0?r.heldReportPending=t:delete r.heldReportPending,this.record=r,this.store.writeSession(r),!0}default:return!1}}commitInstall(e){if(e.expectSid!==void 0&&this.currentSid()!==e.expectSid||e.expectRefresh!==void 0&&this.store.currentRefresh()!==e.expectRefresh)return!1;let t=this.record,r=t?.user??null,n=r?.id!==e.record.user.id,i=null,o={...e.record};if(e.hold){let a=this.store.freeSlot();if(a===null)return!1;this.store.writeSlot(a,e.hold),i=this.heldCount();let l=new Set(t?.heldReportPending??[]);l.add(e.hold.userId),o.heldReportPending=[...l]}else t?.heldReportPending&&!o.heldReportPending&&!n&&(o.heldReportPending=t.heldReportPending);switch(r&&n&&(this.analytics.reset(!1),this.flags.reset(),this.chatbot.newSession(),e.revokePrevious&&t&&!r.isAnonymous&&this.revokeFireAndForget(t.refreshToken)),this.state=o.user.isAnonymous===!1?"identified":"anonymous",this.record=o,this.user=o.user,this.accessToken=o.accessToken,this.accessExpiresAt=o.accessExpiresAt,this.withheld=null,n&&(this.clockSkewConfirmed=!1,this.lastTakeover=null,this.lastDeletionCancelled=null,this.lastAnonRetirement=null),(e.reason!=="hydrate"||e.persist!==!1)&&this.store.writeSession(o),this.analytics.identify(o.user.id),this.flags.setContext({userId:o.user.id}),this.startProactiveRefreshCron(),this.startVisibilityRefreshReset(),this.refreshFailureCount=0,this.refreshCooldownUntil=0,e.hold&&i!==null&&this.emitAuthState({event:"guest_held",userId:e.hold.userId,count:i}),e.reason){case"mint":this.emitAuthState({event:"signed_in",user:o.user,cause:"mint"});break;case"sign_in":this.emitAuthState({event:"signed_in",user:o.user,cause:"sign_in"});break;case"upgrade":this.emitAuthState({event:"signed_in",user:o.user,cause:"link"});break;case"link":this.emitAuthState({event:"user_updated",user:o.user,cause:"link"});break;case"restore":this.emitAuthState({event:"signed_in",user:o.user,cause:"restore"});break;case"claim":this.emitAuthState({event:"user_updated",user:o.user,cause:"merge"});break;case"recover":this.emitAuthState({event:"signed_in",user:o.user});break;case"rehydrate":n&&this.emitAuthState({event:"signed_in",user:o.user});break;case"refresh":r&&JSON.stringify(r)!==JSON.stringify(o.user)&&this.emitAuthState({event:"user_updated",user:o.user,cause:"refresh"});break;case"hydrate":break;default:break}return e.release&&this.commit({type:"release",index:e.release.index,reason:e.release.reason}),e.hold&&this.reportHeld(e.hold.userId,e.hold.refreshToken),!0}commitClear(e){let t=this.record?.refreshToken??this.withheld?.refreshToken??this.store.currentRefresh();if(e.expectRefresh!==void 0&&this.store.currentRefresh()!==e.expectRefresh)return!1;let r=this.state!=="signed_out";if(this.state="signed_out",this.record=null,this.user=null,this.accessToken=null,this.accessExpiresAt=0,this.withheld=null,this.clockSkewConfirmed=!1,this.lastTakeover=null,this.lastDeletionCancelled=null,this.lastAnonRetirement=null,this.store.clearSession(),e.stampNoAutoRestore){let{slots:n}=this.store.readSlots();n.forEach((i,o)=>{i&&i.autoRestore&&this.store.writeSlot(o,{...i,autoRestore:!1})})}return e.keepAnalyticsIdentity||this.analytics.reset(e.reason==="user"||e.reason==="account_deleted"),e.dropQueue&&this.analytics.dropQueue(),this.flags.reset(),this.chatbot.newSession(),this.stopProactiveRefreshCron(),this.stopVisibilityRefreshReset(),this.refreshFailureCount=0,this.refreshCooldownUntil=0,e.revoke&&t&&this.revokeFireAndForget(t),r&&this.emitAuthState(e.endReason!==void 0?{event:"signed_out",user:null,reason:e.reason,endReason:e.endReason}:{event:"signed_out",user:null,reason:e.reason}),!0}commitWithhold(e){if(e.from==="refresh"){if(!e.rotation||this.store.currentRefresh()!==e.rotation.sent)return!1;this.record?this.store.writeSession({...this.record,accessToken:e.rotation.accessToken,accessExpiresAt:e.rotation.accessExpiresAt,refreshToken:e.rotation.refreshToken}):this.store.writeLimboTokens(e.rotation)}this.state="withheld",this.record=null,this.user=null,this.accessToken=null,this.accessExpiresAt=0,this.withheld={info:e.info,refreshToken:e.rotation?.refreshToken??e.refreshToken},this.stopProactiveRefreshCron(),this.stopVisibilityRefreshReset();try{this.hooks.onIdentityWithheld?.()}catch{}for(let t of this.identityWithheldListeners)try{t()}catch{}return e.from==="refresh"&&this.emitAuthState({event:"session_withheld",reason:"project_mismatch",expectedProjectId:e.info.expectedProjectId,actualProjectId:e.info.actualProjectId,userId:e.info.userId}),!0}hydrateFromDisk(e){let t=this.store.readDisk(),r=t.legacy.refreshToken,n=V.recordTrusted(t),i=t.record!==null&&!n,o=t.legacy.user,a=n?o&&o.id===t.record.user.id?o:t.record.user:o,l=t.legacy.accessToken??(n?t.record.accessToken:null),d=t.legacy.accessToken?t.legacy.accessExpiresAt:n?t.record.accessExpiresAt:0;if(!r){if((a||i||t.legacy.userUnreadable||t.recordUnreadable)&&this.store.clearStaleBlob(),e==="boot"){this.state="signed_out";return}this.state!=="signed_out"&&this.commit({type:"clear",reason:"user",revoke:!1,dropQueue:!1,stampNoAutoRestore:!1});return}if(!a){if(e==="storage_event"&&this.record&&this.record.refreshToken===r)return;i&&this.store.clearRecord(),this.commit({type:"unknown",accessToken:l,accessExpiresAt:d});return}let h=this.judge(l);if(h==="mismatch"){this.commit({type:"withhold",from:"hydrate",info:this.withheldInfo(a,l),refreshToken:r});return}if(h==="unknown"){this.commit({type:"unknown",accessToken:l,accessExpiresAt:d});return}let g={v:1,user:a,accessToken:l,accessExpiresAt:d,refreshToken:r,...t.record?.heldReportPending?{heldReportPending:t.record.heldReportPending}:{}};if(e==="storage_event"&&this.record&&this.record.refreshToken===r&&this.record.user.id===a.id)return;let k=!n||JSON.stringify(t.record.user)!==JSON.stringify(a)||t.record.accessToken!==l;if(this.commit({type:"install",reason:e==="boot"?"hydrate":"rehydrate",record:g,persist:k}),e==="boot"){let{slots:v}=this.store.readSlots();v.forEach((m,y)=>{m&&m.userId===a.id&&this.store.writeSlot(y,null)});for(let m of g.heldReportPending??[]){let y=this.store.readSlots().slots.find(N=>N?.userId===m);y?this.reportHeld(m,y.refreshToken):this.commit({type:"held_reported",userId:m})}}}startStorageEventRehydrate(){if(typeof window>"u"||typeof window.addEventListener!="function"||!this.storage.isPersistent())return;let e=t=>{let r=t.key===null?null:this.storage.relativeKey(t.key);t.key!==null&&(r===null||!r.startsWith("auth_"))||this.rehydrateScheduled||(this.rehydrateScheduled=!0,setTimeout(()=>{this.rehydrateScheduled=!1,this.hydrateFromDisk("storage_event")},0))};window.addEventListener("storage",e),this.storageEventUnsub=()=>window.removeEventListener("storage",e)}stopStorageEventRehydrate(){this.storageEventUnsub&&(this.storageEventUnsub(),this.storageEventUnsub=null)}currentSid(){let e=this.record?.accessToken;if(!e)return null;let t=S(e)?.sid;return typeof t=="string"?t:null}judge(e){return Ee(this.expectedProjectId,e)}projectClaim(e){let t=S(e)?.project;return typeof t=="string"?t:null}withheldInfo(e,t){return{reason:"project_mismatch",expectedProjectId:this.expectedProjectId??"",actualProjectId:this.projectClaim(t),userId:e.id,isAnonymous:e.isAnonymous!==!1}}heldCount(){return this.store.readSlots().slots.filter(e=>e!==null).length}buildHeld(e){let t=S(e.accessToken)?.sid;return{v:1,userId:e.user.id,sid:typeof t=="string"?t:"",refreshToken:e.refreshToken,tokenAtHold:e.refreshToken,heldAt:Math.max(Date.now(),...this.store.readSlots().slots.map(r=>r?r.heldAt+1:0)),project:this.projectClaim(e.accessToken),autoRestore:!0}}revokeFireAndForget(e){this.http.post("/auth-service/token/revoke",{refreshToken:e}).catch(()=>{})}reportHeld(e,t){this.http.post("/auth-service/guest/held",{refreshToken:t}).then(r=>{r.success&&this.commit({type:"held_reported",userId:e})}).catch(()=>{})}withheldError(){return new u($.SESSION_WITHHELD,"The stored session belongs to a different project and is withheld; call discardWithheld() or re-init with the matching expectedProjectId",{kind:"config"})}canServeToken(e,t,r){return!e||!t||r>=t-Ve?!1:this.clockSkewConfirmed?!0:Xe(e,r)}canServeCachedToken(e){return this.canServeToken(this.accessToken,this.accessExpiresAt,e)}trackedDeadlineAlive(e){return!!this.accessToken&&!!this.accessExpiresAt&&e<this.accessExpiresAt-Ve}deadlinesDisagree(e){return this.trackedDeadlineAlive(e)&&!this.canServeCachedToken(e)}learnClockSkewFrom(e,t){Xe(e,t)||(this.clockSkewConfirmed=!0)}async refreshAndReconcile(e){let t=this.deadlinesDisagree(e),r=await this.refreshAccessToken();return t&&r&&this.learnClockSkewFrom(r,Date.now()),r}async getAccessToken(e){return this.state==="withheld"?null:!e?.forceRefresh&&this.state!=="unknown"&&this.canServeCachedToken(Date.now())?this.accessToken:this.store.currentRefresh()?this.refreshInflight?this.refreshInflight:Date.now()<this.refreshCooldownUntil?null:this.refreshAndReconcile(Date.now()):null}getAccessTokenSync(){return this.accessToken}getRefreshToken(){return this.state==="withheld"?null:this.store.currentRefresh()}async refreshAccessToken(){if(this.refreshInflight)return this.refreshInflight;let e=this.store.currentRefresh();return e?(this.refreshInflight=(async()=>{try{return await this.performRefresh(e)}finally{this.refreshInflight=null}})(),this.refreshInflight):null}async performRefresh(e){try{let t=await this.http.post("/auth-service/token/refresh",{refreshToken:e});if(!t.success)return qe(t.error?.code)?(this.store.currentRefresh()===e&&this.commit({type:"clear",reason:"session_expired",endReason:$e(t),expectRefresh:e,revoke:!1,dropQueue:!1,stampNoAutoRestore:!1}),this.refreshFailureCount=0,this.refreshCooldownUntil=0,null):(this.armBackoff(),null);let r=q(t.data);if(!r)return this.armBackoff(),null;if(this.store.currentRefresh()!==e)return null;let n=Date.now()+r.expiresIn*1e3,i=this.judge(r.accessToken);if(i==="mismatch"){let a=this.record?.user??ae(t.data);return this.commit({type:"withhold",from:"refresh",info:this.withheldInfo(a??{id:Ye(r.accessToken)??"",email:null,emailVerified:!1,name:null,isAnonymous:!0},r.accessToken),refreshToken:r.refreshToken,rotation:{sent:e,accessToken:r.accessToken,refreshToken:r.refreshToken,accessExpiresAt:n}}),null}let o=ae(t.data);return this.record?this.commit({type:"install",reason:"refresh",record:{...this.record,user:o??this.record.user,accessToken:r.accessToken,accessExpiresAt:n,refreshToken:r.refreshToken},expectRefresh:e}):i==="match"&&o?this.commit({type:"install",reason:"recover",record:{v:1,user:o,accessToken:r.accessToken,accessExpiresAt:n,refreshToken:r.refreshToken},expectRefresh:e}):(this.store.writeLimboTokens({accessToken:r.accessToken,refreshToken:r.refreshToken,accessExpiresAt:n}),this.accessToken=r.accessToken,this.accessExpiresAt=n),this.refreshFailureCount=0,this.refreshCooldownUntil=0,r.accessToken}catch{return this.armBackoff(),null}}async refreshHeld(e,t){let r=t.refreshToken,n=await this.http.post("/auth-service/token/refresh",{refreshToken:r});if(!n.success){if(qe(n.error?.code)){let a=$e(n);if(a&&Ae.includes(a))return this.commit({type:"release",index:e,reason:"dead",endReason:a}),{kind:"dead",endReason:a};throw new u("RESTORE_FAILED",`The held guest's token was refused${a?` (${a})`:" with no end reason"}; the slot is kept \u2014 retry later`,{status:p(n).status,kind:"server"})}throw new u(n.error?.code??"RESTORE_FAILED",n.error?.message??"Could not refresh the held guest",p(n))}let i=q(n.data);if(!i)throw new u("RESTORE_FAILED","Malformed refresh response for the held guest; the slot is kept",{kind:"server"});if(!this.commit({type:"slot_tokens",index:e,sent:r,refreshToken:i.refreshToken,...t.project===null?{project:this.projectClaim(i.accessToken)}:{}}))throw new u("HELD_GUEST_CHANGED","The held slot changed while its token was in flight",{kind:"cancelled"});return{kind:"ok",tokens:i,user:ae(n.data)}}async settle(){for(;this.state==="unknown";){if(!this.store.currentRefresh()){this.commit({type:"clear",reason:"user",revoke:!1,dropQueue:!1,stampNoAutoRestore:!1});return}if(await this.refreshAccessToken(),this.state!=="unknown")return;let e=Math.min(3e4,Math.max(250,this.refreshCooldownUntil-Date.now()));await new Promise(t=>setTimeout(t,e))}}armBackoff(){this.refreshFailureCount+=1;let e=Math.min(3e4,1e3*Math.pow(2,this.refreshFailureCount-1));this.refreshCooldownUntil=Date.now()+e}resetRefreshState(){this.refreshFailureCount=0,this.refreshCooldownUntil=0}startVisibilityRefreshReset(){if(this.visibilityResetUnsub||typeof document>"u")return;let e=()=>{document.visibilityState==="visible"&&this.resetRefreshState()};document.addEventListener("visibilitychange",e),this.visibilityResetUnsub=()=>document.removeEventListener("visibilitychange",e)}stopVisibilityRefreshReset(){this.visibilityResetUnsub&&(this.visibilityResetUnsub(),this.visibilityResetUnsub=null)}startProactiveRefreshCron(){if(typeof window>"u"||this.proactiveRefreshTimer)return;let e=.8,t=6e4,r=3e4,n=async()=>{if(this.attemptInFlight||this.state==="withheld")return;if(this.state==="unknown"){Date.now()>=this.refreshCooldownUntil&&await this.refreshAccessToken();return}if(!this.accessToken||!this.accessExpiresAt)return;let o=Date.now();if(!this.canServeCachedToken(o)){await this.refreshAndReconcile(o);return}let a=this.accessExpiresAt-o;if(a<=0)return;let d=Math.max(a,5*6e4)*(1-e)+(Math.random()*r*2-r);a<=d&&await this.refreshAccessToken()};this.proactiveRefreshTimer=window.setInterval(()=>{n()},t);let i=()=>{typeof document<"u"&&document.visibilityState==="visible"&&n()};typeof document<"u"&&document.addEventListener("visibilitychange",i),this.proactiveRefreshCleanup=()=>{this.proactiveRefreshTimer&&(window.clearInterval(this.proactiveRefreshTimer),this.proactiveRefreshTimer=null),typeof document<"u"&&document.removeEventListener("visibilitychange",i)}}stopProactiveRefreshCron(){this.proactiveRefreshCleanup&&(this.proactiveRefreshCleanup(),this.proactiveRefreshCleanup=null)}serialize(e){let t=async()=>{try{return await e()}catch(n){throw Ut(n)}},r=this.inflight.then(t,t);return this.inflight=r.catch(()=>{}),r}async bearerHeaders(){if(this.state==="withheld")throw this.withheldError();let e=await this.getAccessToken();if(!e)throw new u("NOT_SIGNED_IN","Not signed in");return{Authorization:`Bearer ${e}`}}signInAnonymously(e){return this.serialize(async()=>{if(this.state==="withheld")throw this.withheldError();if(this.state==="unknown"&&await this.settle(),this.status()==="withheld")throw this.withheldError();let{slots:t}=this.store.readSlots(),r=t.filter(l=>l!==null),n=this.record;if(n&&!e?.forceNew)return n.user;let i=r.length+(n&&n.user.isAnonymous?1:0);if(e?.forceNew){if(i>=5)throw new Q(r.length);return this.mintFresh(e,n)}let o=r.map(l=>({slot:l,index:t.indexOf(l)})).filter(({slot:l})=>l.autoRestore&&!this.slotProjectMismatches(l)).sort((l,d)=>d.slot.heldAt-l.slot.heldAt);if(o.length>0&&(this.autoRestoreHeldGuest||i>=5))for(let{slot:l,index:d}of o)try{let h=await this.restoreSlot(d,l,"mint");if(h)return h}catch(h){if(h instanceof L)continue;throw h}let a=this.heldCount();if(a>=5)throw new Q(a);return this.mintFresh(e,null)})}ensureSession(){return this.signInAnonymously()}slotProjectMismatches(e){let t=this.slotProjectAnchor;return t!==void 0&&e.project!==null&&e.project!==t}async mintFresh(e,t){let r=this.currentSid(),n=this.store.readMintKey()??xt();this.store.writeMintKey(n),this.attemptInFlight=!0;try{await this.refreshInflight;let i=await this.http.post("/auth-service/anonymous",{name:e?.name,metadata:e?.metadata,mintKey:n});if(!i.success||!Ie(i.data))throw new u(i.error?.code??"AUTH_ERROR",i.error?.message??"Anonymous signup failed",p(i));let o=i.data;this.guardMinted(o),await this.refreshInflight;let a=this.record,l=a&&a.user.isAnonymous&&t?this.buildHeld(a):void 0;if(!this.commit({type:"install",reason:"mint",record:Re(o),expectSid:r,hold:l,revokePrevious:!!a&&!a.user.isAnonymous}))throw this.revokeFireAndForget(o.tokens.refreshToken),new u("SIGN_IN_SUPERSEDED","The session changed while the mint was in flight; nothing was installed",{kind:"cancelled"});return this.store.clearMintKey(),this.recordServerSignals(o),o.user}finally{this.attemptInFlight=!1}}guardMinted(e){if(this.judge(e.tokens.accessToken)!=="match")throw this.revokeFireAndForget(e.tokens.refreshToken),new u($.PROJECT_MISMATCH,`The server answered for project ${this.projectClaim(e.tokens.accessToken)??"null"}, not expectedProjectId ${this.expectedProjectId??""}; nothing was installed`,{kind:"config"})}async performSwitch(e,t,r){if(this.state==="withheld")throw this.withheldError();if(this.state==="unknown"&&await this.settle(),this.status()==="withheld")throw this.withheldError();let n=this.currentSid();this.attemptInFlight=!0;try{await this.refreshInflight;let i=await e();if(!i.success||!i.data)throw new u(i.error?.code??t,i.error?.message??r,p(i));let o=i.data;if(o.mfaRequired===!0&&typeof o.mfaChallengeToken=="string"){let g=o.user;return{kind:"mfa",challengeToken:o.mfaChallengeToken,userId:g?.id??""}}if(!Ie(i.data))throw new u(i.error?.code??t,i.error?.message??r,p(i));let a=i.data;this.guardMinted(a),this.record&&await this.analytics.flush().catch(()=>{}),await this.refreshInflight;let l=this.record,d=l&&l.user.isAnonymous&&l.user.id!==a.user.id?this.buildHeld(l):void 0;if(!this.commit({type:"install",reason:"sign_in",record:Re(a),expectSid:n,hold:d,revokePrevious:!!l&&!l.user.isAnonymous&&l.user.id!==a.user.id}))throw this.revokeFireAndForget(a.tokens.refreshToken),new u("SIGN_IN_SUPERSEDED","The session changed while the sign-in was in flight; nothing was installed",{kind:"cancelled"});return this.recordServerSignals(a),{kind:"done",user:a.user,previous:l?{userId:l.user.id,isAnonymous:l.user.isAnonymous!==!1,held:!!d}:null,reactivated:a.reactivatedFromDeletion===!0}}finally{this.attemptInFlight=!1}}signIn(e,t){return this.serialize(async()=>{let r=await this.performSwitch(()=>this.http.post("/auth-service/login",{email:e,password:t}),"AUTH_ERROR","Login failed");return r.kind==="mfa"?{mfaRequired:!0,mfaChallengeToken:r.challengeToken,userId:r.userId}:r.user})}challengeMfa(e,t){return this.serialize(async()=>{let r=await this.performSwitch(()=>this.http.post("/auth-service/mfa/challenge",{challengeToken:e,code:t}),"MFA_CHALLENGE_FAILED","Invalid MFA code");if(r.kind==="mfa")throw new u("MFA_CHALLENGE_FAILED","MFA challenge returned another challenge");return r.user})}loginSocial(e){return this.serialize(async()=>{let{link:t,onCredentialInUse:r,...n}=e,i=n,o=()=>this.performSwitch(()=>this.http.post("/auth-service/login/social",i),"SOCIAL_LOGIN_FAILED","Social login failed");if(t){if(this.state==="withheld")throw this.withheldError();if(this.state==="unknown"&&await this.settle(),this.state==="anonymous"||this.state==="identified"){let l=await this.performLink("/auth-service/me/link/social",i,"upgrade");if(l.kind==="done")return l.user;if(l.kind==="recent_auth_required")throw new u("RECENT_AUTH_REQUIRED",l.message??"Re-authenticate to link this credential",{status:l.status??403});if(r==="adopt"){let d=await o();if(d.kind==="mfa")throw new u("MFA_REQUIRED","This account requires MFA; use signIn()/challengeMfa()");return d.user}throw new x(l.message,{provider:l.provider,collision:l.collision,status:l.status})}}let a=await o();if(a.kind==="mfa")throw new u("MFA_REQUIRED","This account requires MFA; use signIn()/challengeMfa()");return a.user})}signInWithGoogle(e,t,r){return this.loginSocial({provider:"google",code:e,redirectUri:t,link:r})}signInWithGitHub(e,t){return this.loginSocial({provider:"github",code:e,redirectUri:t})}signInWithApple(e){return this.loginSocial({provider:"apple",...e})}signInWithMicrosoft(e,t){return this.loginSocial({provider:"microsoft",code:e,redirectUri:t})}signInWithLinkedIn(e,t){return this.loginSocial({provider:"linkedin",code:e,redirectUri:t})}signInWithFacebook(e,t){return this.loginSocial({provider:"facebook",code:e,redirectUri:t})}signInWithDiscord(e,t){return this.loginSocial({provider:"discord",code:e,redirectUri:t})}signInWith(e){return this.serialize(async()=>{let{path:t,body:r}=Be(e),n=await this.performSwitch(()=>this.http.post(t,r),"AUTH_ERROR","Sign-in failed");if(n.kind==="mfa"){let i=n.challengeToken;return{status:"mfa_required",challengeToken:i,verify:o=>this.signInWith({kind:"mfa",challengeToken:i,code:o})}}return{status:"done",user:n.user,previous:n.previous,reactivated:n.reactivated}})}async performLink(e,t,r){if(this.state==="withheld")throw this.withheldError();let n=this.currentSid();this.attemptInFlight=!0;try{await this.refreshInflight;let i=await this.bearerHeaders(),o=await this.http.post(e,t,i);if(!o.success||!o.data?.user){let d=o.error?.code??"LINK_FAILED",h=p(o);if(d==="CREDENTIAL_IN_USE"){let g=Dt(o);return{kind:"credential_in_use",provider:g.provider??"",collision:g.collision??"identity",status:h.status,message:o.error?.message}}if(d==="RECENT_AUTH_REQUIRED")return{kind:"recent_auth_required",status:h.status,message:o.error?.message};throw new u(d,o.error?.message??"Failed to link credential",h)}let a=o.data,l=o.data.user;if(a.upgraded&&Ie(a)){if(this.guardMinted(a),await this.refreshInflight,!this.commit({type:"install",reason:r,record:Re(a),expectSid:n}))throw this.revokeFireAndForget(a.tokens.refreshToken),new u("LINK_SUPERSEDED","The session changed while the link was in flight; nothing was installed",{kind:"cancelled"});return{kind:"done",user:a.user,upgraded:!0,alreadyLinked:!1}}return a.alreadyLinked?{kind:"done",user:l,upgraded:!1,alreadyLinked:!0}:(this.commit({type:"user",user:l,cause:"link",expectSid:n}),{kind:"done",user:l,upgraded:!1,alreadyLinked:!1})}finally{this.attemptInFlight=!1}}link(e){return this.serialize(async()=>{if(this.state==="withheld")throw this.withheldError();if(this.state==="unknown"&&await this.settle(),this.status()==="withheld")throw this.withheldError();if(this.state==="signed_out"){let i=await this.signInWithUnserialized(e);if(i.status!=="done")throw new u("MFA_REQUIRED","This account requires MFA; use signInWith() and complete the challenge");return{status:"done",user:i.user,upgraded:!1,alreadyLinked:!1}}let t=ze(e),r=await this.performLink(t.path,t.body,"link");if(r.kind==="done")return{status:"done",user:r.user,upgraded:r.upgraded,alreadyLinked:r.alreadyLinked};if(r.kind==="recent_auth_required")return{status:"recent_auth_required"};let n=Date.now();return{status:"credential_in_use",provider:r.provider,collision:r.collision,switchAccount:()=>Date.now()-n>bt?Promise.reject(new u("CREDENTIAL_STALE","The refused credential is older than 5 minutes; obtain it again and call signInWith()")):this.signInWith(e),keepCurrent:()=>{}}})}async signInWithUnserialized(e){let{path:t,body:r}=Be(e),n=await this.performSwitch(()=>this.http.post(t,r),"AUTH_ERROR","Sign-in failed");if(n.kind==="mfa"){let i=n.challengeToken;return{status:"mfa_required",challengeToken:i,verify:o=>this.signInWith({kind:"mfa",challengeToken:i,code:o})}}return{status:"done",user:n.user,previous:n.previous,reactivated:n.reactivated}}signUp(e,t,r){return this.serialize(async()=>{if(this.state==="withheld")throw this.withheldError();if(this.state==="unknown"&&await this.settle(),this.status()==="withheld")throw this.withheldError();if(this.state==="identified")throw new z;if(this.state==="anonymous"){let i=await this.performLink("/auth-service/me/link/email",{email:e,password:t},"upgrade");if(i.kind==="done")return i.user;throw i.kind==="credential_in_use"?new U(i.message):new u("RECENT_AUTH_REQUIRED",i.message??"Re-authenticate first",{status:i.status??403})}let n=await this.performSwitch(async()=>{let i=await this.http.post("/auth-service/signup",{email:e,password:t,name:r?.name,metadata:r?.metadata});if(!i.success&&i.error?.code==="CONFLICT")throw new U(i.error.message);return i},"AUTH_ERROR","Signup failed");if(n.kind==="mfa")throw new u("MFA_REQUIRED","Unexpected MFA challenge on signup");return n.user})}linkEmailPassword(e,t){return this.linkLegacy({kind:"password",email:e,password:t})}linkSocial(e){let{provider:t,...r}=e;return this.linkLegacy({kind:t,...r})}linkGoogle(e){return this.linkSocial({provider:"google",...e})}linkApple(e){return this.linkSocial({provider:"apple",...e})}linkLegacy(e){return this.serialize(async()=>{if(this.state==="withheld")throw this.withheldError();if(this.state==="unknown"&&await this.settle(),this.status()==="withheld")throw this.withheldError();if(this.state==="signed_out")throw new u("NOT_SIGNED_IN","Sign in before linking a credential");let t=ze(e),r=await this.performLink(t.path,t.body,"link");if(r.kind==="done")return r.user;throw r.kind==="recent_auth_required"?new u("RECENT_AUTH_REQUIRED",r.message??"Re-authenticate to link this credential",{status:r.status??403}):new x(r.message,{provider:r.provider,collision:r.collision,status:r.status})})}getHeldGuests(){return this.store.readSlots().slots.filter(e=>e!==null).sort((e,t)=>t.heldAt-e.heldAt).map(({userId:e,heldAt:t,autoRestore:r,project:n})=>({userId:e,heldAt:t,autoRestore:r,project:n}))}getHeldGuest(){return this.getHeldGuests()[0]??null}resolveSlot(e){let{slots:t}=this.store.readSlots(),r=t.map((n,i)=>n?{slot:n,index:i}:null).filter(n=>n!==null);if(r.length===0)throw new u("HELD_GUEST_NOT_FOUND","No guest is held on this device");if(e!==void 0){let n=r.find(i=>i.slot.userId===e);if(!n)throw new u("HELD_GUEST_NOT_FOUND",`No held guest with id ${e}`);return n}if(r.length>1)throw new u(Se,`${r.length} guests are held; pass the userId of the one you mean`);return r[0]}claimHeldGuest(e){return this.serialize(async()=>{if(this.state==="withheld")throw this.withheldError();if(this.state!=="identified"||!this.record)throw new u("NOT_IDENTIFIED","claimHeldGuest() needs a signed-in identified account as the merge target");let{index:t,slot:r}=this.resolveSlot(e),n=this.currentSid();this.attemptInFlight=!0;try{await this.refreshInflight;let i=await this.refreshHeld(t,r);if(i.kind==="dead")throw new u("HELD_GUEST_GONE",`Held guest ${r.userId} is no longer available (${i.endReason})`);let o=this.store.currentRefresh();if(!o)throw new u("NOT_SIGNED_IN","Not signed in");let a=await this.http.post("/auth-service/merge",{anonymousRefreshToken:i.tokens.refreshToken,targetRefreshToken:o});if(!a.success||!a.data)throw new u(a.error?.code??"MERGE_FAILED",a.error?.message??"Merge failed",p(a));let l=q(a.data),d=Qe(a.data,this.record.user.id,r.userId);await this.refreshInflight;let h=this.record;if(!l||!h)throw this.commit({type:"release",index:t,reason:"claimed"}),new u("MERGE_FAILED","Merge succeeded but returned no rotated session; sign in again",{kind:"server"});if(!this.commit({type:"install",reason:"claim",record:{...h,accessToken:l.accessToken,accessExpiresAt:Date.now()+l.expiresIn*1e3,refreshToken:l.refreshToken},expectSid:n,expectRefresh:o,release:{index:t,reason:"claimed"}}))throw this.commit({type:"release",index:t,reason:"claimed"}),new u("CLAIM_SUPERSEDED","The session changed while the claim was in flight",{kind:"cancelled"});return{user:this.record.user,stats:d}}finally{this.attemptInFlight=!1}})}restoreHeldGuest(e){return this.serialize(async()=>{if(this.state==="withheld")throw this.withheldError();if(this.state==="unknown"&&await this.settle(),this.status()==="withheld")throw this.withheldError();let{index:t,slot:r}=this.resolveSlot(e),n=await this.restoreSlot(t,r,"verb");if(!n)throw new u("HELD_GUEST_GONE",`Held guest ${r.userId} is no longer available`);return n})}async restoreSlot(e,t,r){let n=this.slotProjectAnchor;if(n!==void 0&&t.project!==null&&t.project!==n)throw new L(t.userId,n,t.project);let i=this.currentSid();this.attemptInFlight=!0;try{await this.refreshInflight;let o=await this.refreshHeld(e,t);if(o.kind==="dead")return null;if(this.judge(o.tokens.accessToken)!=="match")throw new L(t.userId,this.expectedProjectId??n??"",this.projectClaim(o.tokens.accessToken));let l=o.user??Je(o.tokens.accessToken,t.userId);await this.refreshInflight;let d=this.record,h=d&&d.user.isAnonymous&&d.user.id!==l.id?this.buildHeld(d):void 0;if(!this.commit({type:"install",reason:"restore",record:{v:1,user:l,accessToken:o.tokens.accessToken,accessExpiresAt:Date.now()+o.tokens.expiresIn*1e3,refreshToken:o.tokens.refreshToken},expectSid:i,hold:h,release:{index:e,reason:"restored"},revokePrevious:!!d&&!d.user.isAnonymous}))throw new u("SIGN_IN_SUPERSEDED",`The session changed while restoring${r==="mint"?" (auto-restore)":""}; nothing was installed`,{kind:"cancelled"});return l}finally{this.attemptInFlight=!1}}discardHeldGuest(e){return this.serialize(async()=>{if(this.state==="withheld")throw this.withheldError();let{index:t,slot:r}=this.resolveSlot(e);await this.discardSlot(t,r)})}async discardSlot(e,t){let r=await this.http.post("/auth-service/guest/discard",{refreshToken:t.refreshToken}),n=r.error?.status;if(r.success||n===404||r.error?.code==="NOT_FOUND"){this.commit({type:"release",index:e,reason:"discarded"});return}throw new u(r.error?.code??"GUEST_DISCARD_FAILED",r.error?.message??"Could not discard the held guest",p(r))}merge(e){let{slots:t}=this.store.readSlots(),r=t.find(n=>n!==null&&(n.refreshToken===e||n.tokenAtHold===e));return r?this.claimHeldGuest(r.userId).then(n=>n.stats):this.serialize(async()=>{if(this.state==="withheld")throw this.withheldError();if(this.state!=="identified"||!this.record)throw new u("NOT_IDENTIFIED","merge() needs a signed-in identified account as the target");let n=this.currentSid(),i=this.store.currentRefresh();if(!i)throw new u("NOT_SIGNED_IN","Not signed in");let o=await this.http.post("/auth-service/merge",{anonymousRefreshToken:e,targetRefreshToken:i});if(!o.success||!o.data)throw new u(o.error?.code??"MERGE_FAILED",o.error?.message??"Merge failed",p(o));let a=q(o.data),l=Qe(o.data,this.record.user.id,"");await this.refreshInflight;let d=this.record;return a&&d&&this.commit({type:"install",reason:"claim",record:{...d,accessToken:a.accessToken,accessExpiresAt:Date.now()+a.expiresIn*1e3,refreshToken:a.refreshToken},expectSid:n,expectRefresh:i}),l})}getWithheld(){return this.withheld?.info??null}discardWithheld(){return this.serialize(async()=>this.discardWithheldNow())}discardWithheldNow(){return this.state!=="withheld"||!this.withheld?!1:this.commit({type:"clear",reason:"user",expectRefresh:this.withheld.refreshToken,revoke:!0,dropQueue:!1,stampNoAutoRestore:!1,keepAnalyticsIdentity:!0})?!0:(this.hydrateFromDisk("storage_event"),!1)}signOut(){return this.serialize(async()=>{if(this.state==="withheld"){this.discardWithheldNow();return}if(this.state==="signed_out"){this.analytics.reset(!0),this.flags.reset(),this.chatbot.newSession();return}this.commit({type:"clear",reason:"user",revoke:!0,dropQueue:!1,stampNoAutoRestore:!1})})}deleteAccount(e){return this.serialize(async()=>{if(this.state==="withheld")throw this.withheldError();if(this.state==="unknown"&&await this.settle(),this.status()==="withheld")throw this.withheldError();if(this.state==="signed_out")throw new u("NOT_SIGNED_IN","Sign in before deleting your account");let t=await this.bearerHeaders(),r=await this.http.delete("/auth-service/me",t);if(!r.success)throw new u(r.error?.code??"DELETE_ACCOUNT_FAILED",r.error?.message??"Account deletion failed",p(r));let n=r.data??{};this.commit({type:"clear",reason:"account_deleted",revoke:!1,dropQueue:!0,stampNoAutoRestore:!0});let i={status:n.status==="purged"?"purged":"pending",scheduledPurgeAt:n.scheduledPurgeAt??null,graceDays:typeof n.graceDays=="number"?n.graceDays:0,heldGuests:this.heldCount()};if(e?.alsoDiscardHeldGuests){let o=[],{slots:a}=this.store.readSlots();for(let l=0;l<a.length;l++){let d=a[l];if(d)try{await this.discardSlot(l,d)}catch{o.push(d.userId)}}i.heldGuests=this.heldCount(),i.discardFailed=o}return i})}async listLinkedIdentities(){let e=await this.bearerHeaders().catch(()=>{throw new u("NOT_SIGNED_IN","Sign in before listing linked identities")}),t=await this.http.get("/auth-service/me/identities",e);if(!t.success||!t.data)throw new u(t.error?.code??"IDENTITIES_FAILED",t.error?.message??"Failed to list linked identities",p(t));return{identities:t.data.identities??[],hasPassword:!!t.data.hasPassword}}async unlink(e){let t=await this.bearerHeaders().catch(()=>{throw new u("NOT_SIGNED_IN","Sign in before unlinking an identity")}),r=await this.http.delete(`/auth-service/me/identities/${encodeURIComponent(e)}`,t);if(!r.success||!r.data)throw new u(r.error?.code??"UNLINK_FAILED",r.error?.message??"Failed to unlink identity",p(r));return{provider:r.data.provider??e,removed:Number(r.data.removed??0),remaining:Number(r.data.remaining??0)}}async sendMagicLink(e){let t=await this.http.post("/auth-service/magic-link/request",{email:e});if(!t.success)throw new u(t.error?.code??"MAGIC_LINK_REQUEST_FAILED",t.error?.message??"Failed to send link")}async sendEmailOtp(e){let t=await this.http.post("/auth-service/email-otp/request",{email:e});if(!t.success)throw new u(t.error?.code??"EMAIL_OTP_REQUEST_FAILED",t.error?.message??"Failed to send code")}verifyEmailOtp(e,t){return this.serialize(async()=>{let r=await this.performSwitch(()=>this.http.post("/auth-service/email-otp/verify",{email:e,code:t}),"EMAIL_OTP_INVALID","Wrong or expired code");if(r.kind==="mfa")throw new u("MFA_REQUIRED","This account requires MFA; use signIn()/challengeMfa()");return r.user})}verifyMagicLink(e){return this.serialize(async()=>{let t=await this.performSwitch(()=>this.http.post("/auth-service/magic-link/verify",{token:e}),"MAGIC_LINK_INVALID","Invalid or expired magic link");if(t.kind==="mfa")throw new u("MFA_REQUIRED","This account requires MFA; use signIn()/challengeMfa()");return t.user})}async requestPasswordReset(e){let t=await this.http.post("/auth-service/password/forgot",{email:e});if(!t.success)throw new u(t.error?.code??"PASSWORD_RESET_REQUEST_FAILED",t.error?.message??"Failed to send reset email")}async resetPassword(e,t){let r=await this.http.post("/auth-service/password/reset",{token:e,newPassword:t});if(!r.success)throw new u(r.error?.code??"PASSWORD_RESET_FAILED",r.error?.message??"Reset failed")}async verifyEmail(e){let t=await this.http.post("/auth-service/email/verify",{token:e});if(!t.success)throw new u(t.error?.code??"EMAIL_VERIFICATION_FAILED",t.error?.message??"Verification failed")}async sendVerificationEmail(){let e=await this.bearerHeaders().catch(r=>{throw r instanceof u&&r.code===$.SESSION_WITHHELD?r:new u("UNAUTHORIZED","Sign in before requesting a verification email")}),t=await this.http.post("/auth-service/email/verify/resend",{},e);if(!t.success)throw new u(t.error?.code??"VERIFICATION_RESEND_FAILED",t.error?.message??"Failed to send verification email")}async enrollMfa(){let e=await this.http.post("/auth-service/mfa/enroll/start",{},await this.bearerHeaders());if(!e.success||!e.data)throw new u(e.error?.code??"MFA_ENROLL_FAILED",e.error?.message??"MFA enrollment failed");return e.data}async confirmMfa(e){let t=await this.http.post("/auth-service/mfa/enroll/confirm",{code:e},await this.bearerHeaders());return!!(t.success&&t.data?.confirmed)}async disableMfa(){let e=await this.http.post("/auth-service/mfa/disable",{},await this.bearerHeaders());if(!e.success)throw new u(e.error?.code??"MFA_DISABLE_FAILED",e.error?.message??"Failed to disable MFA",p(e))}async registerPasskey(e){if(typeof navigator>"u"||!navigator.credentials)throw new u("PASSKEY_UNSUPPORTED","WebAuthn not supported in this environment");let t=await this.http.post("/auth-service/passkeys/register/start",{},await this.bearerHeaders());if(!t.success||!t.data)throw new u(t.error?.code??"PASSKEY_START_FAILED",t.error?.message??"Passkey start failed");let r=Nt(t.data),n;try{let a=await navigator.credentials.create({publicKey:r});if(!a)throw new Error("create returned null");n=a}catch(a){throw new u("PASSKEY_USER_CANCELLED",a instanceof Error?a.message:"User cancelled passkey registration")}let i=Ht(n),o=await this.http.post("/auth-service/passkeys/register/finish",{response:i,name:e},await this.bearerHeaders());if(!o.success||!o.data)throw new u(o.error?.code??"PASSKEY_FINISH_FAILED",o.error?.message??"Passkey verification failed");return o.data}signInWithPasskey(e){return this.serialize(async()=>{if(typeof navigator>"u"||!navigator.credentials)throw new u("PASSKEY_UNSUPPORTED","WebAuthn not supported in this environment");if(this.state==="withheld")throw this.withheldError();let t=await this.http.post("/auth-service/passkeys/authenticate/start",{userId:e??null});if(!t.success||!t.data)throw new u(t.error?.code??"PASSKEY_START_FAILED",t.error?.message??"Passkey start failed",p(t));let r=Ot(t.data),n;try{let a=await navigator.credentials.get({publicKey:r});if(!a)throw new Error("get returned null");n=a}catch(a){throw new u("PASSKEY_USER_CANCELLED",a instanceof Error?a.message:"User cancelled passkey signin")}let i=Mt(n),o=await this.performSwitch(()=>this.http.post("/auth-service/passkeys/authenticate/finish",{response:i,userId:e??null}),"PASSKEY_AUTH_FAILED","Passkey signin failed");if(o.kind==="mfa")throw new u("MFA_REQUIRED","This account requires MFA; use signIn()/challengeMfa()");return o.user})}async listPasskeys(){let e=await this.http.get("/auth-service/passkeys",await this.bearerHeaders());return!e.success||!Array.isArray(e.data)?[]:e.data}async deletePasskey(e){let t=await this.http.delete(`/auth-service/passkeys/${encodeURIComponent(e)}`,await this.bearerHeaders());if(!t.success)throw new u(t.error?.code??"PASSKEY_DELETE_FAILED",t.error?.message??"Failed to delete passkey",p(t))}async listMySessions(){let e=await this.http.get("/auth-service/sessions/me",await this.bearerHeaders());return!e.success||!Array.isArray(e.data)?[]:e.data}async revokeSession(e){let t=await this.http.delete(`/auth-service/sessions/me/${encodeURIComponent(e)}`,await this.bearerHeaders());if(!t.success)throw new u(t.error?.code??"SESSION_REVOKE_FAILED",t.error?.message??"Failed to revoke session",p(t))}async revokeAllSessions(){let e=await this.http.delete("/auth-service/sessions/me",await this.bearerHeaders());if(!e.success)throw new u(e.error?.code??"SESSION_REVOKE_ALL_FAILED",e.error?.message??"Failed to sign out other devices",p(e))}async startSso(e){let t=await this.http.post("/auth-service/sso/oidc/start",{returnTo:e});if(!t.success||!t.data)throw new u(t.error?.code??"SSO_START_FAILED",t.error?.message??"SSO start failed");return t.data}async signInWithSso(e){let t=e??(typeof window<"u"?window.location.origin:"");if(!t)throw new u("SSO_NO_RETURN_TO","returnTo required outside browser context");let r=await this.startSso(t);typeof window<"u"&&(window.location.href=r.authorizationUrl)}async startSaml(e){let t=await this.http.post("/auth-service/sso/saml/start",{returnTo:e});if(!t.success||!t.data)throw new u(t.error?.code??"SAML_START_FAILED",t.error?.message??"SAML start failed");return t.data}async signInWithSaml(e){let t=e??(typeof window<"u"?window.location.origin:"");if(!t)throw new u("SAML_NO_RETURN_TO","returnTo required outside browser context");let r=await this.startSaml(t);typeof window<"u"&&(window.location.href=r.authorizationUrl)}consumeSsoTokenFromUrl(){return this.serialize(async()=>{if(typeof window>"u")return null;let e=window.location.hash.replace(/^#/,"");if(!e)return null;let t=new URLSearchParams(e),r=t.get("sendora_oidc_error")??t.get("sendora_saml_error");if(r)throw window.history.replaceState(null,"",window.location.pathname+window.location.search),new u("SSO_FAILED",decodeURIComponent(r));let n=t.get("sendora_oidc_token")??t.get("sendora_saml_token");if(!n)return null;let i=t.get("sendora_retired_anon");window.history.replaceState(null,"",window.location.pathname+window.location.search);let o=await this.performSwitch(async()=>{let a=await this.http.post("/auth-service/token/refresh",{refreshToken:n}),l=a.success?q(a.data):null;return l?{success:!0,data:{user:ae(a.data)??Je(l.accessToken,Ye(l.accessToken)??"",!1),tokens:{...l,tokenType:"Bearer"}}}:{success:!1,error:a.error??{code:"SSO_EXCHANGE_FAILED",message:"Could not exchange SSO token"}}},"SSO_EXCHANGE_FAILED","Could not exchange SSO token");if(o.kind==="mfa")throw new u("MFA_REQUIRED","Unexpected MFA challenge on SSO exchange");return i&&this.fireDeviceTakeover(i,o.user.id),o.user})}};function qe(s){return s?ke.includes(s):!1}function Re(s){return{v:1,user:s.user,accessToken:s.tokens.accessToken,accessExpiresAt:Date.now()+s.tokens.expiresIn*1e3,refreshToken:s.tokens.refreshToken}}function xt(){let s="abcdefghijklmnopqrstuvwxyz0123456789",e=new Uint8Array(32),t=globalThis.crypto;if(t?.getRandomValues)t.getRandomValues(e);else for(let n=0;n<e.length;n++)e[n]=Math.floor(Math.random()*256);let r="mk_";for(let n=0;n<e.length;n++)r+=s[e[n]%s.length];return r}function Be(s){switch(s.kind){case"password":return{path:"/auth-service/login",body:{email:s.email,password:s.password}};case"gameCenter":{let{kind:e,...t}=s;return{path:"/auth-service/login/game-center",body:t}}case"playGames":return{path:"/auth-service/login/play-games",body:{serverAuthCode:s.serverAuthCode}};case"magicLink":return{path:"/auth-service/magic-link/verify",body:{token:s.token}};case"emailOtp":return{path:"/auth-service/email-otp/verify",body:{email:s.email,code:s.code}};case"passkey":return{path:"/auth-service/passkeys/authenticate/finish",body:{response:s.assertion,userId:s.userId??null}};case"mfa":return{path:"/auth-service/mfa/challenge",body:{challengeToken:s.challengeToken,code:s.code}};default:{let{kind:e,...t}=s;return{path:"/auth-service/login/social",body:{provider:e,...t}}}}}function ze(s){switch(s.kind){case"password":return{path:"/auth-service/me/link/email",body:{email:s.email,password:s.password}};case"gameCenter":{let{kind:e,...t}=s;return{path:"/auth-service/me/link/game-center",body:t}}case"playGames":return{path:"/auth-service/me/link/play-games",body:{serverAuthCode:s.serverAuthCode}};case"magicLink":case"emailOtp":case"passkey":case"mfa":throw new u("UNSUPPORTED_LINK_CREDENTIAL",`A ${s.kind} credential cannot be linked; sign in with it instead`);default:{let{kind:e,...t}=s;return{path:"/auth-service/me/link/social",body:{provider:e,...t}}}}}function Qe(s,e,t){let r=s&&typeof s=="object"?s:{},n=i=>typeof r[i]=="number"?r[i]:0;return{mergedUserId:typeof r.mergedUserId=="string"?r.mergedUserId:e,deletedAnonymousId:typeof r.deletedAnonymousId=="string"?r.deletedAnonymousId:t,eventsReassigned:n("eventsReassigned"),profilesReassigned:n("profilesReassigned"),entitiesReassigned:n("entitiesReassigned"),pushTokensReassigned:n("pushTokensReassigned")}}function Ye(s){let e=S(s)?.sub;return typeof e=="string"&&e.length>0?e:null}function Je(s,e,t=!0){let r=S(s)??{},n=typeof r.sub=="string"&&r.sub.length>0?r.sub:e,i=typeof r.is_anonymous=="boolean"?r.is_anonymous:t,o={id:n,email:typeof r.email=="string"?r.email:null,emailVerified:typeof r.email_verified=="boolean"?r.email_verified:!i,name:typeof r.name=="string"?r.name:null,isAnonymous:i};if(Object.prototype.hasOwnProperty.call(r,"project")){let a=r.project;o.project=typeof a=="string"?a:null}return o}function B(s){let e=(4-s.length%4)%4,t=(s+"===".slice(0,e)).replace(/-/g,"+").replace(/_/g,"/"),r=atob(t),n=new ArrayBuffer(r.length),i=new Uint8Array(n);for(let o=0;o<r.length;o++)i[o]=r.charCodeAt(o);return n}function E(s){let e=s instanceof Uint8Array?s:new Uint8Array(s),t="";for(let r=0;r<e.length;r++)t+=String.fromCharCode(e[r]);return btoa(t).replace(/\+/g,"-").replace(/\//g,"_").replace(/=+$/,"")}function Nt(s){return{challenge:B(s.challenge),rp:s.rp,user:{id:B(s.user.id),name:s.user.name,displayName:s.user.displayName},pubKeyCredParams:s.pubKeyCredParams,timeout:s.timeout,attestation:s.attestation,excludeCredentials:s.excludeCredentials?.map(e=>({id:B(e.id),type:"public-key",transports:e.transports})),authenticatorSelection:s.authenticatorSelection}}function Ot(s){return{challenge:B(s.challenge),timeout:s.timeout,rpId:s.rpId,allowCredentials:s.allowCredentials?.map(e=>({id:B(e.id),type:"public-key",transports:e.transports})),userVerification:s.userVerification}}function Ht(s){let e=s.response;return{id:s.id,rawId:E(s.rawId),type:s.type,response:{clientDataJSON:E(e.clientDataJSON),attestationObject:E(e.attestationObject),transports:typeof e.getTransports=="function"?e.getTransports():void 0},clientExtensionResults:s.getClientExtensionResults()}}function q(s){if(!s||typeof s!="object")return null;let e=s.tokens,t=e&&typeof e=="object"?e:s;return typeof t.accessToken!="string"||!t.accessToken||typeof t.refreshToken!="string"||!t.refreshToken||typeof t.expiresIn!="number"||t.expiresIn<=0?null:{accessToken:t.accessToken,refreshToken:t.refreshToken,expiresIn:t.expiresIn}}function ae(s){if(!s||typeof s!="object")return null;let e=s.user;if(!e||typeof e!="object")return null;let t=e.id;return typeof t!="string"||t.length===0?null:e}function Xe(s,e){let t=S(s);if(!t)return!0;let r=t.exp;return typeof r!="number"||!Number.isFinite(r)?!0:e<r*1e3}function Mt(s){let e=s.response;return{id:s.id,rawId:E(s.rawId),type:s.type,response:{clientDataJSON:E(e.clientDataJSON),authenticatorData:E(e.authenticatorData),signature:E(e.signature),userHandle:e.userHandle?E(e.userHandle):null},clientExtensionResults:s.getClientExtensionResults()}}var Ft=D;function jt(s){return s===!1?{pageViews:!1,sessionStart:!1,appOpen:!1,appBackground:!1,engagement:!1}:s===!0||s===void 0?{pageViews:!0,sessionStart:!0,appOpen:!0,appBackground:!0,engagement:!0}:{pageViews:s.pageViews??!0,sessionStart:s.sessionStart??!0,appOpen:s.appOpen??!0,appBackground:s.appBackground??!0,engagement:s.engagement??!0}}var Gt=250,Ze=360*60*1e3;function rt(s,e){if(typeof window>"u")return()=>{};let t=jt(e.autoTrack),r=e.sessionIdleMs??18e5,n=[],i="sendora_session_id",o="sendora_session_last_activity";function a(){return et(i)??""}function l(c){tt(i,c)}function d(){let c=et(o);return c&&Number(c)||0}function h(c){tt(o,String(c))}function g(){return`sess_${Date.now().toString(36)}_${Math.random().toString(36).slice(2,10)}`}function k(c){let A=Date.now(),O=d();if(!a()||O&&A-O>r){let te=g();l(te),c&&t.sessionStart&&s.track("session.start",{sessionId:te})}h(A)}k(t.sessionStart),t.appOpen&&s.track("app.opened",{sessionId:a()||void 0,url:window.location.origin+window.location.pathname,referrer:document.referrer||void 0});let v=window.location.pathname,m=0,y=document.visibilityState==="visible"?Date.now():0;function N(){y>0&&(m+=Date.now()-y,y=0)}function ee(){if(!t.engagement)return;N();let c=m;if(m=0,!(c<Gt)){c>Ze&&(c=Ze);try{s.track("app.engagement",{durationMs:Math.round(c),screen:v,sessionId:a()||void 0})}catch{}}}function st(c){v=c,m=0,y=document.visibilityState==="visible"?Date.now():0}if(t.pageViews||t.engagement){t.pageViews&&s.page();let c=()=>{ee(),k(!0),t.pageViews&&s.page(),st(window.location.pathname)},A=()=>c();window.addEventListener("popstate",A),n.push(()=>window.removeEventListener("popstate",A));let O=window;if(!O.__sendoraHistoryPatched){O.__sendoraHistoryPatched=!0;let te=history.pushState,nt=history.replaceState;history.pushState=function(...pe){let fe=te.apply(this,pe);return window.dispatchEvent(new Event("sendora:locationchange")),fe},history.replaceState=function(...pe){let fe=nt.apply(this,pe);return window.dispatchEvent(new Event("sendora:locationchange")),fe}}let he=()=>c();window.addEventListener("sendora:locationchange",he),n.push(()=>window.removeEventListener("sendora:locationchange",he))}if(t.appBackground||t.engagement){let c=()=>{if(document.visibilityState==="hidden"){ee(),t.appBackground&&(k(!0),s.track("app.backgrounded",{sessionId:a()||void 0}));try{s.flush()}catch{}}else document.visibilityState==="visible"&&(t.appBackground&&(k(!0),s.track("app.foregrounded",{sessionId:a()||void 0})),t.engagement&&y===0&&(y=Date.now()))};if(document.addEventListener("visibilitychange",c),n.push(()=>document.removeEventListener("visibilitychange",c)),t.engagement){let A=()=>{ee();try{s.flush()}catch{}};window.addEventListener("pagehide",A),n.push(()=>window.removeEventListener("pagehide",A))}}let Ce=0,T=()=>{let c=Date.now();c-Ce<5e3||(Ce=c,k(!0))};return window.addEventListener("click",T,{passive:!0}),window.addEventListener("keydown",T,{passive:!0}),window.addEventListener("scroll",T,{passive:!0}),n.push(()=>{window.removeEventListener("click",T),window.removeEventListener("keydown",T),window.removeEventListener("scroll",T)}),()=>{ee();for(let c of n)try{c()}catch{}}}function et(s){try{return window.sessionStorage?.getItem(s)??null}catch{return null}}function tt(s,e){try{window.sessionStorage?.setItem(s,e)}catch{}}var J=class s{constructor(e){this.http=e}static isSupported(){return typeof window>"u"?!1:"serviceWorker"in navigator&&"PushManager"in window&&"Notification"in window}static permission(){return typeof Notification>"u"?"denied":Notification.permission}async subscribe(e){if(!s.isSupported())throw new Error("[sendoracloud] Web Push not supported in this browser.");let t=Notification.permission;if(t==="default"&&(t=await Notification.requestPermission()),t!=="granted")throw new Error(`[sendoracloud] Notification permission ${t}.`);let r=await navigator.serviceWorker.getRegistration(e.scope??"/");r||(r=await navigator.serviceWorker.register(e.serviceWorkerPath,{scope:e.scope??"/"})),await navigator.serviceWorker.ready;let i=(await this.http.get("/push/vapid"))?.data?.publicKey;if(!i)throw new Error("[sendoracloud] backend returned no VAPID public key.");let a=await r.pushManager.getSubscription()??await r.pushManager.subscribe({userVisibleOnly:!0,applicationServerKey:Kt(i)}),l=a.toJSON(),d=l.endpoint,h=l.keys?.p256dh??"",g=l.keys?.auth??"",k=await Wt(d),v=await this.http.post("/push/tokens",{platform:"web",token:k,webEndpoint:d,webP256dh:h,webAuth:g,userAgent:typeof navigator<"u"?navigator.userAgent:void 0,locale:typeof navigator<"u"?navigator.language:void 0,timezone:Intl?.DateTimeFormat?.().resolvedOptions?.().timeZone,...e.userId?{userId:e.userId}:{}});if(!v?.data?.tokenId)throw new Error("[sendoracloud] backend returned no tokenId on subscribe.");return{tokenId:v.data.tokenId,subscription:a}}async unsubscribe(e="/"){if(!s.isSupported())return!1;let t=await navigator.serviceWorker.getRegistration(e);if(!t)return!1;let r=await t.pushManager.getSubscription();return r?await r.unsubscribe():!1}async trackOpen(e,t){let r={sendId:e};t!==void 0&&(r.clickAction=t);let n=await this.http.post("/push/track-open",r);if(!n.success)throw new Error(n.error?.message??"push.trackOpen failed")}};function Kt(s){let e="=".repeat((4-s.length%4)%4),t=(s+e).replace(/-/g,"+").replace(/_/g,"/"),r=atob(t),n=new Uint8Array(r.length);for(let i=0;i<r.length;i++)n[i]=r.charCodeAt(i);return n}async function Wt(s){let e=new TextEncoder().encode(s),t=await crypto.subtle.digest("SHA-256",e);return Array.from(new Uint8Array(t)).map(n=>n.toString(16).padStart(2,"0")).join("")}var X=class{constructor(e){}unsupported(){throw new Error("[SendoraCloud] sendora.audiences is not available in the browser SDK. Audiences require a secret (sk_*) key with the audiences:read/write scopes and must be managed from a trusted server, not the browser.")}list(){return this.unsupported()}get(e){return this.unsupported()}create(e){return this.unsupported()}update(e,t){return this.unsupported()}delete(e){return this.unsupported()}};var f=class extends Error{constructor(e,t,r){super(t),this.name="LinkError",this.code=e,this.statusCode=r}};function Te(s,e){let t=(s??"").toUpperCase();return t==="NOT_FOUND"?new f("NOT_FOUND",e):t==="FORBIDDEN"||t==="UNAUTHORIZED"?new f("UNAUTHORIZED",e):t==="RATE_LIMITED"?new f("RATE_LIMITED",e):t==="ENTITLEMENT_ERROR"||/plan limit/i.test(e)?new f("PLAN_LIMIT",e):t==="VALIDATION_ERROR"?/iOS bundle|Android package/i.test(e)?new f("BUNDLE_MISMATCH",e):/2KB|10KB|linkData/i.test(e)?new f("DATA_TOO_LARGE",e):/fallbackUrl/i.test(e)&&/apps/i.test(e)?new f("FALLBACK_REQUIRED",e):new f("INVALID_INPUT",e):t==="PARSE_ERROR"||t==="HTTP_ERROR"||/HTTP \d{3}/.test(e)?new f("NETWORK",e):new f("UNKNOWN",e||`Unknown LinkError (code=${s??"none"})`)}var _e=/^[a-z0-9-]{3,20}$/;function Vt(s){try{let t=new URL(s).pathname.split("/").filter(Boolean);if(t.length===0)return null;let r=t[t.length-1];return _e.test(r)?r:null}catch{return null}}var $t=5*6e4,qt=50,Bt=5,Z=class{constructor(e){this.http=e;this.prewarmCache=new Map;this.prewarmInflight=0}cacheKey(e,t){if(t)return`k:${t}`;let r={},n=e;for(let i of Object.keys(n).sort())r[i]=n[i];return`s:${JSON.stringify(r)}`}evictExpired(){let e=Date.now();for(let[t,r]of this.prewarmCache)e-r.ts>$t&&this.prewarmCache.delete(t);for(;this.prewarmCache.size>qt;){let t=this.prewarmCache.keys().next().value;if(t===void 0)break;this.prewarmCache.delete(t)}}prewarm(e,t){this.evictExpired();let r=this.cacheKey(e,t?.key);if(this.prewarmCache.has(r)||this.prewarmInflight>=Bt)return;this.prewarmInflight++;let n=this.doCreate(e).catch(i=>{throw this.prewarmCache.delete(r),i}).finally(()=>{this.prewarmInflight--});this.prewarmCache.set(r,{promise:n,ts:Date.now()})}async create(e,t){if(!e.title)throw new f("INVALID_INPUT","links.create: title is required");this.evictExpired();let r=this.cacheKey(e,t?.key),n=this.prewarmCache.get(r);return n?(this.prewarmCache.delete(r),n.promise):this.doCreate(e)}async doCreate(e){let t={title:e.title};e.fallbackUrl&&(t.fallbackUrl=e.fallbackUrl),e.iosDeepLinkPath&&(t.iosDeepLinkPath=e.iosDeepLinkPath),e.androidDeepLinkPath&&(t.androidDeepLinkPath=e.androidDeepLinkPath),e.linkData&&(t.linkData=e.linkData),e.ogTitle&&(t.ogTitle=e.ogTitle),e.ogDescription&&(t.ogDescription=e.ogDescription),e.ogImageUrl&&(t.ogImageUrl=e.ogImageUrl),e.campaign&&(t.campaign=e.campaign),e.source&&(t.source=e.source),e.medium&&(t.medium=e.medium),e.channel&&(t.channel=e.channel),e.tags&&(t.tags=e.tags),e.expiresAt&&(t.expiresAt=e.expiresAt),e.iosBundleId&&(t.iosBundleId=e.iosBundleId),e.androidPackageName&&(t.androidPackageName=e.androidPackageName);let r=await this.http.post("/sdk/links",t);if(!r.success||!r.data)throw Te(r.error?.code,r.error?.message??"links.create failed");return r.data}async revoke(e){if(!_e.test(e))throw new f("INVALID_INPUT",`links.revoke: '${e}' is not a valid shortcode`);let t=await this.http.post(`/sdk/links/${encodeURIComponent(e)}/revoke`,{});if(!t.success||!t.data)throw Te(t.error?.code,t.error?.message??"links.revoke failed");return{shortcode:t.data.shortcode,revoked:!0}}async getStats(e){if(!_e.test(e))throw new f("INVALID_INPUT",`links.getStats: '${e}' is not a valid shortcode`);let t=await this.http.get(`/sdk/links/${encodeURIComponent(e)}/stats`);if(!t.success||!t.data)throw Te(t.error?.code,t.error?.message??"links.getStats failed");return t.data}};var le=class{constructor(e){this.http=e}async reportInstall(e={}){let t=await this.http.post("/attribution/install",e);if(!t.success||!t.data)throw new Error(t.error?.message??"attribution.reportInstall failed");return t.data}async checkDeferred(e={}){let t=await this.http.post("/attribution/deferred",e);if(!t.success)throw new Error(t.error?.message??"attribution.checkDeferred failed");return t.data??null}};var ue=class{constructor(e){this.http=e}async createTicket(e){let t=await this.http.post("/support/tickets",e);if(!t.success||!t.data)throw new Error(t.error?.message??"support.createTicket failed");return t.data}async submitCsat(e){let t=await this.http.post("/support/csat",e);if(!t.success||!t.data)throw new Error(t.error?.message??"support.submitCsat failed");return t.data}};var de=class{constructor(e){this.http=e}async search(e){if(!e.query||e.query.trim().length===0)return[];let t=new URLSearchParams({query:e.query});e.limit&&t.set("limit",String(e.limit));let r=await this.http.get(`/kb/search?${t.toString()}`);if(!r.success||!Array.isArray(r.data))throw new Error(r.error?.message??"kb.search failed");return r.data}};var zt=/^[A-Za-z0-9_.-]{1,64}$/;function Qt(s){if(s!==void 0){if(typeof s!="string"||!zt.test(s))throw new Error(`[sendora] init: storagePrefix must be 1-64 chars of A-Z a-z 0-9 _ . - (got ${JSON.stringify(s)}). Changing it signs the browser out, so it is validated rather than ignored.`);return s}}var Yt=/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;function Jt(s){let e=s.expectedProjectId;if(e!==void 0){if(typeof e!="string"||!Yt.test(e))throw new Error(`[sendora] init: expectedProjectId must be a UUID (got ${JSON.stringify(e)}).`);if(s.projectId!==void 0&&s.projectId!==e)throw new Error(`[sendora] init: expectedProjectId (${e}) must equal projectId (${s.projectId}) when both are set \u2014 they name the same project.`)}}var ce=class ce{constructor(e){this.autoTrackCleanup=null;this.http=new re(e),this.storage=new se(Qt(e.storagePrefix),e.tokenStore==="memory"),this.consent=new K(e.defaultConsent===!0,this.http),this.analytics=new H(e,this.http,this.storage,this.consent),this.flags=new M(e,this.http,this.storage),this.surveys=new F(e,this.http,this.storage),this.messages=new j(e,this.http,this.storage),this.chatbot=new G(e,this.http,this.storage),this.auth=new Y(e,this.http,this.storage,this.analytics,this.flags,this.chatbot,{onIdentityWithheld:()=>{this.analytics.withholdIdentity(),this.flags.setContext({})}}),this.webPush=new J(this.http),this.audiences=new X(this.http),this.links=new Z(this.http),this.attribution=new le(this.http),this.support=new ue(this.http),this.kb=new de(this.http),e.autoTrack!==!1&&(this.autoTrackCleanup=rt(this.analytics,e))}static init(e){return Ne(e.apiKey),Jt(e),new ce(e)}static sanitizeHtml(e){return we(e)}static safeUrl(e){return R(e)}track(e,t){this.analytics.track(e,t)}page(e){this.analytics.page(e)}identify(e,t,r){this.analytics.identify(e,t,r),this.flags.setContext({userId:e})}reset(e){this.analytics.reset(),this.flags.reset(),this.chatbot.newSession()}onIdentityWithheld(e){return this.auth.onIdentityWithheld(e)}async flush(){await this.analytics.flush()}destroy(){this.autoTrackCleanup&&(this.autoTrackCleanup(),this.autoTrackCleanup=null),this.analytics.destroy(),this.flags.destroy(),this.messages.destroy()}};ce.version=I;var be=ce,Zr=be;export{Se as AMBIGUOUS_HELD_GUEST,Ft as AUTH_HELD_SLOT_KEYS,Et as AUTH_STATES,$ as AUTH_WITHHELD_CODES,z as AlreadyIdentifiedError,H as Analytics,X as Audiences,Y as Auth,u as AuthError,G as Chatbot,K as Consent,x as CredentialInUseError,ke as DEAD_CODES,U as EmailAlreadyTakenError,M as FeatureFlags,P as HELD_GUEST_SLOTS,Q as HeldGuestLimitError,L as HeldGuestProjectMismatch,j as InAppMessaging,f as LinkError,Z as Links,ve as REFRESH_END_REASONS,It as REJECTED_IN_WITHHELD,Ae as RELEASE_HELD_ON_END_REASONS,be as SendoraCloud,F as Surveys,w as ValidationError,J as WebPush,Zr as default,Vt as extractShortcodeFromUrl,Ee as projectVerdict,R as safeUrl,we as sanitizeHtml};
1
+ var De=/^[a-zA-Z][a-zA-Z0-9._:-]{0,127}$/;var it=new Set(["__proto__","constructor","prototype"]),w=class extends Error{constructor(e){super(`[SendoraCloud] ${e}`),this.name="SendoraValidationError"}};function Pe(s){if(typeof s!="string"||!De.test(s))throw new w(`Invalid event name: must match ${De}, got "${String(s)}".`)}function Le(s){if(s==null)return;if(typeof s!="object"||Array.isArray(s))throw new w("Properties must be a plain object, not an array or primitive.");let e=Ue(s);if(e>5)throw new w(`Properties nested too deeply (${e} levels, max 5).`);xe(s);let t;try{t=JSON.stringify(s).length}catch{throw new w("Properties contain a circular reference or unserializable value.")}if(t>32768)throw new w(`Properties too large (${t} bytes, max 32768).`)}function Ue(s,e=0){if(e>6||s==null||typeof s!="object")return e;let t=e;for(let r of Object.keys(s)){let n=Ue(s[r],e+1);n>t&&(t=n)}return t}function xe(s){if(!(s==null||typeof s!="object"))for(let e of Object.keys(s)){if(it.has(e))throw new w(`Forbidden property key "${e}" (prototype pollution guard).`);xe(s[e])}}var ot=/^pk_[A-Za-z0-9_-]{16,}$/;function Ne(s){if(!s||typeof s!="string")throw new w("apiKey is required.");if(s.startsWith("sk_")||s.startsWith("sendora_secret_"))throw new w("Secret keys must NEVER be used in browser SDK. Use a publishable key (pk_...).");if(!ot.test(s))throw new w("Invalid publishable key format. Expected pk_... (17+ chars).")}function Oe(s){let e=s.replace(/\/$/,"");if(!(e.startsWith("http://localhost")||e.startsWith("http://127.0.0.1"))&&!e.startsWith("https://"))throw new w("apiUrl must be https:// (only http://localhost is allowed for dev).")}var He={name:"@sendoracloud/sdk-web",version:"3.24.2",description:"Sendora Cloud Web SDK \u2014 analytics, feature flags, surveys, in-app messaging, chatbot, auth, deep links (Branch / Firebase parity). Zero dependencies, TypeScript, SSR-safe.",type:"module",main:"./dist/index.cjs",module:"./dist/index.js",types:"./dist/index.d.ts",exports:{".":{types:"./dist/index.d.ts",import:"./dist/index.js",require:"./dist/index.cjs"}},files:["dist","README.md","LICENSE"],keywords:["sendora","analytics","feature-flags","surveys","in-app-messaging","chatbot","tracking","customer-engagement"],homepage:"https://sendoracloud.com/sdks",bugs:{url:"https://github.com/sendoracloud/sdk-web/issues"},author:"Sendora Cloud <hello@sendoracloud.com>",license:"Apache-2.0",publishConfig:{access:"public"},sideEffects:!1,scripts:{build:"tsup src/index.ts --format cjs,esm --dts --clean --minify",typecheck:"tsc --noEmit && tsc --noEmit -p tsconfig.test.json",test:"vitest run",prepublishOnly:"npm run build"},devDependencies:{typescript:"^5.4.0",tsup:"^8.0.0"}};var I=He.version;var lt="https://api.sendoracloud.com",ut=1e4,dt="@sendoracloud/sdk-web",se=class{constructor(e){let t=(e.apiUrl??lt).replace(/\/$/,"");Oe(t),this.apiKey=e.apiKey,this.baseUrl=t,this.debug=!!e.debug}get(e,t){return this.request("GET",e,void 0,t)}post(e,t,r){return this.request("POST",e,t,r)}patch(e,t,r){return this.request("PATCH",e,t,r)}delete(e,t){return this.request("DELETE",e,void 0,t)}async request(e,t,r,n){let i=`${this.baseUrl}/api/v1${t}`,o=typeof AbortController<"u"?new AbortController:null,a=o?setTimeout(()=>o.abort(),ut):null;try{let l=await fetch(i,{method:e,headers:{"Content-Type":"application/json","X-API-Key":this.apiKey,"X-Sendora-SDK-Name":dt,"X-Sendora-SDK-Version":I,...n??{}},body:r?JSON.stringify(r):void 0,signal:o?o.signal:void 0});a&&clearTimeout(a);let d;try{d=await l.json()}catch{d={success:!1,error:{code:"PARSE_ERROR",message:`HTTP ${l.status}`}}}if(this.debug&&console.debug(`[SendoraCloud] ${e} ${t} \u2192 ${l.status}`),!l.ok){if(t.startsWith("/auth-service/")&&!this.debug)console.warn(`[SendoraCloud] ${e} ${t} \u2192 HTTP ${l.status}`);else{let g=d?.error?.code??"HTTP_ERROR",k=d?.error?.message??`HTTP ${l.status}`,v=d?.error?.details?.fieldErrors,m=v?` (${Object.entries(v).map(([y,N])=>`${y}: ${(N??[]).join(", ")}`).join("; ")})`:"";console.warn(`[SendoraCloud] ${e} ${t} \u2192 HTTP ${l.status} \u2014 ${g}: ${k}${m}`)}d&&d.error&&(d.error={...d.error,status:l.status})}return d}catch(l){a&&clearTimeout(a);let d=l instanceof Error&&l.name==="AbortError"?"timeout":"error";return console.warn(`[SendoraCloud] ${e} ${t} network ${d}`),{success:!1,error:{code:"NETWORK_ERROR",message:d}}}}};var ct="sendora_",ne=class{constructor(e,t=!1){this.memoryStore=new Map;this.useLocalStorage=t?!1:this.checkLocalStorage(),this.prefix=e??ct}get(e){let t=this.prefix+e;if(this.useLocalStorage)try{return localStorage.getItem(t)}catch{return this.memoryStore.get(t)??null}return this.memoryStore.get(t)??null}set(e,t){let r=this.prefix+e;if(this.useLocalStorage)try{localStorage.setItem(r,t);return}catch{}this.memoryStore.set(r,t)}remove(e){let t=this.prefix+e;if(this.useLocalStorage)try{localStorage.removeItem(t)}catch{}this.memoryStore.delete(t)}isPersistent(){return this.useLocalStorage}relativeKey(e){return e.startsWith(this.prefix)?e.slice(this.prefix.length):null}clearPrefix(e){let t=this.prefix+e;if(this.useLocalStorage)try{for(let r=localStorage.length-1;r>=0;r--){let n=localStorage.key(r);n&&n.startsWith(t)&&localStorage.removeItem(n)}}catch{}for(let r of Array.from(this.memoryStore.keys()))r.startsWith(t)&&this.memoryStore.delete(r)}checkLocalStorage(){try{if(typeof localStorage>"u")return!1;let e="__sendora_test__";return localStorage.setItem(e,"1"),localStorage.removeItem(e),!0}catch{return!1}}};function _(s=""){let e=new Uint8Array(16),t=typeof globalThis<"u"&&"crypto"in globalThis?globalThis.crypto:void 0;if(!t||typeof t.getRandomValues!="function")throw new Error("[SendoraCloud] crypto.getRandomValues unavailable \u2014 refusing to mint IDs without a CSPRNG");t.getRandomValues(e);let r="";for(let n of e)r+=n.toString(16).padStart(2,"0");return s+r}var Me=500,ge=10,me=6e4,H=class{constructor(e,t,r,n){this.queue=[];this.timer=null;this.userId=null;this.identityToken=null;this.consecutiveFailures=0;this.nextFlushAfter=0;this.breakerOpenAt=0;this.breakerWarned=!1;this.http=t,this.storage=r,this.consent=n,this.projectId=e.projectId,this.flushInterval=e.flushInterval??5e3,this.maxQueueSize=e.maxQueueSize??20,this.persistUserId=!!e.persistUserId,this.stripQueryParams=e.stripQueryParams!==!1,this.appVersion=e.appVersion,this.storage.get("schema_version")===null&&this.storage.set("schema_version","1");let i=this.storage.get("anonymous_id");if(i?this.anonymousId=i:(this.anonymousId=_("anon_"),this.storage.set("anonymous_id",this.anonymousId)),this.persistUserId){let o=this.storage.get("user_id");o&&(this.userId=o)}this.timer=setInterval(()=>this.flush(),this.flushInterval),typeof window<"u"&&window.addEventListener("beforeunload",()=>this.flush()),this.consent.subscribe(o=>{o&&this.flush()})}track(e,t){Pe(e),t&&Le(t),this.queue.length>=Me&&this.queue.shift(),this.queue.push({eventType:e,properties:t??{},userId:this.userId??void 0,anonymousId:this.anonymousId,timestamp:new Date().toISOString(),identityToken:this.identityToken??void 0}),this.queue.length>=this.maxQueueSize&&this.flush()}page(e){if(typeof window>"u")return;let t=this.stripQueryParams?window.location.origin+window.location.pathname:window.location.href;this.track("page.viewed",{url:t,path:window.location.pathname,title:document.title,referrer:document.referrer||void 0,...e})}identify(e,t,r){if(typeof e!="string"||e.length===0||e.length>256)throw new Error("[SendoraCloud] userId must be a 1-256 char string.");this.userId=e,this.identityToken=r?.identityToken??null,this.persistUserId&&this.storage.set("user_id",e),this.track("user.identified",{...t})}reset(e=!0){this.userId=null,this.identityToken=null,this.storage.remove("user_id"),e&&(this.anonymousId=_("anon_"),this.storage.set("anonymous_id",this.anonymousId)),this.storage.clearPrefix("iam_shown_"),this.storage.clearPrefix("survey_shown_")}withholdIdentity(){this.userId=null,this.identityToken=null}dropQueue(){this.queue=[]}async flush(){if(this.queue.length===0||!this.consent.isGranted()||Date.now()<this.nextFlushAfter)return;this.consecutiveFailures>ge&&Date.now()-this.breakerOpenAt>=me&&(this.consecutiveFailures=0,this.breakerOpenAt=0,this.breakerWarned=!1);let e=this.queue.splice(0,100),t=this.getSessionId(),r=e.map(a=>({projectId:this.projectId,module:"custom",eventType:a.eventType,userId:a.userId,anonymousId:a.anonymousId,identityToken:a.identityToken,timestamp:a.timestamp??new Date().toISOString(),properties:a.properties??{},context:this.getContext(),...t?{sessionId:t}:{},consent:["analytics"]}));if((await this.http.post("/events/batch",{events:r})).success){this.consecutiveFailures=0,this.breakerOpenAt=0,this.breakerWarned=!1;return}if(this.consecutiveFailures++,this.consecutiveFailures>ge){this.breakerWarned||(this.breakerOpenAt=Date.now(),this.breakerWarned=!0,console.warn(`[SendoraCloud] Analytics circuit breaker open after ${ge} consecutive failed flushes \u2014 events will be dropped until a flush succeeds or ${me}ms elapse.`));return}let i=Math.min(me,1e3*2**this.consecutiveFailures);this.nextFlushAfter=Date.now()+i;let o=Math.max(0,Me-this.queue.length);o>0&&this.queue.unshift(...e.slice(0,o))}destroy(){this.timer&&clearInterval(this.timer),this.timer=null,this.flush()}getSessionId(){try{return typeof sessionStorage>"u"?void 0:sessionStorage.getItem("sendora_session_id")||void 0}catch{return}}getContext(){return typeof window>"u"?{sdk:{name:"@sendoracloud/sdk-web",version:I}}:{page:{url:this.stripQueryParams?window.location.origin+window.location.pathname:window.location.href,path:window.location.pathname,title:document.title},referrer:document.referrer||void 0,locale:typeof navigator<"u"?navigator.language:void 0,device:this.buildDevice(),sdk:{name:"@sendoracloud/sdk-web",version:I}}}buildDevice(){if(typeof navigator>"u")return;let e=navigator.userAgent||"",r=navigator.userAgentData?.mobile??/Mobi|Android|iPhone|iPod/i.test(e);return{type:/iPad|Tablet|(?:Android(?!.*Mobile))/i.test(e)?"tablet":r?"mobile":"desktop",os:"Web",osVersion:"",model:"",appVersion:this.resolveAppVersion(),browser:ht(e)}}resolveAppVersion(){if(this.appVersion)return this.appVersion;if(typeof document<"u"){let r=document.querySelector('meta[name="sendora:app-version"]')?.getAttribute("content");if(r)return r}let e=globalThis.__SENDORA_APP_VERSION__;return typeof e=="string"?e:""}};function ht(s){let e=[["Edge",/Edg\/(\d+)/],["Opera",/OPR\/(\d+)/],["Firefox",/Firefox\/(\d+)/],["Samsung Internet",/SamsungBrowser\/(\d+)/],["Chrome",/Chrome\/(\d+)/],["Safari",/Version\/(\d+)[^ ]* Safari/]];for(let[t,r]of e){let n=r.exec(s);if(n)return`${t} ${n[1]}`}return"Unknown"}var M=class{constructor(e,t,r){this.cache=new Map;this.refreshInterval=null;this.http=t,this.storage=r;let n=this.storage.get("flags");if(n)try{let i=JSON.parse(n);if(Array.isArray(i))for(let o of i)ye(o)&&this.cache.set(o.key,o)}catch{}}setContext(e){this.userId=e.userId,this.entityId=e.entityId,this.environment=e.environment}async getFlag(e){if(typeof e!="string"||e.length===0||e.length>128)return null;let t=this.cache.get(e);if(t)return t.value;let r=await this.http.post("/feature-flags/evaluate",{key:e,userId:this.userId,entityId:this.entityId,environment:this.environment});return r.success&&r.data&&ye(r.data)?(this.cache.set(e,r.data),this.persistCache(),r.data.value):null}async isEnabled(e,t=!1){let r=await this.getFlag(e);return typeof r=="boolean"?r:t}async refreshAll(){let e=await this.http.post("/feature-flags/evaluate-all",{userId:this.userId,entityId:this.entityId,environment:this.environment});if(e.success&&Array.isArray(e.data)){this.cache.clear();for(let t of e.data)ye(t)&&this.cache.set(t.key,t);this.persistCache()}}startAutoRefresh(e=6e4){this.stopAutoRefresh(),this.refreshAll(),this.refreshInterval=setInterval(()=>this.refreshAll(),e)}stopAutoRefresh(){this.refreshInterval&&clearInterval(this.refreshInterval),this.refreshInterval=null}getAllFlags(){let e={};for(let[t,r]of this.cache)e[t]=r.value;return e}reset(){this.cache.clear(),this.storage.remove("flags"),this.userId=void 0,this.entityId=void 0,this.environment=void 0}destroy(){this.stopAutoRefresh()}persistCache(){this.storage.set("flags",JSON.stringify(Array.from(this.cache.values())))}};function ye(s){if(s==null||typeof s!="object")return!1;let e=s;return Object.prototype.hasOwnProperty.call(e,"__proto__")||Object.prototype.hasOwnProperty.call(e,"constructor")?!1:typeof e.key=="string"&&"value"in e}var pt=32*1024,F=class{constructor(e,t,r){this.activeSurvey=null;this.http=t,this.storage=r}onDisplay(e){this.onSurveyDisplay=e}async showSurvey(e){if(typeof e!="string"||!/^[A-Za-z0-9_-]{6,64}$/.test(e))return null;let t=`survey_shown_${e}`;if(this.storage.get(t))return null;let r=await this.http.get(`/surveys/${encodeURIComponent(e)}/config`);return!r.success||!r.data||!ft(r.data)?null:(this.activeSurvey=r.data,this.storage.set(t,"1"),this.onSurveyDisplay&&this.onSurveyDisplay(r.data),r.data)}async submitResponse(e,t,r=!0){let n=0;try{n=JSON.stringify(t).length}catch{return!1}if(n>pt)return!1;let i=await this.http.post("/surveys/responses",{surveyId:e,answers:t,completed:r});return i.success&&(this.activeSurvey=null),i.success}dismiss(){this.activeSurvey=null}getActiveSurvey(){return this.activeSurvey}};function ft(s){if(s==null||typeof s!="object")return!1;let e=s;return typeof e.id!="string"||typeof e.name!="string"||!Array.isArray(e.questions)?!1:e.questions.every(gt)}function gt(s){if(s==null||typeof s!="object")return!1;let e=s;return typeof e.id=="string"&&typeof e.text=="string"}function T(s){if(!(!s||typeof s!="string"))try{let e=typeof window<"u"?window.location.href:"https://local/",t=new URL(s,e);return t.protocol==="http:"||t.protocol==="https:"?t.href:void 0}catch{return}}var mt=new Set(["b","i","u","em","strong","a","p","br","span","ul","ol","li","h1","h2","h3","h4"]),yt={a:new Set(["href","target","rel"])};function we(s){if(typeof DOMParser>"u")return"";let t=new DOMParser().parseFromString(`<div>${s}</div>`,"text/html").body.firstElementChild;return t?(Fe(t),t.innerHTML):""}function Fe(s){let e=Array.from(s.children);for(let t of e){let r=t.tagName.toLowerCase();if(!mt.has(r)){let i=document.createTextNode(t.textContent??"");t.replaceWith(i);continue}let n=yt[r]??new Set;for(let i of Array.from(t.attributes)){if(!n.has(i.name.toLowerCase())){t.removeAttribute(i.name);continue}if(i.name.toLowerCase()==="href"){let o=T(i.value);o?t.setAttribute("href",o):t.removeAttribute(i.name)}}r==="a"&&(t.setAttribute("rel","noopener noreferrer"),t.setAttribute("target","_blank")),Fe(t)}}var j=class{constructor(e,t,r){this.messages=[];this.pollInterval=null;this.http=t,this.storage=r}onDisplay(e){this.onMessageDisplay=e}async checkMessages(){let e=await this.http.get("/in-app-messages/active");if(!e.success||!Array.isArray(e.data))return null;this.messages=e.data.map(wt);for(let t of this.messages){let r=`iam_shown_${t.id}`;if(!this.storage.get(r))return this.storage.set(r,"1"),this.onMessageDisplay&&this.onMessageDisplay(t),t}return null}async recordAction(e,t){await this.http.post("/in-app-messages/impressions",{messageId:e,action:t})}startPolling(e=3e5){this.stopPolling(),this.checkMessages(),this.pollInterval=setInterval(()=>this.checkMessages(),e)}stopPolling(){this.pollInterval&&clearInterval(this.pollInterval),this.pollInterval=null}getMessages(){return this.messages}destroy(){this.stopPolling()}};function wt(s){return{...s,content:{...s.content,ctaUrl:T(s.content.ctaUrl),imageUrl:T(s.content.imageUrl)}}}var kt=4e3,G=class{constructor(e,t,r){this.chatbotId=null;this.messages=[];this.http=t,this.storage=r;let n=this.storage.get("chat_session_id");this.sessionId=n??_("chat_"),n||this.storage.set("chat_session_id",this.sessionId)}init(e){if(typeof e!="string"||!/^[A-Za-z0-9_-]{6,64}$/.test(e))throw new Error("[SendoraCloud] Invalid chatbotId.");this.chatbotId=e}onNewMessage(e){this.onMessage=e}async sendMessage(e,t){if(!this.chatbotId||typeof e!="string"||e.length===0||e.length>kt)return null;let r={role:"user",content:e,timestamp:new Date().toISOString()};this.messages.push(r);let n=await this.http.post("/chatbot/message",{chatbotId:this.chatbotId,sessionId:this.sessionId,message:e,userId:t});if(n.success&&n.data&&typeof n.data.reply=="string"){let i={role:"assistant",content:n.data.reply,timestamp:new Date().toISOString()};return this.messages.push(i),this.onMessage&&this.onMessage(i),i}return null}getMessages(){return[...this.messages]}newSession(){this.messages=[],this.sessionId=_("chat_"),this.storage.set("chat_session_id",this.sessionId)}getSessionId(){return this.sessionId}};var K=class{constructor(e,t){this.listeners=new Set;this.granted=e,this.http=t}isGranted(){return this.granted}grant(){this.granted||(this.granted=!0,this.emit())}revoke(){this.granted&&(this.granted=!1,this.emit())}subscribe(e){return this.listeners.add(e),()=>this.listeners.delete(e)}async record(e){if(!this.http)throw new Error("consent.record requires SDK init (HttpClient unavailable)");let t=await this.http.post("/consent/record",e);if(!t.success||!t.data)throw new Error(t.error?.message??"consent.record failed");return t.data}async requestDeletion(e){if(!this.http)throw new Error("consent.requestDeletion requires SDK init (HttpClient unavailable)");let t=await this.http.post("/consent/deletion-request",e);if(!t.success||!t.data)throw new Error(t.error?.message??"consent.requestDeletion failed");return t.data}emit(){for(let e of this.listeners)try{e(this.granted)}catch{}}};var b="auth_access_token",C="auth_access_expires",ie="auth_refresh_token",oe="auth_user",W="auth_session",D=["auth_held_0","auth_held_1","auth_held_2","auth_held_3","auth_held_4"],ae="auth_mint_key",je="schema_version";var Ke=[b,C,ie,oe,W],vt=[...Ke,...D],kr=[...vt,ae];function At(s){if(s===null)return{user:null,unreadable:!1};try{let e=JSON.parse(s);return!e||typeof e!="object"||typeof e.id!="string"||e.id.length===0?{user:null,unreadable:!0}:{user:e,unreadable:!1}}catch{return{user:null,unreadable:!0}}}function St(s){if(s===null)return{record:null,unreadable:!1};try{let e=JSON.parse(s);if(!e||typeof e!="object"||e.v!==1)return{record:null,unreadable:!0};if(!e.user||typeof e.user!="object"||typeof e.user.id!="string"||e.user.id.length===0)return{record:null,unreadable:!0};if(typeof e.refreshToken!="string"||e.refreshToken.length===0)return{record:null,unreadable:!0};let t=typeof e.accessToken=="string"&&e.accessToken.length>0?e.accessToken:null,r=typeof e.accessExpiresAt=="number"&&Number.isFinite(e.accessExpiresAt)?e.accessExpiresAt:0,n=Array.isArray(e.heldReportPending)?e.heldReportPending.filter(i=>typeof i=="string"):void 0;return{record:{v:1,user:e.user,accessToken:t,accessExpiresAt:r,refreshToken:e.refreshToken,...n&&n.length>0?{heldReportPending:n}:{}},unreadable:!1}}catch{return{record:null,unreadable:!0}}}function Ge(s){if(s===null)return{slot:null,unreadable:!1};try{let e=JSON.parse(s);return!e||typeof e!="object"||e.v!==1||typeof e.userId!="string"||e.userId.length===0||typeof e.refreshToken!="string"||e.refreshToken.length===0?{slot:null,unreadable:!0}:{slot:{v:1,userId:e.userId,sid:typeof e.sid=="string"?e.sid:"",refreshToken:e.refreshToken,tokenAtHold:typeof e.tokenAtHold=="string"?e.tokenAtHold:e.refreshToken,heldAt:typeof e.heldAt=="number"&&Number.isFinite(e.heldAt)?e.heldAt:0,project:typeof e.project=="string"?e.project:null,autoRestore:e.autoRestore!==!1},unreadable:!1}}catch{return{slot:null,unreadable:!0}}}var V=class{constructor(e){this.storage=e}readDisk(){let{record:e,unreadable:t}=St(this.storage.get(W)),{user:r,unreadable:n}=At(this.storage.get(oe)),i=this.storage.get(C),o=i?Number(i):0;return{record:e,recordUnreadable:t,legacy:{user:r,userUnreadable:n,accessToken:this.storage.get(b),accessExpiresAt:Number.isFinite(o)?o:0,refreshToken:this.storage.get(ie)}}}currentRefresh(){return this.readDisk().legacy.refreshToken}static recordTrusted(e){return!!e.record&&!!e.legacy.refreshToken&&e.record.refreshToken===e.legacy.refreshToken}writeSession(e){this.storage.set(oe,JSON.stringify(e.user)),e.accessToken?(this.storage.set(b,e.accessToken),this.storage.set(C,String(e.accessExpiresAt))):(this.storage.remove(b),this.storage.remove(C)),this.storage.set(ie,e.refreshToken),this.storage.set(W,JSON.stringify(e)),this.storage.get(je)!=="2"&&this.storage.set(je,"2")}clearRecord(){this.storage.remove(W)}writeLimboTokens(e){this.storage.set(b,e.accessToken),this.storage.set(C,String(e.accessExpiresAt)),this.storage.set(ie,e.refreshToken)}clearSession(){for(let e of Ke)this.storage.remove(e)}clearStaleBlob(){this.storage.remove(oe),this.storage.remove(b),this.storage.remove(C),this.storage.remove(W)}readSlots(){let e=[],t=[];return D.forEach((r,n)=>{let{slot:i,unreadable:o}=Ge(this.storage.get(r));e.push(i),o&&t.push(n)}),{slots:e,unreadable:t}}readSlot(e){return Ge(this.storage.get(D[e])).slot}writeSlot(e,t){let r=D[e];t===null?this.storage.remove(r):this.storage.set(r,JSON.stringify(t))}freeSlot(){let{slots:e,unreadable:t}=this.readSlots();for(let r=0;r<e.length;r++)if(e[r]===null&&!t.includes(r))return r;return null}readMintKey(){return this.storage.get(ae)}writeMintKey(e){this.storage.set(ae,e)}clearMintKey(){this.storage.remove(ae)}};var Et=["unknown","signed_out","anonymous","identified","withheld"],P=5,ke=["INVALID_REFRESH_TOKEN"],ve=["expired","revoked","evicted","deleted","reuse","unknown"],Ae=["deleted","revoked","expired"],Se="AMBIGUOUS_HELD_GUEST",It=["MINT","SIGN_IN","LINK","CLAIM","RESTORE","DISCARD","DELETE","SESSION_VERB"],$={SESSION_WITHHELD:"SESSION_WITHHELD",PROJECT_MISMATCH:"PROJECT_MISMATCH"};var We="project";function Ee(s,e){if(s===void 0)return"match";let t=A(e);if(t===null||!Object.prototype.hasOwnProperty.call(t,We))return"unknown";let r=t[We];return r===null?"mismatch":typeof r=="string"&&r===s?"match":"mismatch"}function A(s){if(typeof s!="string"||s.length===0)return null;let e=s.split(".");if(e.length!==3)return null;let t=Rt(e[1]);if(t===null)return null;let r=_t(t);if(r===null)return null;let n;try{n=JSON.parse(r)}catch{return null}return n===null||typeof n!="object"||Array.isArray(n)?null:n}var Tt=(()=>{let s=new Int16Array(128).fill(-1),e="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";for(let t=0;t<e.length;t++)s[e.charCodeAt(t)]=t;return s[45]=62,s[95]=63,s[43]=62,s[47]=63,s})();function Rt(s){let e=s.length;for(;e>0&&s.charCodeAt(e-1)===61;)e--;if(e%4===1)return null;let t=new Uint8Array(Math.floor(e*3/4)),r=0,n=0,i=0;for(let o=0;o<e;o++){let a=s.charCodeAt(o),l=a<128?Tt[a]:-1;if(l<0)return null;r=r<<6|l,n+=6,n>=8&&(n-=8,t[i++]=r>>n&255)}return i===t.length?t:t.subarray(0,i)}function _t(s){let e="",t=0,r=s.length;for(;t<r;){let n=s[t],i,o;if(n<128)i=n,o=0;else if(n>=194&&n<=223)i=n&31,o=1;else if(n>=224&&n<=239)i=n&15,o=2;else if(n>=240&&n<=244)i=n&7,o=3;else return null;if(t+o>=r)return null;for(let a=1;a<=o;a++){let l=s[t+a];if((l&192)!==128)return null;i=i<<6|l&63}if(o===2&&i<2048||o===3&&(i<65536||i>1114111)||i>=55296&&i<=57343)return null;if(i>65535){let a=i-65536;e+=String.fromCharCode(55296+(a>>10),56320+(a&1023))}else e+=String.fromCharCode(i);t+=o+1}return e}var Ve=3e4,bt=5*6e4,Ct=/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;function Ie(s){if(!s||typeof s!="object")return!1;let e=s,t=e.user,r=e.tokens;return!(!t||typeof t.id!="string"||t.id.length===0||!r||typeof r.accessToken!="string"||r.accessToken.length===0||typeof r.refreshToken!="string"||r.refreshToken.length===0||typeof r.expiresIn!="number"||r.expiresIn<=0||t.isAnonymous!==void 0&&typeof t.isAnonymous!="boolean"||t.email!==void 0&&t.email!==null&&typeof t.email!="string"||t.emailVerified!==void 0&&typeof t.emailVerified!="boolean"||t.name!==void 0&&t.name!==null&&typeof t.name!="string"||t.signupMethod!==void 0&&t.signupMethod!==null&&typeof t.signupMethod!="string"||t.lastLoginMethod!==void 0&&t.lastLoginMethod!==null&&typeof t.lastLoginMethod!="string"||t.project!==void 0&&t.project!==null&&typeof t.project!="string"||e.retiredAnonUserId!==void 0&&typeof e.retiredAnonUserId!="string")}var U=class extends Error{constructor(e="An account with this email already exists"){super(e),this.name="EmailAlreadyTakenError"}},Q=class extends Error{constructor(e="Already signed in with an identity; use link*() to add a credential, or sign out first"){super(e),this.name="AlreadyIdentifiedError"}},x=class extends Error{constructor(t="This credential is already linked to a different account",r){super(t);this.code="CREDENTIAL_IN_USE";this.kind="credential_in_use";this.retryable=!1;this.name="CredentialInUseError",this.provider=r?.provider,this.collision=r?.collision,this.status=r?.status}};function Dt(s){let e=s?.error?.details;if(!e||typeof e!="object")return{};let t=e;return{provider:typeof t.provider=="string"?t.provider:void 0,collision:t.collision==="identity"||t.collision==="email"?t.collision:void 0}}function $e(s){let e=s?.error?.details;if(!e||typeof e!="object")return;let t=e.endReason;return typeof t=="string"&&ve.includes(t)?t:void 0}var Pt=new Set(["network","server","rate_limited","account_locked"]);function Lt(s,e){switch(s){case"NETWORK_ERROR":case"NETWORK_TIMEOUT":return"network";case"PARSE_ERROR":case"RESTORE_FAILED":return"server";case"RATE_LIMITED":case"RATE_LIMIT":case"RATE_LIMIT_EXCEEDED":case"QUOTA_EXCEEDED":return"rate_limited";case"ACCOUNT_LOCKED":return"account_locked";case"CREDENTIAL_IN_USE":return"credential_in_use";case"LAST_CREDENTIAL":return"last_credential";case"RECENT_AUTH_REQUIRED":return"recent_auth_required";case"NOT_ANONYMOUS":case"FORBIDDEN_NON_ANONYMOUS":return"already_identified";case"PASSKEY_USER_CANCELLED":case"GAME_CENTER_CANCELLED":case"PLAY_GAMES_CANCELLED":case"SSO_CANCELLED":case"SIGN_IN_SUPERSEDED":case"LINK_SUPERSEDED":case"CLAIM_SUPERSEDED":case"HELD_GUEST_CHANGED":return"cancelled";case"GAME_CENTER_UNAVAILABLE":case"PLAY_GAMES_UNAVAILABLE":case"ENTITLEMENT_ERROR":case"tier_required":case"SESSION_WITHHELD":case"PROJECT_MISMATCH":case"HELD_GUEST_LIMIT":case"HELD_GUEST_PROJECT_MISMATCH":case"UNSUPPORTED_LINK_CREDENTIAL":return"config";case"UNAUTHORIZED":case"INVALID_CREDENTIALS":case"INVALID_REFRESH_TOKEN":case"EMAIL_OTP_INVALID":case"MAGIC_LINK_INVALID":case"PASSKEY_RP_MISMATCH":case"NOT_SIGNED_IN":case"AMBIGUOUS_HELD_GUEST":case"HELD_GUEST_NOT_FOUND":case"HELD_GUEST_GONE":case"NOT_IDENTIFIED":case"CREDENTIAL_STALE":case"MFA_REQUIRED":return"invalid_credential";default:break}if(typeof e=="number"){if(e===429)return"rate_limited";if(e>=500)return"server";if(e>=400)return"invalid_credential"}return"unknown"}var u=class extends Error{constructor(e,t,r){super(t),this.name="AuthError",this.code=e,this.kind=r?.kind??Lt(e,r?.status),this.retryable=Pt.has(this.kind),this.retryAfterSeconds=r?.retryAfterSeconds,this.status=r?.status}},Y=class extends u{constructor(e,t=`Every held-guest slot is occupied (${5}); restore or discard one first`){super("HELD_GUEST_LIMIT",t,{kind:"config"}),this.name="HeldGuestLimitError",this.heldGuests=e}},L=class extends u{constructor(e,t,r){super("HELD_GUEST_PROJECT_MISMATCH",`Held guest ${e} belongs to project ${r??"null"}, not ${t}`,{kind:"config"}),this.name="HeldGuestProjectMismatch",this.userId=e,this.expectedProjectId=t,this.actualProjectId=r}};function Ut(s){if(s instanceof u||s instanceof U||s instanceof Q||s instanceof x)return s;let e=s?.name;return e==="AbortError"||e==="TimeoutError"||e==="NetworkTimeoutError"?new u("NETWORK_TIMEOUT",s instanceof Error?s.message:"timeout",{kind:"network"}):new u("UNKNOWN_ERROR",s instanceof Error?s.message:String(s),{kind:"unknown"})}function p(s){let e=s.error?.status,t=s.error?.details?.retryAfterSeconds;return{status:typeof e=="number"?e:void 0,retryAfterSeconds:typeof t=="number"&&Number.isFinite(t)&&t>0?t:void 0}}var J=class{constructor(e,t,r,n,i,o,a={}){this.state="unknown";this.record=null;this.user=null;this.accessToken=null;this.accessExpiresAt=0;this.withheld=null;this.clockSkewConfirmed=!1;this.inflight=Promise.resolve();this.refreshInflight=null;this.attemptInFlight=!1;this.refreshFailureCount=0;this.refreshCooldownUntil=0;this.visibilityResetUnsub=null;this.proactiveRefreshTimer=null;this.proactiveRefreshCleanup=null;this.storageEventUnsub=null;this.rehydrateScheduled=!1;this.takeoverListeners=new Set;this.lastTakeover=null;this.deletionCancelledListeners=new Set;this.lastDeletionCancelled=null;this.lastAnonRetirement=null;this.authStateListeners=new Set;this.identityWithheldListeners=new Set;this.hydrated=!1;this.http=t,this.storage=r,this.store=new V(r),this.analytics=n,this.flags=i,this.chatbot=o,this.hooks=a,this.expectedProjectId=e.expectedProjectId,this.slotProjectAnchor=e.expectedProjectId??e.projectId,this.autoRestoreHeldGuest=e.autoRestoreHeldGuest!==!1,this.hydrateFromDisk("boot"),this.hydrated=!0,this.startStorageEventRehydrate()}status(){return this.state}authStateReady(){return Promise.resolve(this.state)}getCurrentUser(){return this.user}getUserSync(){return this.user}isReady(){return this.hydrated}onDeviceTakeover(e){return this.takeoverListeners.add(e),()=>{this.takeoverListeners.delete(e)}}getLastDeviceTakeover(){return this.lastTakeover}onAuthStateChanged(e){if(this.authStateListeners.add(e),this.hydrated){let t=this.user,r={event:"initial",status:this.state,user:t,...this.withheld?{withheld:this.withheld.info}:{}};try{e(r)}catch{}if(t)try{e({event:"signed_in",user:t})}catch{}}return()=>{this.authStateListeners.delete(e)}}onIdentityWithheld(e){return this.identityWithheldListeners.add(e),()=>{this.identityWithheldListeners.delete(e)}}emitAuthState(e){for(let t of this.authStateListeners)try{t(e)}catch{}}fireDeviceTakeover(e,t){if(!e||!Ct.test(e))return;let r={retiredAnonUserId:e,identifiedUserId:t,at:new Date};this.lastTakeover=r;for(let n of this.takeoverListeners)try{n(r)}catch{}this.emitAuthState({event:"device_takeover",user:this.user,retiredAnonUserId:e})}onDeletionCancelled(e){return this.deletionCancelledListeners.add(e),()=>{this.deletionCancelledListeners.delete(e)}}getLastDeletionCancelled(){return this.lastDeletionCancelled}getLastAnonRetirement(){return this.lastAnonRetirement}fireDeletionCancelled(e){let t={userId:e,at:new Date};this.lastDeletionCancelled=t;for(let r of this.deletionCancelledListeners)try{r(t)}catch{}this.emitAuthState({event:"deletion_cancelled",user:this.user})}recordServerSignals(e){e.anonRetirement&&(this.lastAnonRetirement=e.anonRetirement),e.retiredAnonUserId&&this.fireDeviceTakeover(e.retiredAnonUserId,e.user.id),e.reactivatedFromDeletion&&this.fireDeletionCancelled(e.user.id)}commit(e){switch(e.type){case"install":return this.commitInstall(e);case"clear":return this.commitClear(e);case"user":{if(this.currentSid()!==e.expectSid||!this.record)return!1;let t={...this.record,user:e.user};return this.record=t,this.user=e.user,this.store.writeSession(t),this.analytics.identify(e.user.id),this.flags.setContext({userId:e.user.id}),this.emitAuthState({event:"user_updated",user:e.user,cause:e.cause}),!0}case"release":{let t=this.store.readSlot(e.index);return t?(this.store.writeSlot(e.index,null),this.emitAuthState({event:"guest_released",userId:t.userId,reason:e.reason,...e.endReason?{endReason:e.endReason}:{}}),!0):!1}case"slot_tokens":{let t=this.store.readSlot(e.index);return!t||t.refreshToken!==e.sent?!1:(this.store.writeSlot(e.index,{...t,refreshToken:e.refreshToken,...e.project!==void 0&&t.project===null?{project:e.project}:{}}),!0)}case"withhold":return this.commitWithhold(e);case"unknown":return this.state="unknown",this.record=null,this.user=null,this.withheld=null,this.accessToken=e.accessToken,this.accessExpiresAt=e.accessExpiresAt,this.startProactiveRefreshCron(),this.startVisibilityRefreshReset(),!0;case"held_reported":{if(!this.record?.heldReportPending?.includes(e.userId))return!1;let t=this.record.heldReportPending.filter(n=>n!==e.userId),r={...this.record};return t.length>0?r.heldReportPending=t:delete r.heldReportPending,this.record=r,this.store.writeSession(r),!0}default:return!1}}commitInstall(e){if(e.expectSid!==void 0&&this.currentSid()!==e.expectSid||e.expectRefresh!==void 0&&this.store.currentRefresh()!==e.expectRefresh)return!1;let t=this.record,r=t?.user??null,n=r?.id!==e.record.user.id,i=null,o={...e.record};if(e.hold){let a=this.store.freeSlot();if(a===null)return!1;this.store.writeSlot(a,e.hold),i=this.heldCount();let l=new Set(t?.heldReportPending??[]);l.add(e.hold.userId),o.heldReportPending=[...l]}else t?.heldReportPending&&!o.heldReportPending&&!n&&(o.heldReportPending=t.heldReportPending);switch(r&&n&&(this.analytics.reset(!1),this.flags.reset(),this.chatbot.newSession(),e.revokePrevious&&t&&!r.isAnonymous&&this.revokeFireAndForget(t.refreshToken)),this.state=o.user.isAnonymous===!1?"identified":"anonymous",this.record=o,this.user=o.user,this.accessToken=o.accessToken,this.accessExpiresAt=o.accessExpiresAt,this.withheld=null,n&&(this.clockSkewConfirmed=!1,this.lastTakeover=null,this.lastDeletionCancelled=null,this.lastAnonRetirement=null),(e.reason!=="hydrate"||e.persist!==!1)&&this.store.writeSession(o),this.analytics.identify(o.user.id),this.flags.setContext({userId:o.user.id}),this.startProactiveRefreshCron(),this.startVisibilityRefreshReset(),this.refreshFailureCount=0,this.refreshCooldownUntil=0,e.hold&&i!==null&&this.emitAuthState({event:"guest_held",userId:e.hold.userId,count:i}),e.reason){case"mint":this.emitAuthState({event:"signed_in",user:o.user,cause:"mint"});break;case"sign_in":this.emitAuthState({event:"signed_in",user:o.user,cause:"sign_in"});break;case"upgrade":this.emitAuthState({event:"signed_in",user:o.user,cause:"link"});break;case"link":this.emitAuthState({event:"user_updated",user:o.user,cause:"link"});break;case"restore":this.emitAuthState({event:"signed_in",user:o.user,cause:"restore"});break;case"claim":this.emitAuthState({event:"user_updated",user:o.user,cause:"merge"});break;case"recover":this.emitAuthState({event:"signed_in",user:o.user});break;case"rehydrate":n&&this.emitAuthState({event:"signed_in",user:o.user});break;case"refresh":r&&JSON.stringify(r)!==JSON.stringify(o.user)&&this.emitAuthState({event:"user_updated",user:o.user,cause:"refresh"});break;case"hydrate":break;default:break}return e.release&&this.commit({type:"release",index:e.release.index,reason:e.release.reason}),e.hold&&this.reportHeld(e.hold.userId,e.hold.refreshToken),!0}commitClear(e){let t=this.record?.refreshToken??this.withheld?.refreshToken??this.store.currentRefresh();if(e.expectRefresh!==void 0&&this.store.currentRefresh()!==e.expectRefresh)return!1;let r=this.state!=="signed_out";if(this.state="signed_out",this.record=null,this.user=null,this.accessToken=null,this.accessExpiresAt=0,this.withheld=null,this.clockSkewConfirmed=!1,this.lastTakeover=null,this.lastDeletionCancelled=null,this.lastAnonRetirement=null,this.store.clearSession(),e.stampNoAutoRestore){let{slots:n}=this.store.readSlots();n.forEach((i,o)=>{i&&i.autoRestore&&this.store.writeSlot(o,{...i,autoRestore:!1})})}return e.keepAnalyticsIdentity||this.analytics.reset(e.reason==="user"||e.reason==="account_deleted"),e.dropQueue&&this.analytics.dropQueue(),this.flags.reset(),this.chatbot.newSession(),this.stopProactiveRefreshCron(),this.stopVisibilityRefreshReset(),this.refreshFailureCount=0,this.refreshCooldownUntil=0,e.revoke&&t&&this.revokeFireAndForget(t),r&&this.emitAuthState(e.endReason!==void 0?{event:"signed_out",user:null,reason:e.reason,endReason:e.endReason}:{event:"signed_out",user:null,reason:e.reason}),!0}commitWithhold(e){if(e.from==="refresh"){if(!e.rotation||this.store.currentRefresh()!==e.rotation.sent)return!1;this.record?this.store.writeSession({...this.record,accessToken:e.rotation.accessToken,accessExpiresAt:e.rotation.accessExpiresAt,refreshToken:e.rotation.refreshToken}):this.store.writeLimboTokens(e.rotation)}this.state="withheld",this.record=null,this.user=null,this.accessToken=null,this.accessExpiresAt=0,this.withheld={info:e.info,refreshToken:e.rotation?.refreshToken??e.refreshToken},this.stopProactiveRefreshCron(),this.stopVisibilityRefreshReset();try{this.hooks.onIdentityWithheld?.()}catch{}for(let t of this.identityWithheldListeners)try{t()}catch{}return e.from==="refresh"&&this.emitAuthState({event:"session_withheld",reason:"project_mismatch",expectedProjectId:e.info.expectedProjectId,actualProjectId:e.info.actualProjectId,userId:e.info.userId}),!0}hydrateFromDisk(e){let t=this.store.readDisk(),r=t.legacy.refreshToken,n=V.recordTrusted(t),i=t.record!==null&&!n,o=t.legacy.user,a=n?o&&o.id===t.record.user.id?o:t.record.user:o,l=t.legacy.accessToken??(n?t.record.accessToken:null),d=t.legacy.accessToken?t.legacy.accessExpiresAt:n?t.record.accessExpiresAt:0;if(!r){if((a||i||t.legacy.userUnreadable||t.recordUnreadable)&&this.store.clearStaleBlob(),e==="boot"){this.state="signed_out";return}this.state!=="signed_out"&&this.commit({type:"clear",reason:"user",revoke:!1,dropQueue:!1,stampNoAutoRestore:!1});return}if(!a){if(e==="storage_event"&&this.record&&this.record.refreshToken===r)return;i&&this.store.clearRecord(),this.commit({type:"unknown",accessToken:l,accessExpiresAt:d});return}let h=this.judge(l);if(h==="mismatch"){this.commit({type:"withhold",from:"hydrate",info:this.withheldInfo(a,l),refreshToken:r});return}if(h==="unknown"){this.commit({type:"unknown",accessToken:l,accessExpiresAt:d});return}let g={v:1,user:a,accessToken:l,accessExpiresAt:d,refreshToken:r,...t.record?.heldReportPending?{heldReportPending:t.record.heldReportPending}:{}};if(e==="storage_event"&&this.record&&this.record.refreshToken===r&&this.record.user.id===a.id)return;let k=!n||JSON.stringify(t.record.user)!==JSON.stringify(a)||t.record.accessToken!==l;if(this.commit({type:"install",reason:e==="boot"?"hydrate":"rehydrate",record:g,persist:k}),e==="boot"){let{slots:v}=this.store.readSlots();v.forEach((m,y)=>{m&&m.userId===a.id&&this.store.writeSlot(y,null)});for(let m of g.heldReportPending??[]){let y=this.store.readSlots().slots.find(N=>N?.userId===m);y?this.reportHeld(m,y.refreshToken):this.commit({type:"held_reported",userId:m})}}}startStorageEventRehydrate(){if(typeof window>"u"||typeof window.addEventListener!="function"||!this.storage.isPersistent())return;let e=t=>{let r=t.key===null?null:this.storage.relativeKey(t.key);t.key!==null&&(r===null||!r.startsWith("auth_"))||this.rehydrateScheduled||(this.rehydrateScheduled=!0,setTimeout(()=>{this.rehydrateScheduled=!1,this.hydrateFromDisk("storage_event")},0))};window.addEventListener("storage",e),this.storageEventUnsub=()=>window.removeEventListener("storage",e)}stopStorageEventRehydrate(){this.storageEventUnsub&&(this.storageEventUnsub(),this.storageEventUnsub=null)}currentSid(){let e=this.record?.accessToken;if(!e)return null;let t=A(e)?.sid;return typeof t=="string"?t:null}judge(e){return Ee(this.expectedProjectId,e)}projectClaim(e){let t=A(e)?.project;return typeof t=="string"?t:null}withheldInfo(e,t){return{reason:"project_mismatch",expectedProjectId:this.expectedProjectId??"",actualProjectId:this.projectClaim(t),userId:e.id,isAnonymous:e.isAnonymous!==!1}}heldCount(){return this.store.readSlots().slots.filter(e=>e!==null).length}buildHeld(e){let t=A(e.accessToken)?.sid;return{v:1,userId:e.user.id,sid:typeof t=="string"?t:"",refreshToken:e.refreshToken,tokenAtHold:e.refreshToken,heldAt:Math.max(Date.now(),...this.store.readSlots().slots.map(r=>r?r.heldAt+1:0)),project:this.projectClaim(e.accessToken),autoRestore:!0}}revokeFireAndForget(e){this.http.post("/auth-service/token/revoke",{refreshToken:e}).catch(()=>{})}reportHeld(e,t){this.http.post("/auth-service/guest/held",{refreshToken:t}).then(r=>{r.success&&this.commit({type:"held_reported",userId:e})}).catch(()=>{})}withheldError(){return new u($.SESSION_WITHHELD,"The stored session belongs to a different project and is withheld; call discardWithheld() or re-init with the matching expectedProjectId",{kind:"config"})}canServeToken(e,t,r){return!e||!t||r>=t-Ve?!1:this.clockSkewConfirmed?!0:Xe(e,r)}canServeCachedToken(e){return this.canServeToken(this.accessToken,this.accessExpiresAt,e)}trackedDeadlineAlive(e){return!!this.accessToken&&!!this.accessExpiresAt&&e<this.accessExpiresAt-Ve}deadlinesDisagree(e){return this.trackedDeadlineAlive(e)&&!this.canServeCachedToken(e)}learnClockSkewFrom(e,t){Xe(e,t)||(this.clockSkewConfirmed=!0)}async refreshAndReconcile(e){let t=this.deadlinesDisagree(e),r=await this.refreshAccessToken();return t&&r&&this.learnClockSkewFrom(r,Date.now()),r}async getAccessToken(e){return this.state==="withheld"?null:!e?.forceRefresh&&this.state!=="unknown"&&this.canServeCachedToken(Date.now())?this.accessToken:this.store.currentRefresh()?this.refreshInflight?this.refreshInflight:Date.now()<this.refreshCooldownUntil?null:this.refreshAndReconcile(Date.now()):null}getAccessTokenSync(){return this.accessToken}getRefreshToken(){return this.state==="withheld"?null:this.store.currentRefresh()}async refreshAccessToken(){if(this.refreshInflight)return this.refreshInflight;let e=this.store.currentRefresh();return e?(this.refreshInflight=(async()=>{try{return await this.performRefresh(e)}finally{this.refreshInflight=null}})(),this.refreshInflight):null}async performRefresh(e){try{let t=await this.http.post("/auth-service/token/refresh",{refreshToken:e});if(!t.success)return qe(t.error?.code)?(this.store.currentRefresh()===e&&this.commit({type:"clear",reason:"session_expired",endReason:$e(t),expectRefresh:e,revoke:!1,dropQueue:!1,stampNoAutoRestore:!1}),this.refreshFailureCount=0,this.refreshCooldownUntil=0,null):(this.armBackoff(),null);let r=q(t.data);if(!r)return this.armBackoff(),null;if(this.store.currentRefresh()!==e)return null;let n=Date.now()+r.expiresIn*1e3,i=this.judge(r.accessToken);if(i==="mismatch"){let a=this.record?.user??B(t.data);return this.commit({type:"withhold",from:"refresh",info:this.withheldInfo(a??{id:Ye(r.accessToken)??"",email:null,emailVerified:!1,name:null,isAnonymous:!0},r.accessToken),refreshToken:r.refreshToken,rotation:{sent:e,accessToken:r.accessToken,refreshToken:r.refreshToken,accessExpiresAt:n}}),null}let o=B(t.data);return this.record?this.commit({type:"install",reason:"refresh",record:{...this.record,user:o??this.record.user,accessToken:r.accessToken,accessExpiresAt:n,refreshToken:r.refreshToken},expectRefresh:e}):i==="match"&&o?this.commit({type:"install",reason:"recover",record:{v:1,user:o,accessToken:r.accessToken,accessExpiresAt:n,refreshToken:r.refreshToken},expectRefresh:e}):(this.store.writeLimboTokens({accessToken:r.accessToken,refreshToken:r.refreshToken,accessExpiresAt:n}),this.accessToken=r.accessToken,this.accessExpiresAt=n),this.refreshFailureCount=0,this.refreshCooldownUntil=0,r.accessToken}catch{return this.armBackoff(),null}}async refreshHeld(e,t){let r=t.refreshToken,n=await this.http.post("/auth-service/token/refresh",{refreshToken:r});if(!n.success){if(qe(n.error?.code)){let l=$e(n);if(l&&Ae.includes(l))return this.commit({type:"release",index:e,reason:"dead",endReason:l}),{kind:"dead",endReason:l};throw new u("RESTORE_FAILED",`The held guest's token was refused${l?` (${l})`:" with no end reason"}; the slot is kept \u2014 retry later`,{status:p(n).status,kind:"server"})}throw new u(n.error?.code??"RESTORE_FAILED",n.error?.message??"Could not refresh the held guest",p(n))}let i=q(n.data);if(!i)throw new u("RESTORE_FAILED","Malformed refresh response for the held guest; the slot is kept",{kind:"server"});let o=B(n.data)?.id??A(i.accessToken)?.sub;if(typeof o=="string"&&o&&o!==t.userId)throw new u("HELD_GUEST_IDENTITY_MISMATCH","The held guest's refresh was answered for a different account; nothing was changed",{kind:"unknown"});if(!this.commit({type:"slot_tokens",index:e,sent:r,refreshToken:i.refreshToken,...t.project===null?{project:this.projectClaim(i.accessToken)}:{}}))throw new u("HELD_GUEST_CHANGED","The held slot changed while its token was in flight",{kind:"cancelled"});return{kind:"ok",tokens:i,user:B(n.data)}}async settle(){for(;this.state==="unknown";){if(!this.store.currentRefresh()){this.commit({type:"clear",reason:"user",revoke:!1,dropQueue:!1,stampNoAutoRestore:!1});return}if(await this.refreshAccessToken(),this.state!=="unknown")return;let e=Math.min(3e4,Math.max(250,this.refreshCooldownUntil-Date.now()));await new Promise(t=>setTimeout(t,e))}}armBackoff(){this.refreshFailureCount+=1;let e=Math.min(3e4,1e3*Math.pow(2,this.refreshFailureCount-1));this.refreshCooldownUntil=Date.now()+e}resetRefreshState(){this.refreshFailureCount=0,this.refreshCooldownUntil=0}startVisibilityRefreshReset(){if(this.visibilityResetUnsub||typeof document>"u")return;let e=()=>{document.visibilityState==="visible"&&this.resetRefreshState()};document.addEventListener("visibilitychange",e),this.visibilityResetUnsub=()=>document.removeEventListener("visibilitychange",e)}stopVisibilityRefreshReset(){this.visibilityResetUnsub&&(this.visibilityResetUnsub(),this.visibilityResetUnsub=null)}startProactiveRefreshCron(){if(typeof window>"u"||this.proactiveRefreshTimer)return;let e=.8,t=6e4,r=3e4,n=async()=>{if(this.attemptInFlight||this.state==="withheld")return;if(this.state==="unknown"){Date.now()>=this.refreshCooldownUntil&&await this.refreshAccessToken();return}if(!this.accessToken||!this.accessExpiresAt)return;let o=Date.now();if(!this.canServeCachedToken(o)){await this.refreshAndReconcile(o);return}let a=this.accessExpiresAt-o;if(a<=0)return;let d=Math.max(a,5*6e4)*(1-e)+(Math.random()*r*2-r);a<=d&&await this.refreshAccessToken()};this.proactiveRefreshTimer=window.setInterval(()=>{n()},t);let i=()=>{typeof document<"u"&&document.visibilityState==="visible"&&n()};typeof document<"u"&&document.addEventListener("visibilitychange",i),this.proactiveRefreshCleanup=()=>{this.proactiveRefreshTimer&&(window.clearInterval(this.proactiveRefreshTimer),this.proactiveRefreshTimer=null),typeof document<"u"&&document.removeEventListener("visibilitychange",i)}}stopProactiveRefreshCron(){this.proactiveRefreshCleanup&&(this.proactiveRefreshCleanup(),this.proactiveRefreshCleanup=null)}serialize(e){let t=async()=>{try{return await e()}catch(n){throw Ut(n)}},r=this.inflight.then(t,t);return this.inflight=r.catch(()=>{}),r}async bearerHeaders(){if(this.state==="withheld")throw this.withheldError();let e=await this.getAccessToken();if(!e)throw new u("NOT_SIGNED_IN","Not signed in");return{Authorization:`Bearer ${e}`}}signInAnonymously(e){return this.serialize(async()=>{if(this.state==="withheld")throw this.withheldError();if(this.state==="unknown"&&await this.settle(),this.status()==="withheld")throw this.withheldError();let{slots:t}=this.store.readSlots(),r=t.filter(l=>l!==null),n=this.record;if(n&&!e?.forceNew)return n.user;let i=r.length+(n&&n.user.isAnonymous?1:0);if(e?.forceNew){if(i>=5)throw new Y(r.length);return this.mintFresh(e,n)}let o=r.map(l=>({slot:l,index:t.indexOf(l)})).filter(({slot:l})=>l.autoRestore&&!this.slotProjectMismatches(l)).sort((l,d)=>d.slot.heldAt-l.slot.heldAt);if(o.length>0&&(this.autoRestoreHeldGuest||i>=5))for(let{slot:l,index:d}of o)try{let h=await this.restoreSlot(d,l,"mint");if(h)return h}catch(h){if(h instanceof L)continue;throw h}let a=this.heldCount();if(a>=5)throw new Y(a);return this.mintFresh(e,null)})}ensureSession(){return this.signInAnonymously()}slotProjectMismatches(e){let t=this.slotProjectAnchor;return t!==void 0&&e.project!==null&&e.project!==t}async mintFresh(e,t){let r=this.currentSid(),n=this.store.readMintKey()??xt();this.store.writeMintKey(n),this.attemptInFlight=!0;try{await this.refreshInflight;let i=await this.http.post("/auth-service/anonymous",{name:e?.name,metadata:e?.metadata,mintKey:n});if(!i.success||!Ie(i.data))throw new u(i.error?.code??"AUTH_ERROR",i.error?.message??"Anonymous signup failed",p(i));let o=i.data;this.guardMinted(o),await this.refreshInflight;let a=this.record,l=a&&a.user.isAnonymous&&t?this.buildHeld(a):void 0;if(!this.commit({type:"install",reason:"mint",record:Te(o),expectSid:r,hold:l,revokePrevious:!!a&&!a.user.isAnonymous}))throw this.revokeFireAndForget(o.tokens.refreshToken),new u("SIGN_IN_SUPERSEDED","The session changed while the mint was in flight; nothing was installed",{kind:"cancelled"});return this.store.clearMintKey(),this.recordServerSignals(o),o.user}finally{this.attemptInFlight=!1}}guardMinted(e){if(this.judge(e.tokens.accessToken)!=="match")throw this.revokeFireAndForget(e.tokens.refreshToken),new u($.PROJECT_MISMATCH,`The server answered for project ${this.projectClaim(e.tokens.accessToken)??"null"}, not expectedProjectId ${this.expectedProjectId??""}; nothing was installed`,{kind:"config"})}async performSwitch(e,t,r){if(this.state==="withheld")throw this.withheldError();if(this.state==="unknown"&&await this.settle(),this.status()==="withheld")throw this.withheldError();let n=this.currentSid();this.attemptInFlight=!0;try{await this.refreshInflight;let i=await e();if(!i.success||!i.data)throw new u(i.error?.code??t,i.error?.message??r,p(i));let o=i.data;if(o.mfaRequired===!0&&typeof o.mfaChallengeToken=="string"){let g=o.user;return{kind:"mfa",challengeToken:o.mfaChallengeToken,userId:g?.id??""}}if(!Ie(i.data))throw new u(i.error?.code??t,i.error?.message??r,p(i));let a=i.data;this.guardMinted(a),this.record&&await this.analytics.flush().catch(()=>{}),await this.refreshInflight;let l=this.record,d=l&&l.user.isAnonymous&&l.user.id!==a.user.id?this.buildHeld(l):void 0;if(!this.commit({type:"install",reason:"sign_in",record:Te(a),expectSid:n,hold:d,revokePrevious:!!l&&!l.user.isAnonymous&&l.user.id!==a.user.id}))throw this.revokeFireAndForget(a.tokens.refreshToken),new u("SIGN_IN_SUPERSEDED","The session changed while the sign-in was in flight; nothing was installed",{kind:"cancelled"});return this.recordServerSignals(a),{kind:"done",user:a.user,previous:l?{userId:l.user.id,isAnonymous:l.user.isAnonymous!==!1,held:!!d}:null,reactivated:a.reactivatedFromDeletion===!0}}finally{this.attemptInFlight=!1}}signIn(e,t){return this.serialize(async()=>{let r=await this.performSwitch(()=>this.http.post("/auth-service/login",{email:e,password:t}),"AUTH_ERROR","Login failed");return r.kind==="mfa"?{mfaRequired:!0,mfaChallengeToken:r.challengeToken,userId:r.userId}:r.user})}challengeMfa(e,t){return this.serialize(async()=>{let r=await this.performSwitch(()=>this.http.post("/auth-service/mfa/challenge",{challengeToken:e,code:t}),"MFA_CHALLENGE_FAILED","Invalid MFA code");if(r.kind==="mfa")throw new u("MFA_CHALLENGE_FAILED","MFA challenge returned another challenge");return r.user})}loginSocial(e){return this.serialize(async()=>{let{link:t,onCredentialInUse:r,...n}=e,i=n,o=()=>this.performSwitch(()=>this.http.post("/auth-service/login/social",i),"SOCIAL_LOGIN_FAILED","Social login failed");if(t){if(this.state==="withheld")throw this.withheldError();if(this.state==="unknown"&&await this.settle(),this.state==="anonymous"||this.state==="identified"){let l=await this.performLink("/auth-service/me/link/social",i,"upgrade");if(l.kind==="done")return l.user;if(l.kind==="recent_auth_required")throw new u("RECENT_AUTH_REQUIRED",l.message??"Re-authenticate to link this credential",{status:l.status??403});if(r==="adopt"){let d=await o();if(d.kind==="mfa")throw new u("MFA_REQUIRED","This account requires MFA; use signIn()/challengeMfa()");return d.user}throw new x(l.message,{provider:l.provider,collision:l.collision,status:l.status})}}let a=await o();if(a.kind==="mfa")throw new u("MFA_REQUIRED","This account requires MFA; use signIn()/challengeMfa()");return a.user})}signInWithGoogle(e,t,r){return this.loginSocial({provider:"google",code:e,redirectUri:t,link:r})}signInWithGitHub(e,t){return this.loginSocial({provider:"github",code:e,redirectUri:t})}signInWithApple(e){return this.loginSocial({provider:"apple",...e})}signInWithMicrosoft(e,t){return this.loginSocial({provider:"microsoft",code:e,redirectUri:t})}signInWithLinkedIn(e,t){return this.loginSocial({provider:"linkedin",code:e,redirectUri:t})}signInWithFacebook(e,t){return this.loginSocial({provider:"facebook",code:e,redirectUri:t})}signInWithDiscord(e,t){return this.loginSocial({provider:"discord",code:e,redirectUri:t})}signInWith(e){return this.serialize(async()=>{let{path:t,body:r}=Be(e),n=await this.performSwitch(()=>this.http.post(t,r),"AUTH_ERROR","Sign-in failed");if(n.kind==="mfa"){let i=n.challengeToken;return{status:"mfa_required",challengeToken:i,verify:o=>this.signInWith({kind:"mfa",challengeToken:i,code:o})}}return{status:"done",user:n.user,previous:n.previous,reactivated:n.reactivated}})}async performLink(e,t,r){if(this.state==="withheld")throw this.withheldError();let n=this.currentSid();this.attemptInFlight=!0;try{await this.refreshInflight;let i=await this.bearerHeaders(),o=await this.http.post(e,t,i);if(!o.success||!o.data?.user){let d=o.error?.code??"LINK_FAILED",h=p(o);if(d==="CREDENTIAL_IN_USE"){let g=Dt(o);return{kind:"credential_in_use",provider:g.provider??"",collision:g.collision??"identity",status:h.status,message:o.error?.message}}if(d==="RECENT_AUTH_REQUIRED")return{kind:"recent_auth_required",status:h.status,message:o.error?.message};throw new u(d,o.error?.message??"Failed to link credential",h)}let a=o.data,l=o.data.user;if(a.upgraded&&Ie(a)){if(this.guardMinted(a),await this.refreshInflight,!this.commit({type:"install",reason:r,record:Te(a),expectSid:n}))throw this.revokeFireAndForget(a.tokens.refreshToken),new u("LINK_SUPERSEDED","The session changed while the link was in flight; nothing was installed",{kind:"cancelled"});return{kind:"done",user:a.user,upgraded:!0,alreadyLinked:!1}}return a.alreadyLinked?{kind:"done",user:l,upgraded:!1,alreadyLinked:!0}:(this.commit({type:"user",user:l,cause:"link",expectSid:n}),{kind:"done",user:l,upgraded:!1,alreadyLinked:!1})}finally{this.attemptInFlight=!1}}link(e){return this.serialize(async()=>{if(this.state==="withheld")throw this.withheldError();if(this.state==="unknown"&&await this.settle(),this.status()==="withheld")throw this.withheldError();if(this.state==="signed_out"){let i=await this.signInWithUnserialized(e);if(i.status!=="done")throw new u("MFA_REQUIRED","This account requires MFA; use signInWith() and complete the challenge");return{status:"done",user:i.user,upgraded:!1,alreadyLinked:!1}}let t=ze(e),r=await this.performLink(t.path,t.body,"link");if(r.kind==="done")return{status:"done",user:r.user,upgraded:r.upgraded,alreadyLinked:r.alreadyLinked};if(r.kind==="recent_auth_required")return{status:"recent_auth_required"};let n=Date.now();return{status:"credential_in_use",provider:r.provider,collision:r.collision,switchAccount:()=>Date.now()-n>bt?Promise.reject(new u("CREDENTIAL_STALE","The refused credential is older than 5 minutes; obtain it again and call signInWith()")):this.signInWith(e),keepCurrent:()=>{}}})}async signInWithUnserialized(e){let{path:t,body:r}=Be(e),n=await this.performSwitch(()=>this.http.post(t,r),"AUTH_ERROR","Sign-in failed");if(n.kind==="mfa"){let i=n.challengeToken;return{status:"mfa_required",challengeToken:i,verify:o=>this.signInWith({kind:"mfa",challengeToken:i,code:o})}}return{status:"done",user:n.user,previous:n.previous,reactivated:n.reactivated}}signUp(e,t,r){return this.serialize(async()=>{if(this.state==="withheld")throw this.withheldError();if(this.state==="unknown"&&await this.settle(),this.status()==="withheld")throw this.withheldError();if(this.state==="identified")throw new Q;if(this.state==="anonymous"){let i=await this.performLink("/auth-service/me/link/email",{email:e,password:t},"upgrade");if(i.kind==="done")return i.user;throw i.kind==="credential_in_use"?new U(i.message):new u("RECENT_AUTH_REQUIRED",i.message??"Re-authenticate first",{status:i.status??403})}let n=await this.performSwitch(async()=>{let i=await this.http.post("/auth-service/signup",{email:e,password:t,name:r?.name,metadata:r?.metadata});if(!i.success&&i.error?.code==="CONFLICT")throw new U(i.error.message);return i},"AUTH_ERROR","Signup failed");if(n.kind==="mfa")throw new u("MFA_REQUIRED","Unexpected MFA challenge on signup");return n.user})}linkEmailPassword(e,t){return this.linkLegacy({kind:"password",email:e,password:t})}linkSocial(e){let{provider:t,...r}=e;return this.linkLegacy({kind:t,...r})}linkGoogle(e){return this.linkSocial({provider:"google",...e})}linkApple(e){return this.linkSocial({provider:"apple",...e})}linkLegacy(e){return this.serialize(async()=>{if(this.state==="withheld")throw this.withheldError();if(this.state==="unknown"&&await this.settle(),this.status()==="withheld")throw this.withheldError();if(this.state==="signed_out")throw new u("NOT_SIGNED_IN","Sign in before linking a credential");let t=ze(e),r=await this.performLink(t.path,t.body,"link");if(r.kind==="done")return r.user;throw r.kind==="recent_auth_required"?new u("RECENT_AUTH_REQUIRED",r.message??"Re-authenticate to link this credential",{status:r.status??403}):new x(r.message,{provider:r.provider,collision:r.collision,status:r.status})})}getHeldGuests(){return this.store.readSlots().slots.filter(e=>e!==null).sort((e,t)=>t.heldAt-e.heldAt).map(({userId:e,heldAt:t,autoRestore:r,project:n})=>({userId:e,heldAt:t,autoRestore:r,project:n}))}getHeldGuest(){return this.getHeldGuests()[0]??null}resolveSlot(e){let{slots:t}=this.store.readSlots(),r=t.map((n,i)=>n?{slot:n,index:i}:null).filter(n=>n!==null);if(r.length===0)throw new u("HELD_GUEST_NOT_FOUND","No guest is held on this device");if(e!==void 0){let n=r.find(i=>i.slot.userId===e);if(!n)throw new u("HELD_GUEST_NOT_FOUND",`No held guest with id ${e}`);return n}if(r.length>1)throw new u(Se,`${r.length} guests are held; pass the userId of the one you mean`);return r[0]}claimHeldGuest(e){return this.serialize(async()=>{if(this.state==="withheld")throw this.withheldError();if(this.state!=="identified"||!this.record)throw new u("NOT_IDENTIFIED","claimHeldGuest() needs a signed-in identified account as the merge target");let{index:t,slot:r}=this.resolveSlot(e),n=this.currentSid();this.attemptInFlight=!0;try{await this.refreshInflight;let i=await this.refreshHeld(t,r);if(i.kind==="dead")throw new u("HELD_GUEST_GONE",`Held guest ${r.userId} is no longer available (${i.endReason})`);let o=this.store.currentRefresh();if(!o)throw new u("NOT_SIGNED_IN","Not signed in");let a=await this.http.post("/auth-service/merge",{anonymousRefreshToken:i.tokens.refreshToken,targetRefreshToken:o});if(!a.success||!a.data)throw new u(a.error?.code??"MERGE_FAILED",a.error?.message??"Merge failed",p(a));let l=q(a.data),d=Qe(a.data,this.record.user.id,r.userId);await this.refreshInflight;let h=this.record;if(!l||!h)throw this.commit({type:"release",index:t,reason:"claimed"}),new u("MERGE_FAILED","Merge succeeded but returned no rotated session; sign in again",{kind:"server"});if(!this.commit({type:"install",reason:"claim",record:{...h,accessToken:l.accessToken,accessExpiresAt:Date.now()+l.expiresIn*1e3,refreshToken:l.refreshToken},expectSid:n,expectRefresh:o,release:{index:t,reason:"claimed"}}))throw this.commit({type:"release",index:t,reason:"claimed"}),new u("CLAIM_SUPERSEDED","The session changed while the claim was in flight",{kind:"cancelled"});return{user:this.record.user,stats:d}}finally{this.attemptInFlight=!1}})}restoreHeldGuest(e){return this.serialize(async()=>{if(this.state==="withheld")throw this.withheldError();if(this.state==="unknown"&&await this.settle(),this.status()==="withheld")throw this.withheldError();let{index:t,slot:r}=this.resolveSlot(e),n=await this.restoreSlot(t,r,"verb");if(!n)throw new u("HELD_GUEST_GONE",`Held guest ${r.userId} is no longer available`);return n})}async restoreSlot(e,t,r){let n=this.slotProjectAnchor;if(n!==void 0&&t.project!==null&&t.project!==n)throw new L(t.userId,n,t.project);let i=this.currentSid();this.attemptInFlight=!0;try{await this.refreshInflight;let o=await this.refreshHeld(e,t);if(o.kind==="dead")return null;if(this.judge(o.tokens.accessToken)!=="match")throw new L(t.userId,this.expectedProjectId??n??"",this.projectClaim(o.tokens.accessToken));let l=o.user??Je(o.tokens.accessToken,t.userId);await this.refreshInflight;let d=this.record,h=d&&d.user.isAnonymous&&d.user.id!==l.id?this.buildHeld(d):void 0;if(!this.commit({type:"install",reason:"restore",record:{v:1,user:l,accessToken:o.tokens.accessToken,accessExpiresAt:Date.now()+o.tokens.expiresIn*1e3,refreshToken:o.tokens.refreshToken},expectSid:i,hold:h,release:{index:e,reason:"restored"},revokePrevious:!!d&&!d.user.isAnonymous}))throw new u("SIGN_IN_SUPERSEDED",`The session changed while restoring${r==="mint"?" (auto-restore)":""}; nothing was installed`,{kind:"cancelled"});return l}finally{this.attemptInFlight=!1}}discardHeldGuest(e){return this.serialize(async()=>{if(this.state==="withheld")throw this.withheldError();let{index:t,slot:r}=this.resolveSlot(e);await this.discardSlot(t,r)})}async discardSlot(e,t){let r=await this.http.post("/auth-service/guest/discard",{refreshToken:t.refreshToken}),n=r.error?.status;if(r.success||n===404||r.error?.code==="NOT_FOUND"){this.commit({type:"release",index:e,reason:"discarded"});return}throw new u(r.error?.code??"GUEST_DISCARD_FAILED",r.error?.message??"Could not discard the held guest",p(r))}merge(e){let{slots:t}=this.store.readSlots(),r=t.find(n=>n!==null&&(n.refreshToken===e||n.tokenAtHold===e));return r?this.claimHeldGuest(r.userId).then(n=>n.stats):this.serialize(async()=>{if(this.state==="withheld")throw this.withheldError();if(this.state!=="identified"||!this.record)throw new u("NOT_IDENTIFIED","merge() needs a signed-in identified account as the target");let n=this.currentSid(),i=this.store.currentRefresh();if(!i)throw new u("NOT_SIGNED_IN","Not signed in");let o=await this.http.post("/auth-service/merge",{anonymousRefreshToken:e,targetRefreshToken:i});if(!o.success||!o.data)throw new u(o.error?.code??"MERGE_FAILED",o.error?.message??"Merge failed",p(o));let a=q(o.data),l=Qe(o.data,this.record.user.id,"");await this.refreshInflight;let d=this.record;return a&&d&&this.commit({type:"install",reason:"claim",record:{...d,accessToken:a.accessToken,accessExpiresAt:Date.now()+a.expiresIn*1e3,refreshToken:a.refreshToken},expectSid:n,expectRefresh:i}),l})}getWithheld(){return this.withheld?.info??null}discardWithheld(){return this.serialize(async()=>this.discardWithheldNow())}discardWithheldNow(){return this.state!=="withheld"||!this.withheld?!1:this.commit({type:"clear",reason:"user",expectRefresh:this.withheld.refreshToken,revoke:!0,dropQueue:!1,stampNoAutoRestore:!1,keepAnalyticsIdentity:!0})?!0:(this.hydrateFromDisk("storage_event"),!1)}signOut(){return this.serialize(async()=>{if(this.state==="withheld"){this.discardWithheldNow();return}if(this.state==="signed_out"){this.analytics.reset(!0),this.flags.reset(),this.chatbot.newSession();return}this.commit({type:"clear",reason:"user",revoke:!0,dropQueue:!1,stampNoAutoRestore:!1})})}deleteAccount(e){return this.serialize(async()=>{if(this.state==="withheld")throw this.withheldError();if(this.state==="unknown"&&await this.settle(),this.status()==="withheld")throw this.withheldError();if(this.state==="signed_out")throw new u("NOT_SIGNED_IN","Sign in before deleting your account");let t=await this.bearerHeaders(),r=await this.http.delete("/auth-service/me",t);if(!r.success)throw new u(r.error?.code??"DELETE_ACCOUNT_FAILED",r.error?.message??"Account deletion failed",p(r));let n=r.data??{};this.commit({type:"clear",reason:"account_deleted",revoke:!1,dropQueue:!0,stampNoAutoRestore:!0});let i={status:n.status==="purged"?"purged":"pending",scheduledPurgeAt:n.scheduledPurgeAt??null,graceDays:typeof n.graceDays=="number"?n.graceDays:0,heldGuests:this.heldCount()};if(e?.alsoDiscardHeldGuests){let o=[],{slots:a}=this.store.readSlots();for(let l=0;l<a.length;l++){let d=a[l];if(d)try{await this.discardSlot(l,d)}catch{o.push(d.userId)}}i.heldGuests=this.heldCount(),i.discardFailed=o}return i})}async listLinkedIdentities(){let e=await this.bearerHeaders().catch(()=>{throw new u("NOT_SIGNED_IN","Sign in before listing linked identities")}),t=await this.http.get("/auth-service/me/identities",e);if(!t.success||!t.data)throw new u(t.error?.code??"IDENTITIES_FAILED",t.error?.message??"Failed to list linked identities",p(t));return{identities:t.data.identities??[],hasPassword:!!t.data.hasPassword}}async unlink(e){let t=await this.bearerHeaders().catch(()=>{throw new u("NOT_SIGNED_IN","Sign in before unlinking an identity")}),r=await this.http.delete(`/auth-service/me/identities/${encodeURIComponent(e)}`,t);if(!r.success||!r.data)throw new u(r.error?.code??"UNLINK_FAILED",r.error?.message??"Failed to unlink identity",p(r));return{provider:r.data.provider??e,removed:Number(r.data.removed??0),remaining:Number(r.data.remaining??0)}}async sendMagicLink(e){let t=await this.http.post("/auth-service/magic-link/request",{email:e});if(!t.success)throw new u(t.error?.code??"MAGIC_LINK_REQUEST_FAILED",t.error?.message??"Failed to send link")}async sendEmailOtp(e){let t=await this.http.post("/auth-service/email-otp/request",{email:e});if(!t.success)throw new u(t.error?.code??"EMAIL_OTP_REQUEST_FAILED",t.error?.message??"Failed to send code")}verifyEmailOtp(e,t){return this.serialize(async()=>{let r=await this.performSwitch(()=>this.http.post("/auth-service/email-otp/verify",{email:e,code:t}),"EMAIL_OTP_INVALID","Wrong or expired code");if(r.kind==="mfa")throw new u("MFA_REQUIRED","This account requires MFA; use signIn()/challengeMfa()");return r.user})}verifyMagicLink(e){return this.serialize(async()=>{let t=await this.performSwitch(()=>this.http.post("/auth-service/magic-link/verify",{token:e}),"MAGIC_LINK_INVALID","Invalid or expired magic link");if(t.kind==="mfa")throw new u("MFA_REQUIRED","This account requires MFA; use signIn()/challengeMfa()");return t.user})}async requestPasswordReset(e){let t=await this.http.post("/auth-service/password/forgot",{email:e});if(!t.success)throw new u(t.error?.code??"PASSWORD_RESET_REQUEST_FAILED",t.error?.message??"Failed to send reset email")}async resetPassword(e,t){let r=await this.http.post("/auth-service/password/reset",{token:e,newPassword:t});if(!r.success)throw new u(r.error?.code??"PASSWORD_RESET_FAILED",r.error?.message??"Reset failed")}async verifyEmail(e){let t=await this.http.post("/auth-service/email/verify",{token:e});if(!t.success)throw new u(t.error?.code??"EMAIL_VERIFICATION_FAILED",t.error?.message??"Verification failed")}async sendVerificationEmail(){let e=await this.bearerHeaders().catch(r=>{throw r instanceof u&&r.code===$.SESSION_WITHHELD?r:new u("UNAUTHORIZED","Sign in before requesting a verification email")}),t=await this.http.post("/auth-service/email/verify/resend",{},e);if(!t.success)throw new u(t.error?.code??"VERIFICATION_RESEND_FAILED",t.error?.message??"Failed to send verification email")}async enrollMfa(){let e=await this.http.post("/auth-service/mfa/enroll/start",{},await this.bearerHeaders());if(!e.success||!e.data)throw new u(e.error?.code??"MFA_ENROLL_FAILED",e.error?.message??"MFA enrollment failed");return e.data}async confirmMfa(e){let t=await this.http.post("/auth-service/mfa/enroll/confirm",{code:e},await this.bearerHeaders());return!!(t.success&&t.data?.confirmed)}async disableMfa(){let e=await this.http.post("/auth-service/mfa/disable",{},await this.bearerHeaders());if(!e.success)throw new u(e.error?.code??"MFA_DISABLE_FAILED",e.error?.message??"Failed to disable MFA",p(e))}async registerPasskey(e){if(typeof navigator>"u"||!navigator.credentials)throw new u("PASSKEY_UNSUPPORTED","WebAuthn not supported in this environment");let t=await this.http.post("/auth-service/passkeys/register/start",{},await this.bearerHeaders());if(!t.success||!t.data)throw new u(t.error?.code??"PASSKEY_START_FAILED",t.error?.message??"Passkey start failed");let r=Nt(t.data),n;try{let a=await navigator.credentials.create({publicKey:r});if(!a)throw new Error("create returned null");n=a}catch(a){throw new u("PASSKEY_USER_CANCELLED",a instanceof Error?a.message:"User cancelled passkey registration")}let i=Ht(n),o=await this.http.post("/auth-service/passkeys/register/finish",{response:i,name:e},await this.bearerHeaders());if(!o.success||!o.data)throw new u(o.error?.code??"PASSKEY_FINISH_FAILED",o.error?.message??"Passkey verification failed");return o.data}signInWithPasskey(e){return this.serialize(async()=>{if(typeof navigator>"u"||!navigator.credentials)throw new u("PASSKEY_UNSUPPORTED","WebAuthn not supported in this environment");if(this.state==="withheld")throw this.withheldError();let t=await this.http.post("/auth-service/passkeys/authenticate/start",{userId:e??null});if(!t.success||!t.data)throw new u(t.error?.code??"PASSKEY_START_FAILED",t.error?.message??"Passkey start failed",p(t));let r=Ot(t.data),n;try{let a=await navigator.credentials.get({publicKey:r});if(!a)throw new Error("get returned null");n=a}catch(a){throw new u("PASSKEY_USER_CANCELLED",a instanceof Error?a.message:"User cancelled passkey signin")}let i=Mt(n),o=await this.performSwitch(()=>this.http.post("/auth-service/passkeys/authenticate/finish",{response:i,userId:e??null}),"PASSKEY_AUTH_FAILED","Passkey signin failed");if(o.kind==="mfa")throw new u("MFA_REQUIRED","This account requires MFA; use signIn()/challengeMfa()");return o.user})}async listPasskeys(){let e=await this.http.get("/auth-service/passkeys",await this.bearerHeaders());return!e.success||!Array.isArray(e.data)?[]:e.data}async deletePasskey(e){let t=await this.http.delete(`/auth-service/passkeys/${encodeURIComponent(e)}`,await this.bearerHeaders());if(!t.success)throw new u(t.error?.code??"PASSKEY_DELETE_FAILED",t.error?.message??"Failed to delete passkey",p(t))}async listMySessions(){let e=await this.http.get("/auth-service/sessions/me",await this.bearerHeaders());return!e.success||!Array.isArray(e.data)?[]:e.data}async revokeSession(e){let t=await this.http.delete(`/auth-service/sessions/me/${encodeURIComponent(e)}`,await this.bearerHeaders());if(!t.success)throw new u(t.error?.code??"SESSION_REVOKE_FAILED",t.error?.message??"Failed to revoke session",p(t))}async revokeAllSessions(){let e=await this.http.delete("/auth-service/sessions/me",await this.bearerHeaders());if(!e.success)throw new u(e.error?.code??"SESSION_REVOKE_ALL_FAILED",e.error?.message??"Failed to sign out other devices",p(e))}async startSso(e){let t=await this.http.post("/auth-service/sso/oidc/start",{returnTo:e});if(!t.success||!t.data)throw new u(t.error?.code??"SSO_START_FAILED",t.error?.message??"SSO start failed");return t.data}async signInWithSso(e){let t=e??(typeof window<"u"?window.location.origin:"");if(!t)throw new u("SSO_NO_RETURN_TO","returnTo required outside browser context");let r=await this.startSso(t);typeof window<"u"&&(window.location.href=r.authorizationUrl)}async startSaml(e){let t=await this.http.post("/auth-service/sso/saml/start",{returnTo:e});if(!t.success||!t.data)throw new u(t.error?.code??"SAML_START_FAILED",t.error?.message??"SAML start failed");return t.data}async signInWithSaml(e){let t=e??(typeof window<"u"?window.location.origin:"");if(!t)throw new u("SAML_NO_RETURN_TO","returnTo required outside browser context");let r=await this.startSaml(t);typeof window<"u"&&(window.location.href=r.authorizationUrl)}consumeSsoTokenFromUrl(){return this.serialize(async()=>{if(typeof window>"u")return null;let e=window.location.hash.replace(/^#/,"");if(!e)return null;let t=new URLSearchParams(e),r=t.get("sendora_oidc_error")??t.get("sendora_saml_error");if(r)throw window.history.replaceState(null,"",window.location.pathname+window.location.search),new u("SSO_FAILED",decodeURIComponent(r));let n=t.get("sendora_oidc_token")??t.get("sendora_saml_token");if(!n)return null;let i=t.get("sendora_retired_anon");window.history.replaceState(null,"",window.location.pathname+window.location.search);let o=await this.performSwitch(async()=>{let a=await this.http.post("/auth-service/token/refresh",{refreshToken:n}),l=a.success?q(a.data):null;return l?{success:!0,data:{user:B(a.data)??Je(l.accessToken,Ye(l.accessToken)??"",!1),tokens:{...l,tokenType:"Bearer"}}}:{success:!1,error:a.error??{code:"SSO_EXCHANGE_FAILED",message:"Could not exchange SSO token"}}},"SSO_EXCHANGE_FAILED","Could not exchange SSO token");if(o.kind==="mfa")throw new u("MFA_REQUIRED","Unexpected MFA challenge on SSO exchange");return i&&this.fireDeviceTakeover(i,o.user.id),o.user})}};function qe(s){return s?ke.includes(s):!1}function Te(s){return{v:1,user:s.user,accessToken:s.tokens.accessToken,accessExpiresAt:Date.now()+s.tokens.expiresIn*1e3,refreshToken:s.tokens.refreshToken}}function xt(){let s="abcdefghijklmnopqrstuvwxyz0123456789",e=new Uint8Array(32),t=globalThis.crypto;if(t?.getRandomValues)t.getRandomValues(e);else for(let n=0;n<e.length;n++)e[n]=Math.floor(Math.random()*256);let r="mk_";for(let n=0;n<e.length;n++)r+=s[e[n]%s.length];return r}function Be(s){switch(s.kind){case"password":return{path:"/auth-service/login",body:{email:s.email,password:s.password}};case"gameCenter":{let{kind:e,...t}=s;return{path:"/auth-service/login/game-center",body:t}}case"playGames":return{path:"/auth-service/login/play-games",body:{serverAuthCode:s.serverAuthCode}};case"magicLink":return{path:"/auth-service/magic-link/verify",body:{token:s.token}};case"emailOtp":return{path:"/auth-service/email-otp/verify",body:{email:s.email,code:s.code}};case"passkey":return{path:"/auth-service/passkeys/authenticate/finish",body:{response:s.assertion,userId:s.userId??null}};case"mfa":return{path:"/auth-service/mfa/challenge",body:{challengeToken:s.challengeToken,code:s.code}};default:{let{kind:e,...t}=s;return{path:"/auth-service/login/social",body:{provider:e,...t}}}}}function ze(s){switch(s.kind){case"password":return{path:"/auth-service/me/link/email",body:{email:s.email,password:s.password}};case"gameCenter":{let{kind:e,...t}=s;return{path:"/auth-service/me/link/game-center",body:t}}case"playGames":return{path:"/auth-service/me/link/play-games",body:{serverAuthCode:s.serverAuthCode}};case"magicLink":case"emailOtp":case"passkey":case"mfa":throw new u("UNSUPPORTED_LINK_CREDENTIAL",`A ${s.kind} credential cannot be linked; sign in with it instead`);default:{let{kind:e,...t}=s;return{path:"/auth-service/me/link/social",body:{provider:e,...t}}}}}function Qe(s,e,t){let r=s&&typeof s=="object"?s:{},n=i=>typeof r[i]=="number"?r[i]:0;return{mergedUserId:typeof r.mergedUserId=="string"?r.mergedUserId:e,deletedAnonymousId:typeof r.deletedAnonymousId=="string"?r.deletedAnonymousId:t,eventsReassigned:n("eventsReassigned"),profilesReassigned:n("profilesReassigned"),entitiesReassigned:n("entitiesReassigned"),pushTokensReassigned:n("pushTokensReassigned")}}function Ye(s){let e=A(s)?.sub;return typeof e=="string"&&e.length>0?e:null}function Je(s,e,t=!0){let r=A(s)??{},n=typeof r.sub=="string"&&r.sub.length>0?r.sub:e,i=typeof r.is_anonymous=="boolean"?r.is_anonymous:t,o={id:n,email:typeof r.email=="string"?r.email:null,emailVerified:typeof r.email_verified=="boolean"?r.email_verified:!i,name:typeof r.name=="string"?r.name:null,isAnonymous:i};if(Object.prototype.hasOwnProperty.call(r,"project")){let a=r.project;o.project=typeof a=="string"?a:null}return o}function z(s){let e=(4-s.length%4)%4,t=(s+"===".slice(0,e)).replace(/-/g,"+").replace(/_/g,"/"),r=atob(t),n=new ArrayBuffer(r.length),i=new Uint8Array(n);for(let o=0;o<r.length;o++)i[o]=r.charCodeAt(o);return n}function E(s){let e=s instanceof Uint8Array?s:new Uint8Array(s),t="";for(let r=0;r<e.length;r++)t+=String.fromCharCode(e[r]);return btoa(t).replace(/\+/g,"-").replace(/\//g,"_").replace(/=+$/,"")}function Nt(s){return{challenge:z(s.challenge),rp:s.rp,user:{id:z(s.user.id),name:s.user.name,displayName:s.user.displayName},pubKeyCredParams:s.pubKeyCredParams,timeout:s.timeout,attestation:s.attestation,excludeCredentials:s.excludeCredentials?.map(e=>({id:z(e.id),type:"public-key",transports:e.transports})),authenticatorSelection:s.authenticatorSelection}}function Ot(s){return{challenge:z(s.challenge),timeout:s.timeout,rpId:s.rpId,allowCredentials:s.allowCredentials?.map(e=>({id:z(e.id),type:"public-key",transports:e.transports})),userVerification:s.userVerification}}function Ht(s){let e=s.response;return{id:s.id,rawId:E(s.rawId),type:s.type,response:{clientDataJSON:E(e.clientDataJSON),attestationObject:E(e.attestationObject),transports:typeof e.getTransports=="function"?e.getTransports():void 0},clientExtensionResults:s.getClientExtensionResults()}}function q(s){if(!s||typeof s!="object")return null;let e=s.tokens,t=e&&typeof e=="object"?e:s;return typeof t.accessToken!="string"||!t.accessToken||typeof t.refreshToken!="string"||!t.refreshToken||typeof t.expiresIn!="number"||t.expiresIn<=0?null:{accessToken:t.accessToken,refreshToken:t.refreshToken,expiresIn:t.expiresIn}}function B(s){if(!s||typeof s!="object")return null;let e=s.user;if(!e||typeof e!="object")return null;let t=e.id;return typeof t!="string"||t.length===0?null:e}function Xe(s,e){let t=A(s);if(!t)return!0;let r=t.exp;return typeof r!="number"||!Number.isFinite(r)?!0:e<r*1e3}function Mt(s){let e=s.response;return{id:s.id,rawId:E(s.rawId),type:s.type,response:{clientDataJSON:E(e.clientDataJSON),authenticatorData:E(e.authenticatorData),signature:E(e.signature),userHandle:e.userHandle?E(e.userHandle):null},clientExtensionResults:s.getClientExtensionResults()}}var Ft=D;function jt(s){return s===!1?{pageViews:!1,sessionStart:!1,appOpen:!1,appBackground:!1,engagement:!1}:s===!0||s===void 0?{pageViews:!0,sessionStart:!0,appOpen:!0,appBackground:!0,engagement:!0}:{pageViews:s.pageViews??!0,sessionStart:s.sessionStart??!0,appOpen:s.appOpen??!0,appBackground:s.appBackground??!0,engagement:s.engagement??!0}}var Gt=250,Ze=360*60*1e3;function rt(s,e){if(typeof window>"u")return()=>{};let t=jt(e.autoTrack),r=e.sessionIdleMs??18e5,n=[],i="sendora_session_id",o="sendora_session_last_activity";function a(){return et(i)??""}function l(c){tt(i,c)}function d(){let c=et(o);return c&&Number(c)||0}function h(c){tt(o,String(c))}function g(){return`sess_${Date.now().toString(36)}_${Math.random().toString(36).slice(2,10)}`}function k(c){let S=Date.now(),O=d();if(!a()||O&&S-O>r){let re=g();l(re),c&&t.sessionStart&&s.track("session.start",{sessionId:re})}h(S)}k(t.sessionStart),t.appOpen&&s.track("app.opened",{sessionId:a()||void 0,url:window.location.origin+window.location.pathname,referrer:document.referrer||void 0});let v=window.location.pathname,m=0,y=document.visibilityState==="visible"?Date.now():0;function N(){y>0&&(m+=Date.now()-y,y=0)}function te(){if(!t.engagement)return;N();let c=m;if(m=0,!(c<Gt)){c>Ze&&(c=Ze);try{s.track("app.engagement",{durationMs:Math.round(c),screen:v,sessionId:a()||void 0})}catch{}}}function st(c){v=c,m=0,y=document.visibilityState==="visible"?Date.now():0}if(t.pageViews||t.engagement){t.pageViews&&s.page();let c=()=>{te(),k(!0),t.pageViews&&s.page(),st(window.location.pathname)},S=()=>c();window.addEventListener("popstate",S),n.push(()=>window.removeEventListener("popstate",S));let O=window;if(!O.__sendoraHistoryPatched){O.__sendoraHistoryPatched=!0;let re=history.pushState,nt=history.replaceState;history.pushState=function(...pe){let fe=re.apply(this,pe);return window.dispatchEvent(new Event("sendora:locationchange")),fe},history.replaceState=function(...pe){let fe=nt.apply(this,pe);return window.dispatchEvent(new Event("sendora:locationchange")),fe}}let he=()=>c();window.addEventListener("sendora:locationchange",he),n.push(()=>window.removeEventListener("sendora:locationchange",he))}if(t.appBackground||t.engagement){let c=()=>{if(document.visibilityState==="hidden"){te(),t.appBackground&&(k(!0),s.track("app.backgrounded",{sessionId:a()||void 0}));try{s.flush()}catch{}}else document.visibilityState==="visible"&&(t.appBackground&&(k(!0),s.track("app.foregrounded",{sessionId:a()||void 0})),t.engagement&&y===0&&(y=Date.now()))};if(document.addEventListener("visibilitychange",c),n.push(()=>document.removeEventListener("visibilitychange",c)),t.engagement){let S=()=>{te();try{s.flush()}catch{}};window.addEventListener("pagehide",S),n.push(()=>window.removeEventListener("pagehide",S))}}let Ce=0,R=()=>{let c=Date.now();c-Ce<5e3||(Ce=c,k(!0))};return window.addEventListener("click",R,{passive:!0}),window.addEventListener("keydown",R,{passive:!0}),window.addEventListener("scroll",R,{passive:!0}),n.push(()=>{window.removeEventListener("click",R),window.removeEventListener("keydown",R),window.removeEventListener("scroll",R)}),()=>{te();for(let c of n)try{c()}catch{}}}function et(s){try{return window.sessionStorage?.getItem(s)??null}catch{return null}}function tt(s,e){try{window.sessionStorage?.setItem(s,e)}catch{}}var X=class s{constructor(e){this.http=e}static isSupported(){return typeof window>"u"?!1:"serviceWorker"in navigator&&"PushManager"in window&&"Notification"in window}static permission(){return typeof Notification>"u"?"denied":Notification.permission}async subscribe(e){if(!s.isSupported())throw new Error("[sendoracloud] Web Push not supported in this browser.");let t=Notification.permission;if(t==="default"&&(t=await Notification.requestPermission()),t!=="granted")throw new Error(`[sendoracloud] Notification permission ${t}.`);let r=await navigator.serviceWorker.getRegistration(e.scope??"/");r||(r=await navigator.serviceWorker.register(e.serviceWorkerPath,{scope:e.scope??"/"})),await navigator.serviceWorker.ready;let i=(await this.http.get("/push/vapid"))?.data?.publicKey;if(!i)throw new Error("[sendoracloud] backend returned no VAPID public key.");let a=await r.pushManager.getSubscription()??await r.pushManager.subscribe({userVisibleOnly:!0,applicationServerKey:Kt(i)}),l=a.toJSON(),d=l.endpoint,h=l.keys?.p256dh??"",g=l.keys?.auth??"",k=await Wt(d),v=await this.http.post("/push/tokens",{platform:"web",token:k,webEndpoint:d,webP256dh:h,webAuth:g,userAgent:typeof navigator<"u"?navigator.userAgent:void 0,locale:typeof navigator<"u"?navigator.language:void 0,timezone:Intl?.DateTimeFormat?.().resolvedOptions?.().timeZone,...e.userId?{userId:e.userId}:{}});if(!v?.data?.tokenId)throw new Error("[sendoracloud] backend returned no tokenId on subscribe.");return{tokenId:v.data.tokenId,subscription:a}}async unsubscribe(e="/"){if(!s.isSupported())return!1;let t=await navigator.serviceWorker.getRegistration(e);if(!t)return!1;let r=await t.pushManager.getSubscription();return r?await r.unsubscribe():!1}async trackOpen(e,t){let r={sendId:e};t!==void 0&&(r.clickAction=t);let n=await this.http.post("/push/track-open",r);if(!n.success)throw new Error(n.error?.message??"push.trackOpen failed")}};function Kt(s){let e="=".repeat((4-s.length%4)%4),t=(s+e).replace(/-/g,"+").replace(/_/g,"/"),r=atob(t),n=new Uint8Array(r.length);for(let i=0;i<r.length;i++)n[i]=r.charCodeAt(i);return n}async function Wt(s){let e=new TextEncoder().encode(s),t=await crypto.subtle.digest("SHA-256",e);return Array.from(new Uint8Array(t)).map(n=>n.toString(16).padStart(2,"0")).join("")}var Z=class{constructor(e){}unsupported(){throw new Error("[SendoraCloud] sendora.audiences is not available in the browser SDK. Audiences require a secret (sk_*) key with the audiences:read/write scopes and must be managed from a trusted server, not the browser.")}list(){return this.unsupported()}get(e){return this.unsupported()}create(e){return this.unsupported()}update(e,t){return this.unsupported()}delete(e){return this.unsupported()}};var f=class extends Error{constructor(e,t,r){super(t),this.name="LinkError",this.code=e,this.statusCode=r}};function Re(s,e){let t=(s??"").toUpperCase();return t==="NOT_FOUND"?new f("NOT_FOUND",e):t==="FORBIDDEN"||t==="UNAUTHORIZED"?new f("UNAUTHORIZED",e):t==="RATE_LIMITED"?new f("RATE_LIMITED",e):t==="ENTITLEMENT_ERROR"||/plan limit/i.test(e)?new f("PLAN_LIMIT",e):t==="VALIDATION_ERROR"?/iOS bundle|Android package/i.test(e)?new f("BUNDLE_MISMATCH",e):/2KB|10KB|linkData/i.test(e)?new f("DATA_TOO_LARGE",e):/fallbackUrl/i.test(e)&&/apps/i.test(e)?new f("FALLBACK_REQUIRED",e):new f("INVALID_INPUT",e):t==="PARSE_ERROR"||t==="HTTP_ERROR"||/HTTP \d{3}/.test(e)?new f("NETWORK",e):new f("UNKNOWN",e||`Unknown LinkError (code=${s??"none"})`)}var _e=/^[a-z0-9-]{3,20}$/;function Vt(s){try{let t=new URL(s).pathname.split("/").filter(Boolean);if(t.length===0)return null;let r=t[t.length-1];return _e.test(r)?r:null}catch{return null}}var $t=5*6e4,qt=50,Bt=5,ee=class{constructor(e){this.http=e;this.prewarmCache=new Map;this.prewarmInflight=0}cacheKey(e,t){if(t)return`k:${t}`;let r={},n=e;for(let i of Object.keys(n).sort())r[i]=n[i];return`s:${JSON.stringify(r)}`}evictExpired(){let e=Date.now();for(let[t,r]of this.prewarmCache)e-r.ts>$t&&this.prewarmCache.delete(t);for(;this.prewarmCache.size>qt;){let t=this.prewarmCache.keys().next().value;if(t===void 0)break;this.prewarmCache.delete(t)}}prewarm(e,t){this.evictExpired();let r=this.cacheKey(e,t?.key);if(this.prewarmCache.has(r)||this.prewarmInflight>=Bt)return;this.prewarmInflight++;let n=this.doCreate(e).catch(i=>{throw this.prewarmCache.delete(r),i}).finally(()=>{this.prewarmInflight--});this.prewarmCache.set(r,{promise:n,ts:Date.now()})}async create(e,t){if(!e.title)throw new f("INVALID_INPUT","links.create: title is required");this.evictExpired();let r=this.cacheKey(e,t?.key),n=this.prewarmCache.get(r);return n?(this.prewarmCache.delete(r),n.promise):this.doCreate(e)}async doCreate(e){let t={title:e.title};e.fallbackUrl&&(t.fallbackUrl=e.fallbackUrl),e.iosDeepLinkPath&&(t.iosDeepLinkPath=e.iosDeepLinkPath),e.androidDeepLinkPath&&(t.androidDeepLinkPath=e.androidDeepLinkPath),e.linkData&&(t.linkData=e.linkData),e.ogTitle&&(t.ogTitle=e.ogTitle),e.ogDescription&&(t.ogDescription=e.ogDescription),e.ogImageUrl&&(t.ogImageUrl=e.ogImageUrl),e.campaign&&(t.campaign=e.campaign),e.source&&(t.source=e.source),e.medium&&(t.medium=e.medium),e.channel&&(t.channel=e.channel),e.tags&&(t.tags=e.tags),e.expiresAt&&(t.expiresAt=e.expiresAt),e.iosBundleId&&(t.iosBundleId=e.iosBundleId),e.androidPackageName&&(t.androidPackageName=e.androidPackageName);let r=await this.http.post("/sdk/links",t);if(!r.success||!r.data)throw Re(r.error?.code,r.error?.message??"links.create failed");return r.data}async revoke(e){if(!_e.test(e))throw new f("INVALID_INPUT",`links.revoke: '${e}' is not a valid shortcode`);let t=await this.http.post(`/sdk/links/${encodeURIComponent(e)}/revoke`,{});if(!t.success||!t.data)throw Re(t.error?.code,t.error?.message??"links.revoke failed");return{shortcode:t.data.shortcode,revoked:!0}}async getStats(e){if(!_e.test(e))throw new f("INVALID_INPUT",`links.getStats: '${e}' is not a valid shortcode`);let t=await this.http.get(`/sdk/links/${encodeURIComponent(e)}/stats`);if(!t.success||!t.data)throw Re(t.error?.code,t.error?.message??"links.getStats failed");return t.data}};var le=class{constructor(e){this.http=e}async reportInstall(e={}){let t=await this.http.post("/attribution/install",e);if(!t.success||!t.data)throw new Error(t.error?.message??"attribution.reportInstall failed");return t.data}async checkDeferred(e={}){let t=await this.http.post("/attribution/deferred",e);if(!t.success)throw new Error(t.error?.message??"attribution.checkDeferred failed");return t.data??null}};var ue=class{constructor(e){this.http=e}async createTicket(e){let t=await this.http.post("/support/tickets",e);if(!t.success||!t.data)throw new Error(t.error?.message??"support.createTicket failed");return t.data}async submitCsat(e){let t=await this.http.post("/support/csat",e);if(!t.success||!t.data)throw new Error(t.error?.message??"support.submitCsat failed");return t.data}};var de=class{constructor(e){this.http=e}async search(e){if(!e.query||e.query.trim().length===0)return[];let t=new URLSearchParams({query:e.query});e.limit&&t.set("limit",String(e.limit));let r=await this.http.get(`/kb/search?${t.toString()}`);if(!r.success||!Array.isArray(r.data))throw new Error(r.error?.message??"kb.search failed");return r.data}};var zt=/^[A-Za-z0-9_.-]{1,64}$/;function Qt(s){if(s!==void 0){if(typeof s!="string"||!zt.test(s))throw new Error(`[sendora] init: storagePrefix must be 1-64 chars of A-Z a-z 0-9 _ . - (got ${JSON.stringify(s)}). Changing it signs the browser out, so it is validated rather than ignored.`);return s}}var Yt=/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;function Jt(s){let e=s.expectedProjectId;if(e!==void 0){if(typeof e!="string"||!Yt.test(e))throw new Error(`[sendora] init: expectedProjectId must be a UUID (got ${JSON.stringify(e)}).`);if(s.projectId!==void 0&&s.projectId!==e)throw new Error(`[sendora] init: expectedProjectId (${e}) must equal projectId (${s.projectId}) when both are set \u2014 they name the same project.`)}}var ce=class ce{constructor(e){this.autoTrackCleanup=null;this.http=new se(e),this.storage=new ne(Qt(e.storagePrefix),e.tokenStore==="memory"),this.consent=new K(e.defaultConsent===!0,this.http),this.analytics=new H(e,this.http,this.storage,this.consent),this.flags=new M(e,this.http,this.storage),this.surveys=new F(e,this.http,this.storage),this.messages=new j(e,this.http,this.storage),this.chatbot=new G(e,this.http,this.storage),this.auth=new J(e,this.http,this.storage,this.analytics,this.flags,this.chatbot,{onIdentityWithheld:()=>{this.analytics.withholdIdentity(),this.flags.setContext({})}}),this.webPush=new X(this.http),this.audiences=new Z(this.http),this.links=new ee(this.http),this.attribution=new le(this.http),this.support=new ue(this.http),this.kb=new de(this.http),e.autoTrack!==!1&&(this.autoTrackCleanup=rt(this.analytics,e))}static init(e){return Ne(e.apiKey),Jt(e),new ce(e)}static sanitizeHtml(e){return we(e)}static safeUrl(e){return T(e)}track(e,t){this.analytics.track(e,t)}page(e){this.analytics.page(e)}identify(e,t,r){this.analytics.identify(e,t,r),this.flags.setContext({userId:e})}reset(e){this.analytics.reset(),this.flags.reset(),this.chatbot.newSession()}onIdentityWithheld(e){return this.auth.onIdentityWithheld(e)}async flush(){await this.analytics.flush()}destroy(){this.autoTrackCleanup&&(this.autoTrackCleanup(),this.autoTrackCleanup=null),this.analytics.destroy(),this.flags.destroy(),this.messages.destroy()}};ce.version=I;var be=ce,Zr=be;export{Se as AMBIGUOUS_HELD_GUEST,Ft as AUTH_HELD_SLOT_KEYS,Et as AUTH_STATES,$ as AUTH_WITHHELD_CODES,Q as AlreadyIdentifiedError,H as Analytics,Z as Audiences,J as Auth,u as AuthError,G as Chatbot,K as Consent,x as CredentialInUseError,ke as DEAD_CODES,U as EmailAlreadyTakenError,M as FeatureFlags,P as HELD_GUEST_SLOTS,Y as HeldGuestLimitError,L as HeldGuestProjectMismatch,j as InAppMessaging,f as LinkError,ee as Links,ve as REFRESH_END_REASONS,It as REJECTED_IN_WITHHELD,Ae as RELEASE_HELD_ON_END_REASONS,be as SendoraCloud,F as Surveys,w as ValidationError,X as WebPush,Zr as default,Vt as extractShortcodeFromUrl,Ee as projectVerdict,T as safeUrl,we as sanitizeHtml};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sendoracloud/sdk-web",
3
- "version": "3.24.1",
3
+ "version": "3.24.2",
4
4
  "description": "Sendora Cloud Web SDK — analytics, feature flags, surveys, in-app messaging, chatbot, auth, deep links (Branch / Firebase parity). Zero dependencies, TypeScript, SSR-safe.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",