@joryio/web-sdk 1.3.1-beta.1 → 1.3.1-beta.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/CHANGELOG.md +5 -1
- package/dist/core/inapp.d.ts +15 -0
- package/dist/core/inapp.d.ts.map +1 -1
- package/dist/index.d.mts +1 -0
- package/dist/joryio-sw.js +1 -1
- package/dist/joryio.cjs.js +74 -8
- package/dist/joryio.min.js +2 -2
- package/dist/joryio.min.js.map +1 -1
- package/dist/joryio.mjs +74 -8
- package/dist/joryio.umd.js +74 -8
- package/package.json +1 -1
- package/src/core/inapp.ts +136 -16
package/dist/joryio.min.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Joryio Web SDK v1.3.1-beta.
|
|
2
|
+
* Joryio Web SDK v1.3.1-beta.2
|
|
3
3
|
* (c) 2026 Joryio. All rights reserved.
|
|
4
4
|
* @license Commercial - see https://github.com/joryio/joryio-web-sdk/blob/main/LICENSE
|
|
5
5
|
*/
|
|
6
|
-
!function(t,i){"object"==typeof exports&&"undefined"!=typeof module?i(exports):"function"==typeof define&&define.amd?define(["exports"],i):i((t="undefined"!=typeof globalThis?globalThis:t||self).JoryioSDK={})}(this,function(t){"use strict";const i="1.3.1";function e(t){const i=(t||"").trim();if(!i)return"https://api-eu1.joryio.com/api";const e=(/^https?:\/\//i.test(i)?i:"https://"+i).replace(/\/+$/,"");try{const t=new URL(e);if(""===t.pathname||"/"===t.pathname)return e+"/api"}catch(t){}return e}const s={allowHtmlJsInAppMessages:"inApp",evaluationMode:"inApp",syncInterval:"inApp",displayOptions:"inApp"};const n=16777619;class r{static hashKey(t){return function(t){let i=2166136261;for(let e=0;e<t.length;e++){const s=t.charCodeAt(e);i^=255&s,i=Math.imul(i,n),i^=s>>>8&255,i=Math.imul(i,n)}return e=i>>>0,e=Math.imul(e^=e>>>16,2246822507),e=Math.imul(e^=e>>>13,3266489909),(e^=e>>>16)>>>0;var e}(t).toString(36)}constructor(t,i){this.memoryStore=new Map,this.prefix=`jry_${r.hashKey(t)}_`,this.logger=i,this.isLocalStorageAvailable=this.checkLocalStorageAvailable(),this.isLocalStorageAvailable||this.logger.warn("LocalStorage not available, using in-memory storage")}checkLocalStorageAvailable(){try{const t="__jry_test__";return localStorage.setItem(t,"test"),localStorage.removeItem(t),!0}catch(t){return!1}}getKey(t){return`${this.prefix}${t}`}storageKeyFor(t){return this.getKey(t)}set(t,i,e){const s={value:i,expiresAt:e?Date.now()+864e5*e:null};if(this.isLocalStorageAvailable)try{localStorage.setItem(this.getKey(t),JSON.stringify(s)),this.memoryStore.delete(t)}catch(i){this.logger.error("Failed to write to localStorage:",i);try{localStorage.removeItem(this.getKey(t))}catch(t){}this.memoryStore.set(t,s)}else this.memoryStore.set(t,s)}get(t){var i;let e=null;if(this.isLocalStorageAvailable)try{const i=localStorage.getItem(this.getKey(t));i&&(e=JSON.parse(i))}catch(i){this.logger.error("Failed to read from localStorage:",i);try{localStorage.removeItem(this.getKey(t))}catch(t){}}return e||(e=this.memoryStore.get(t)||null),e&&e.expiresAt&&e.expiresAt<Date.now()?(this.remove(t),null):null!==(i=null==e?void 0:e.value)&&void 0!==i?i:null}remove(t){if(this.isLocalStorageAvailable)try{localStorage.removeItem(this.getKey(t))}catch(t){this.logger.error("Failed to remove from localStorage:",t)}this.memoryStore.delete(t)}clear(){if(this.isLocalStorageAvailable)try{const t=[];for(let i=0;i<localStorage.length;i++){const e=localStorage.key(i);e&&e.startsWith(this.prefix)&&t.push(e)}t.forEach(t=>localStorage.removeItem(t))}catch(t){this.logger.error("Failed to clear localStorage:",t)}this.memoryStore.clear()}}function o(){return"undefined"!=typeof crypto&&crypto.randomUUID?crypto.randomUUID():"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g,t=>{const i=16*Math.random()|0;return("x"===t?i:3&i|8).toString(16)})}function h(){if("undefined"!=typeof crypto&&crypto.getRandomValues){const t=new Uint8Array(6);return crypto.getRandomValues(t),Date.now().toString(36)+Array.from(t,t=>t.toString(16).padStart(2,"0")).join("")}return Date.now().toString(36)+Math.random().toString(36).substr(2,9)}const a="session_id",u="session_start",d="last_activity",l=864e5;class c{constructor(t,i,e){this.currentSessionId=null,this.lastActivityAt=0,this.lastActivityPersistedAt=0,this.isNewSession=!1,this.onNewSessionCallback=null,this.boundVisibilityHandler=null,this.storage=t,this.logger=i,this.sessionTimeoutMs=e||18e5,this.initializeSession(),"undefined"!=typeof document&&(this.boundVisibilityHandler=()=>{"visible"===document.visibilityState&&this.checkAndRefreshSession()},document.addEventListener("visibilitychange",this.boundVisibilityHandler))}onNewSession(t){this.onNewSessionCallback=t}initializeSession(){const t=this.storage.get(a),i=this.storage.get(d),e=this.storage.get(u);if(t&&i){const s=Date.now(),n=s-i,r=e?s-e:1/0;if(n<this.sessionTimeoutMs&&l>r)return this.currentSessionId=t,this.isNewSession=!1,this.updateActivity(),void this.logger.debug("Resumed session: "+this.currentSessionId);l>r?this.logger.debug(`Session expired (${n}ms since last activity)`):this.logger.debug(`Session too old (${Math.round(r/1e3/60/60)}h), creating new session`)}this.startNewSession()}startNewSession(){const t=this.currentSessionId;this.currentSessionId=h(),this.isNewSession=!0;const i=Date.now();this.storage.set(a,this.currentSessionId),this.storage.set(u,i),this.storage.set(d,i),this.lastActivityAt=i,this.lastActivityPersistedAt=i,this.logger.debug("Started new session: "+this.currentSessionId),t&&this.onNewSessionCallback&&this.onNewSessionCallback()}checkAndRefreshSession(){const t=this.storage.get(d),i=this.storage.get(u);if(t&&i){const e=Date.now(),s=e-t,n=e-i;s<this.sessionTimeoutMs?l>n||(this.logger.debug(`Session too old on tab focus (${Math.round(n/1e3/60/60)}h old)`),this.startNewSession()):(this.logger.debug(`Session expired on tab focus (${Math.round(s/1e3/60)} min inactive)`),this.startNewSession())}}refreshIfExpired(){if(!this.currentSessionId)return!1;const t=Date.now(),i=Math.max(this.lastActivityAt,this.storage.get(d)||0)||t,e=this.storage.get(u)||t;return t-i<this.sessionTimeoutMs?t-e>=l&&(this.logger.debug("Session reached its maximum age"),this.startNewSession(),!0):(this.logger.debug(`Session expired (${Math.round((t-i)/1e3/60)} min inactive)`),this.startNewSession(),!0)}updateActivity(){if(!this.currentSessionId)return;const t=Date.now();this.lastActivityAt=t,3e4>t-this.lastActivityPersistedAt||(this.lastActivityPersistedAt=t,this.storage.set(d,t))}getSessionInfo(){return{sessionId:this.currentSessionId||this.storage.get(a)||"",sessionStart:this.storage.get(u)||Date.now(),lastActivity:this.lastActivityAt||this.storage.get(d)||Date.now(),isNewSession:this.isNewSession}}getSessionId(){return this.currentSessionId||this.storage.get(a)||""}ensureSession(){if(this.currentSessionId)return this.currentSessionId;const t=this.storage.get(a);if(t)return this.currentSessionId=t,t;this.currentSessionId=h(),this.isNewSession=!0;const i=Date.now();return this.storage.set(a,this.currentSessionId),this.storage.set(u,i),this.storage.set(d,i),this.lastActivityAt=i,this.lastActivityPersistedAt=i,this.logger.debug("Started new session: "+this.currentSessionId),this.onNewSessionCallback&&this.onNewSessionCallback(),this.currentSessionId}followStoredSession(){const t=this.storage.get(a);return t!==this.currentSessionId&&(this.currentSessionId=t||null,this.isNewSession=!1,this.lastActivityAt=t?this.storage.get(d)||Date.now():0,this.lastActivityPersistedAt=this.lastActivityAt,this.logger.debug("Following the session another tab started: "+(t||"(none)")),!0)}renewSession(){this.updateActivity(),this.logger.debug("Session renewed: "+this.currentSessionId)}resetSession(){this.logger.debug(`Resetting session (was: ${this.currentSessionId})`),this.startNewSession()}clear(){this.currentSessionId=null,this.isNewSession=!1,this.lastActivityAt=0,this.lastActivityPersistedAt=0,this.storage.remove(a),this.storage.remove(u),this.storage.remove(d)}destroy(){this.boundVisibilityHandler&&"undefined"!=typeof document&&(document.removeEventListener("visibilitychange",this.boundVisibilityHandler),this.boundVisibilityHandler=null)}}function p(t,i){return t&&i?t.anonymousId===i.anonymousId&&(t.userId||null)===(i.userId||null):!t&&!i}class f{constructor(t=500){this.maxEntries=t,this.entries=[]}add(t,i,e,s){if(!i)return;const n=s?Object.assign({},s):void 0;if("set"===t||"unset"===t)return this.entries=this.entries.filter(t=>t.key!==i||t.inFlight||!p(t.owner,n)),this.entries.push("set"===t?{key:i,kind:t,value:e,owner:n}:{key:i,kind:t,owner:n}),void this.trim();const r=this.lastFor(i);if(r&&!r.inFlight&&r.kind===t&&p(r.owner,n))if("increment"===t)r.value=(+r.value||0)+ +e;else for(const t of y(e))m(r.values,t)||r.values.push(t);else"increment"===t?this.entries.push({key:i,kind:t,value:+e,owner:n}):this.entries.push({key:i,kind:t,values:v(y(e)),owner:n}),this.trim()}mark(t,i){for(const[e,s]of Object.entries(t.attributes||{}))this.add("set",e,s,i);for(const e of t.unset||[])this.add("unset",e,void 0,i);for(const[e,s]of Object.entries(t.increment||{}))"number"==typeof s&&Number.isFinite(s)&&this.add("increment",e,s,i);for(const[e,s]of Object.entries(t.append||{}))this.add("append",e,s,i);for(const[e,s]of Object.entries(t.remove||{}))this.add("remove",e,s,i)}isEmpty(){return 0===this.entries.length}hasUnsent(){return this.entries.some(t=>!t.inFlight)}nextRequest(t){return this.build(!0,t)}peekRequest(t){return this.build(!1,t)}toOps(){var t,i;return null!==(i=null===(t=this.peekRequest())||void 0===t?void 0:t.ops)&&void 0!==i?i:null}acknowledge(t){const i=new Set(t);this.entries=this.entries.filter(t=>!i.has(t))}release(t,i){let e=0;const s=new Set(t);return this.entries=this.entries.filter(t=>!s.has(t)||(t.inFlight=!1,!i||"increment"!==t.kind||(e++,!1))),e}drop(t){this.acknowledge(t)}dropIncrements(t){const i=new Set(t.filter(t=>"increment"===t.kind));this.entries=this.entries.filter(t=>!i.has(t))}pending(t){const i={};for(const e of this.entries)t&&e.owner&&e.owner.anonymousId!==t||("set"===e.kind?i[e.key]=e.value:"unset"===e.kind&&delete i[e.key]);return i}serialize(){return this.entries.map(t=>{const i={key:t.key,kind:t.kind};return"set"!==t.kind&&"increment"!==t.kind||(i.value=t.value),t.values&&(i.values=[...t.values]),t.owner&&(i.owner=Object.assign({},t.owner)),t.attempts&&(i.attempts=t.attempts),i})}restore(t){if(Array.isArray(t))for(const i of t){if(!i||"object"!=typeof i||"string"!=typeof i.key)continue;const t=i.kind,e=i.owner&&"object"==typeof i.owner&&"string"==typeof i.owner.anonymousId?Object.assign({anonymousId:i.owner.anonymousId},"string"==typeof i.owner.userId?{userId:i.owner.userId}:{}):void 0,s=this.entries.length;"set"===t?this.add("set",i.key,i.value,e):"unset"===t?this.add("unset",i.key,void 0,e):"increment"===t&&"number"==typeof i.value&&Number.isFinite(i.value)?this.add("increment",i.key,i.value,e):"append"!==t&&"remove"!==t||!Array.isArray(i.values)||this.add(t,i.key,i.values,e);const n=this.entries.length>s?this.entries[this.entries.length-1]:void 0;n&&Number.isInteger(i.attempts)&&i.attempts>0&&(n.attempts=i.attempts)}}pinOwner(t,i){for(const e of this.entries)e.owner&&(e.owner.anonymousId!==t||e.owner.userId)||(e.owner={anonymousId:t,userId:i})}clear(){this.entries=[]}build(t,i=t=>t){var e,s,n,r,o;const h=new Set(this.entries.filter(t=>t.inFlight).map(t=>t.key)),a=new Set,u={},d=[];let l,c=!1;for(const t of this.entries){if(t.inFlight||h.has(t.key)||a.has(t.key)){a.add(t.key);continue}const f=i(t.owner);if(!c||p(f,l))switch(c||(c=!0,l=f),a.add(t.key),d.push(t),t.kind){case"set":(null!==(e=u.attributes)&&void 0!==e?e:u.attributes={})[t.key]=t.value;break;case"unset":(null!==(s=u.unset)&&void 0!==s?s:u.unset=[]).push(t.key);break;case"increment":(null!==(n=u.increment)&&void 0!==n?n:u.increment={})[t.key]=t.value;break;case"append":(null!==(r=u.append)&&void 0!==r?r:u.append={})[t.key]=[...t.values];break;case"remove":(null!==(o=u.remove)&&void 0!==o?o:u.remove={})[t.key]=[...t.values]}else a.add(t.key)}if(!d.length)return null;if(t)for(const t of d)t.inFlight=!0;return Object.assign({ops:u,entries:d},l?{owner:Object.assign({},l)}:{})}lastFor(t){for(let i=this.entries.length-1;i>=0;i--)if(this.entries[i].key===t)return this.entries[i]}trim(){for(;this.entries.length>this.maxEntries;){const t=this.entries.findIndex(t=>!t.inFlight);if(0>t)break;this.entries.splice(t,1)}}}function y(t){return Array.isArray(t)?[...t]:[t]}function m(t,i){if(null!==i&&"object"==typeof i){const e=b(i);return t.some(t=>null!==t&&"object"==typeof t&&b(t)===e)}return t.some(t=>Object.is(t,i))}function v(t){const i=[];for(const e of t)m(i,e)||i.push(e);return i}function b(t){try{return JSON.stringify(t)}catch(i){return t+""}}const g="user_id",w="anonymous_id",k="user_attributes";class S{constructor(t,i,e,s){this.pending=new f,this.userId=null,this.attributes={},this.storage=t,this.logger=i,this.anonymousId=s||this.storage.get(w)||o(),this.storage.get(w)||(this.storage.set(w,this.anonymousId),this.logger.debug("Generated new anonymous ID: "+this.anonymousId)),this.userId=e||this.storage.get(g)||null,this.userId&&this.logger.debug("Loaded user ID: "+this.userId),this.attributes={},this.storage.remove(k)}identify(t,i){const e=this.userId;this.userId=t,this.storage.set(g,t),i&&this.setAttributes(i),e!==t&&this.logger.info(`User identified: ${t} (was: ${e||"anonymous"})`)}reset(){this.logger.debug(`Resetting identity (was: ${this.userId||"anonymous"})`),this.userId=null,this.attributes={},this.anonymousId=o(),this.storage.remove(g),this.storage.remove(k),this.storage.set(w,this.anonymousId),this.logger.debug("New anonymous ID: "+this.anonymousId)}adopt(t,i){t!==this.anonymousId&&(this.attributes={}),this.anonymousId=t,this.userId=i}setAttributes(t){t&&"object"==typeof t&&!Array.isArray(t)?(this.attributes=Object.assign(Object.assign({},this.attributes),t),this.logger.debug("Updated user attributes:",this.attributes)):this.logger.error("setAttributes requires a plain object")}setAttribute(t,i){this.attributes[t]=i,this.logger.debug(`Set attribute: ${t} = ${i}`)}incrementAttribute(t,i=1){const e=this.attributes[t],s="number"==typeof e?e:0;this.setAttribute(t,s+i),this.logger.debug(`Incremented attribute: ${t} by ${i} (now: ${this.attributes[t]})`)}unsetAttribute(t){delete this.attributes[t],this.logger.debug("Unset attribute: "+t)}addToArray(t,i){const e=this.attributes[t];let s=[];Array.isArray(e)?s=[...e]:null!=e&&(this.logger.warn(`Attribute ${t} is not an array, converting to array`),s=[e]),s.includes(i)?this.logger.debug(`Value already exists in array: ${t} = ${i}`):(s.push(i),this.setAttribute(t,s),this.logger.debug(`Added to array: ${t} = ${i}`))}removeFromArray(t,i){const e=this.attributes[t];if(!Array.isArray(e))return void this.logger.warn(`Attribute ${t} is not an array, cannot remove value`);const s=e.filter(t=>t!==i);s.length!==e.length?(this.setAttribute(t,s),this.logger.debug(`Removed from array: ${t} = ${i}`)):this.logger.debug(`Value not found in array: ${t} = ${i}`)}getIdentity(){return{userId:this.userId,anonymousId:this.anonymousId,attributes:Object.assign({},this.attributes)}}getUserId(){return this.userId}getAnonymousId(){return this.anonymousId}getAttributes(){return Object.assign({},this.attributes)}getAttribute(t){return this.attributes[t]}isIdentified(){return null!==this.userId}}function j(t){return!!t&&"object"==typeof t&&!Array.isArray(t)&&!1===t.success}function A(t){return{userId:t.userId,anonymousId:t.anonymousId,attributes:t.attributes||{}}}function I(t){let i=0;for(let e=0;e<t.length;e++){const s=t.charCodeAt(e);128>s?i+=1:2048>s?i+=2:55296>s||s>56319?i+=3:(i+=4,e++)}return i}function O(t,i=Date.now()){if(!t)return;const e=+t;if(Number.isFinite(e)&&e>=0)return Math.round(1e3*e);const s=Date.parse(t);return Number.isFinite(s)?Math.max(0,s-i):void 0}const $="X-Joryio-Auth",D=2592e6;function _(t,i=Date.now()){if("string"==typeof t)return t?{token:t,at:i}:null;if(!t||"object"!=typeof t)return null;const{token:e,at:s,standby:n}=t;return"string"==typeof e&&e&&"number"==typeof s&&Number.isFinite(s)?!0===n?{token:e,at:s,standby:!0}:{token:e,at:s}:null}function T(t){var i;const e=null===(i=C(t))||void 0===i?void 0:i.sub;return"string"==typeof e&&e?e:null}function C(t){if(!t)return null;try{const i=t.split(".")[1];if(!i)return null;const e=i.replace(/-/g,"+").replace(/_/g,"/"),s=e+"=".repeat((4-e.length%4)%4),n="function"==typeof atob?atob:t=>globalThis.Buffer.from(t,"base64").toString("binary"),r=decodeURIComponent(Array.prototype.map.call(n(s),t=>"%"+("00"+t.charCodeAt(0).toString(16)).slice(-2)).join("")),o=JSON.parse(r);return o&&"object"==typeof o&&!Array.isArray(o)?o:null}catch(t){return null}}function x(t,i){const e=((t||"")+"").split("?")[0],s=i&&"object"==typeof i?i:{};if(e.endsWith("/v1/push/unregister"))return!0;if(e.endsWith("/v1/subscriptions/channel"))return"unsubscribed"===s.status;if(e.endsWith("/v1/subscriptions/group"))return"unsubscribe"===s.action;if(e.endsWith("/v1/attributes")){if(["increment","append","remove","unset"].some(t=>null!=s[t]&&Object.keys(s[t]).length>0))return!1;const t=s.attributes;if(!t||"object"!=typeof t||Array.isArray(t))return!1;const i=Object.keys(t);return i.length>0&&i.every(i=>"tracking_opted_out"===i&&!0===t[i])}return!1}const P={failureThreshold:5,cooldownMs:3e4};class M{constructor(t,i,e,s){this.circuitState="closed",this.consecutiveFailures=0,this.circuitOpenedAt=0,this.sdkAuthEnabled=!1,this.sdkAuthFailureCallback=null,this.retiredSdkAuthTokens=new Map,this.retiredTokenStore=null,this.sdkAuthTokenUser=null,this.keepaliveBytesInFlight=0,this.currentUserId=null,this.suspended=!1,this.sdkKey=t,this.logger=i,this.retryConfig=e,this.circuitBreakerConfig=Object.assign(Object.assign({},P),s)}setSdkAuthenticationEnabled(t){this.sdkAuthEnabled=t}setSdkAuthenticationToken(t){const i="string"==typeof t&&t?t:void 0,e=this.sdkAuthToken;if(e&&i&&e!==i){const t=T(e),s=T(i),n=t||this.sdkAuthTokenUser,r=t&&s?t!==s:!!n&&n!==this.currentUserId;n&&r&&this.retireToken(n,e)}this.sdkAuthToken=i,this.sdkAuthTokenUser=i?this.currentUserId:null}retireSdkAuthToken(){const t=T(this.sdkAuthToken),i=t||this.currentUserId,e=!!t&&t!==this.currentUserId;i&&this.sdkAuthToken&&this.retireToken(i,this.sdkAuthToken,e),this.sdkAuthToken=void 0,this.sdkAuthTokenUser=null}retireToken(t,i,e=!1){const s=new Map,n=this.retiredSdkAuthTokens.get(t);for(n&&n.token!==i&&s.set(t,n.token),this.retiredSdkAuthTokens.delete(t),this.retiredSdkAuthTokens.set(t,e?{token:i,at:Date.now(),standby:!0}:{token:i,at:Date.now()});this.retiredSdkAuthTokens.size>4;){const t=this.retiredSdkAuthTokens.keys().next().value;s.set(t,this.retiredSdkAuthTokens.get(t).token),this.retiredSdkAuthTokens.delete(t)}this.saveRetiredTokens(s)}switchUser(t){const i=this.currentUserId;if(i&&i!==t&&this.sdkAuthToken){const i=T(this.sdkAuthToken);t&&i===t||this.retireSdkAuthToken()}if(this.currentUserId=t,!this.sdkAuthToken&&t){const i=this.retiredSdkAuthTokens.get(t);i&&T(i.token)===t&&(this.sdkAuthToken=i.token,this.sdkAuthTokenUser=t)}this.adoptStandbyToken(t)}adoptStandbyToken(t){if(!t)return;const i=this.retiredSdkAuthTokens.get(t);i&&i.standby&&T(i.token)===t&&(this.retiredSdkAuthTokens.set(t,{token:i.token,at:i.at}),this.saveRetiredTokens())}dropStandbySdkAuthTokens(t=new Set){if(this.retiredSdkAuthTokens.forEach((i,e)=>{i.standby&&!t.has(e)&&this.retiredSdkAuthTokens.delete(e)}),this.retiredTokenStore)try{this.retiredTokenStore.update(i=>{const e={},s=Date.now();for(const n of Object.keys(i||{})){const r=_(i[n],s);!r||r.standby&&!t.has(n)||s-r.at>D||(e[n]=r)}return e})}catch(t){this.logger.warn("Could not store the SDK authentication tokens:",t)}}setRetiredTokenStore(t){if(this.retiredTokenStore=t,!t)return;let i=null;try{i=t.load()}catch(t){this.logger.warn("Could not read the stored SDK authentication tokens:",t)}if(!i||"object"!=typeof i)return;const e=Date.now();for(const t of Object.keys(i)){const s=_(i[t],e);s&&e-s.at<=D&&(this.retiredSdkAuthTokens.has(t)||this.retiredSdkAuthTokens.set(t,s))}}retiredSdkAuthUsers(){return Array.from(this.retiredSdkAuthTokens.keys())}forgetRetiredSdkAuthTokensExcept(t,i=Date.now()){const e=new Map;let s=null;return this.retiredSdkAuthTokens.forEach((n,r)=>{const o=i-n.at;o>D?e.set(r,n.token):n.standby||t.has(r)||(6e4>o?s=Math.min(null!=s?s:1/0,6e4-o):e.set(r,n.token))}),e.forEach((t,i)=>this.retiredSdkAuthTokens.delete(i)),e.size&&this.saveRetiredTokens(e),s}saveRetiredTokens(t=new Map){if(this.retiredTokenStore)try{this.retiredTokenStore.update(i=>{const e={},s=Date.now();for(const n of Object.keys(i||{})){const r=_(i[n],s);r&&s-r.at<=D&&t.get(n)!==r.token&&(e[n]=r)}return this.retiredSdkAuthTokens.forEach((t,i)=>{const n=_(e[i],s);if(!n||n.token===t.token)return void(e[i]=Object.assign({},t));const r=function(t,i){const e=C(t),s=C(i),n=t=>"number"==typeof t&&Number.isFinite(t)?t:null;for(const r of["exp","iat"]){const o=n(null==e?void 0:e[r]),h=n(null==s?void 0:s[r]);if(null!==o&&null!==h&&o!==h)return o>h?t:i}return null}(n.token,t.token);(r?r!==t.token:n.at>t.at)?this.retiredSdkAuthTokens.set(i,n):e[i]=Object.assign({},t)}),e})}catch(t){this.logger.warn("Could not store the SDK authentication tokens:",t)}}sdkAuthTokenFor(t){var i;const e=void 0===t?this.currentUserId:t;if(!e)return;const s=this.sdkAuthEnabled?this.sdkAuthToken:void 0,n=T(s);return s&&n===e?s:!s||n||e!==this.currentUserId||null!==this.sdkAuthTokenUser&&this.sdkAuthTokenUser!==e?null===(i=this.retiredSdkAuthTokens.get(e))||void 0===i?void 0:i.token:s}getCurrentUserId(){return this.currentUserId}setSdkAuthenticationFailureCallback(t){this.sdkAuthFailureCallback=t}setCurrentUserId(t){this.currentUserId=t,this.adoptStandbyToken(t)}isSuspended(){return this.suspended}noteSuspended(t,i){return 402===t&&(this.suspended||(this.suspended=!0,console.warn(`[Joryio SDK] The API refused this request with 402 ${(null==i?void 0:i.code)||""} - event ingestion is paused for this workspace. Nothing more will be sent this page view; queued events are kept.`)),!0)}getSdkAuthHeaders(t){const i=this.sdkAuthTokenFor(t);return i?{[$]:i}:{}}keepaliveBudget(){return Math.max(0,61440-this.keepaliveBytesInFlight)}isSdkAuthError(t,i){return 401===t&&!!i&&"object"==typeof i&&"sdk_authentication_error"===i.error}async refreshSdkAuthToken(t){if(!this.sdkAuthEnabled||!this.sdkAuthFailureCallback)return;const i=this.sdkAuthToken;let e;try{e=await Promise.resolve(this.sdkAuthFailureCallback(t))}catch(t){return void this.logger.error("SDK authentication failure callback threw:",t)}"string"==typeof e&&e&&this.setSdkAuthenticationToken(e);const s=this.sdkAuthToken;return s&&s!==i?s:void 0}async request(t){var i,e;if(this.suspended&&!x(t.url,t.body))return{ok:!1,status:402,error:"Ingestion suspended",data:{code:"SDK_INGESTION_SUSPENDED"}};if("open"===this.circuitState){const t=Date.now()-this.circuitOpenedAt;if(t<this.circuitBreakerConfig.cooldownMs)return this.logger.warn(`Circuit breaker OPEN – failing fast (${Math.round((this.circuitBreakerConfig.cooldownMs-t)/1e3)}s remaining)`),{ok:!1,status:0,error:"Circuit breaker is open – API requests are temporarily blocked"};this.circuitState="half-open",this.logger.info("Circuit breaker transitioning to HALF-OPEN – allowing probe request")}const{url:s,method:n="POST",headers:r={}}=t;let o;try{o=t.body?JSON.stringify(t.body):void 0}catch(t){return this.logger.error(`Request to ${s} not sent: its body cannot be serialized`,t),{ok:!1,status:400,error:"The request body cannot be serialized"}}const h=void 0===t.subjectUserId||(t.subjectUserId||null)===this.currentUserId;let a,u,d=null,l=0,c=0,p=!1;for(;c<=this.retryConfig.maxRetries;){try{this.logger.debug(`Request attempt ${c+1}/${this.retryConfig.maxRetries+1}: ${n} ${s}`);let{response:f,responseData:y}=await this.performFetch(s,n,r,o,t.subjectUserId);if(!p&&this.sdkAuthEnabled&&h&&this.isSdkAuthError(f.status,y)&&(p=!0,this.logger.warn(`SDK authentication rejected (${(null==y?void 0:y.reason)||"invalid"}) on ${s} – refreshing token`),await this.refreshSdkAuthToken({reason:(null==y?void 0:y.reason)||(this.sdkAuthToken?"invalid":"missing"),endpoint:s,userId:void 0===t.subjectUserId?this.currentUserId:t.subjectUserId||null})&&(this.logger.debug("SDK authentication token refreshed – retrying request once"),({response:f,responseData:y}=await this.performFetch(s,n,r,o,t.subjectUserId)))),f.ok)return this.onRequestSuccess(),j(y)?(this.logger.warn(`Request to ${s} answered ${f.status} with success: false`),{ok:!1,status:f.status,data:y,error:(null==y?void 0:y.error)||(null==y?void 0:y.message)||"The server reported success: false",softFailure:!0}):(this.logger.debug("Request successful: "+f.status),{ok:!0,status:f.status,data:y});if(!this.shouldRetry(f.status))return this.logger.warn("Request failed with non-retryable status: "+f.status),this.noteSuspended(f.status,y),{ok:!1,status:f.status,error:(null==y?void 0:y.message)||f.statusText,data:y};l=f.status,a=y,u=O(null===(e=null===(i=f.headers)||void 0===i?void 0:i.get)||void 0===e?void 0:e.call(i,"retry-after")),d=Error(`HTTP ${f.status}: ${f.statusText}`),this.logger.warn(`Request failed (attempt ${c+1}): ${d.message}`)}catch(t){d=t,l=0,a=void 0,u=void 0,this.logger.error(`Request error (attempt ${c+1}):`,t)}if(c<this.retryConfig.maxRetries){const t=Math.max(this.calculateBackoff(c),Math.min(null!=u?u:0,3e4));this.logger.debug(`Retrying in ${t}ms...`),await this.sleep(t)}c++}return this.onRequestFailure(),this.logger.error(`Request failed after ${this.retryConfig.maxRetries+1} attempts`),Object.assign({ok:!1,status:l,data:a,error:(null==d?void 0:d.message)||"Network request failed"},void 0!==u?{retryAfterMs:u}:{})}onRequestSuccess(){(this.consecutiveFailures>0||"closed"!==this.circuitState)&&this.logger.info(`Circuit breaker CLOSED – request succeeded after ${this.consecutiveFailures} consecutive failure(s)`),this.consecutiveFailures=0,this.circuitState="closed",this.circuitOpenedAt=0}onRequestFailure(){if(this.consecutiveFailures++,"half-open"===this.circuitState)return this.circuitState="open",this.circuitOpenedAt=Date.now(),void this.logger.warn(`Circuit breaker re-OPENED – probe request failed (${this.consecutiveFailures} consecutive failures)`);this.consecutiveFailures<this.circuitBreakerConfig.failureThreshold||(this.circuitState="open",this.circuitOpenedAt=Date.now(),this.logger.warn(`Circuit breaker OPENED – ${this.consecutiveFailures} consecutive failures reached threshold of ${this.circuitBreakerConfig.failureThreshold}`))}getCircuitBreakerState(){return{state:this.circuitState,consecutiveFailures:this.consecutiveFailures,openedAt:this.circuitOpenedAt}}async performFetch(t,i,e,s,n){const r=new AbortController,o=setTimeout(()=>r.abort(),this.retryConfig.timeoutMs||1e4),h=Object.assign({"Content-Type":"application/json","X-SDK-Key":this.sdkKey},e),a=this.sdkAuthTokenFor(n);let u;a&&(h[$]=a);try{u=await fetch(t,{method:i,headers:h,body:s,signal:r.signal,credentials:"omit"})}finally{clearTimeout(o)}return{response:u,responseData:await this.parseResponse(u)}}async parseResponse(t){var i,e;const s=null===(e=null===(i=t.headers)||void 0===i?void 0:i.get)||void 0===e?void 0:e.call(i,"content-type");if(s&&s.includes("application/json"))try{return await t.json()}catch(t){return this.logger.warn("Failed to parse JSON response"),null}return await t.text()}shouldRetry(t){return 408===t||429===t||t>=500}calculateBackoff(t){const{backoffMs:i,maxBackoffMs:e=3e4}=this.retryConfig,s=Math.min(i*Math.pow(2,t),e),n=.25*s*(2*Math.random()-1);return Math.max(0,Math.floor(s+n))}sleep(t){return new Promise(i=>setTimeout(i,t))}async sendEvents(t,i,e){var s;const n={events:i};return e&&(n.identify=A(e)),this.request({url:t+"/v1/track/batch",method:"POST",body:n,subjectUserId:(null==e?void 0:e.userId)||(null===(s=i.find(t=>t&&t.userId))||void 0===s?void 0:s.userId)||null})}supportsKeepalive(){try{return"function"==typeof fetch&&"undefined"!=typeof Request&&"keepalive"in Request.prototype}catch(t){return!1}}sendEventsKeepalive(t,i,e){const s={events:i};return e&&(s.identify=A(e)),this.postKeepalive(t+"/v1/track/batch",s)}postKeepalive(t,i){if(this.suspended&&!x(t,i)||!this.supportsKeepalive())return null;let e;try{e=JSON.stringify(i)}catch(t){return null}const s=I(e)+256;if(this.keepaliveBytesInFlight+s>61440)return null;const n={"Content-Type":"application/json","X-SDK-Key":this.sdkKey},r=this.sdkAuthTokenFor(function(t){if(!t||"object"!=typeof t)return null;if("string"==typeof t.userId&&t.userId)return t.userId;if("string"==typeof t.externalId&&t.externalId)return t.externalId;if(t.identify&&"string"==typeof t.identify.userId&&t.identify.userId)return t.identify.userId;for(const i of[t.events,t.impressions])if(Array.isArray(i)){const t=i.find(t=>t&&"string"==typeof t.userId&&t.userId);if(t)return t.userId}return null}(i));r&&(n[$]=r);try{this.keepaliveBytesInFlight+=s;let i=!1;const r=()=>{i||(i=!0,this.keepaliveBytesInFlight=Math.max(0,this.keepaliveBytesInFlight-s))};return fetch(t,{method:"POST",headers:n,body:e,keepalive:!0,credentials:"omit"}).then(async t=>{r();const i=await this.parseResponse(t).catch(()=>null),e=t.ok&&j(i);return Object.assign({ok:t.ok&&!e,status:t.status,data:i},e?{softFailure:!0}:{})},t=>(r(),{ok:!1,status:0,error:((null==t?void 0:t.message)||t)+""}))}catch(t){return this.keepaliveBytesInFlight=Math.max(0,this.keepaliveBytesInFlight-s),this.logger.warn("keepalive request could not be started:",t),null}}async sendIdentify(t,i,e,s){return this.request({url:t+"/v1/identify",method:"POST",body:{userId:i,attributes:e,anonymousId:s},subjectUserId:i})}async sendAddAlias(t,i){return this.request({url:t+"/v1/alias/add",method:"POST",body:i,subjectUserId:i.userId||null})}async sendDeviceSession(t,i){return this.request({url:t+"/v1/device/session",method:"POST",body:i})}async sendSetAttributes(t,i,e,s){return this.request({url:t+"/v1/attributes",method:"POST",body:Object.assign({userId:e||void 0,anonymousId:e?void 0:s},i),subjectUserId:e||null})}async sendSubscriptionUpdate(t,i){return this.request({url:t+"/v1/subscriptions/channel",method:"POST",body:i,subjectUserId:i.userId||null})}async sendSubscriptionGroupUpdate(t,i){return this.request({url:t+"/v1/subscriptions/group",method:"POST",body:i,subjectUserId:i.userId||null})}}const K="event_queue",F="event_queue_inflight",N="pending_identify",q=921600,E=3e5;function U(t,i){return i.every(i=>i.anonymousId===t.anonymousId&&(!i.userId||i.userId===t.userId))}class z{constructor(t,i,e,s,n=!0,r=1e3,o=1e3){if(this.queue=[],this.flushTimer=null,this.flushCallback=null,this.pendingPersist=!1,this.persistTimer=null,this.isFlushing=!1,this.flushWaiters=[],this.pendingIdentifies=[],this.inflightEvents=[],this.paused=!1,this.suspended=!1,this.consecutiveFailures=0,this.nextAttemptAt=0,this.retryAfterUntil=0,this.generation=0,this.clearedInflightCallback=null,this.storage=t,this.logger=i,this.batchSize=e>0?Math.floor(e):50,this.flushInterval=s,this.persistQueue=n,this.maxQueueSize=r>0?Math.floor(r):1e3,this.retryBackoffMs=o>0?o:1e3,this.persistQueue){const t=this.storage.get(F)||[],i=this.storage.get(K)||[];this.queue=[...t,...i],t.length>0&&(this.storage.remove(F),this.logger.debug(`Recovered ${t.length} in-flight events from previous page`)),this.queue.length>this.maxQueueSize&&(this.queue=this.queue.slice(-this.maxQueueSize)),this.queue.length>0&&(this.logger.debug(`Loaded ${this.queue.length} events from storage`),this.persistQueueToStorage());const e=this.storage.get(N),s=Array.isArray(e)?e:e?[e]:[];this.pendingIdentifies=s.filter(t=>t&&"string"==typeof t.userId&&"string"==typeof t.anonymousId).slice(-20),this.pendingIdentifies.length&&this.logger.debug(`Recovered ${this.pendingIdentifies.length} pending identify(s) from a previous page`)}}setFlushCallback(t){this.flushCallback=t}setPaused(t){this.paused=t}isPaused(){return this.paused}isSuspended(){return this.suspended}isBackingOff(){return this.consecutiveFailures>0||Date.now()<this.retryAfterUntil}resetBackoff(){this.consecutiveFailures=0,this.nextAttemptAt=0}setPendingIdentify(t){const i=this.pendingIdentifies[this.pendingIdentifies.length-1],e={userId:t.userId,anonymousId:t.anonymousId,attributes:t.attributes||{}};if(!i||i.userId!==e.userId||i.anonymousId!==e.anonymousId){if(this.pendingIdentifies.push(e),this.pendingIdentifies.length>20){const t=this.pendingIdentifies.shift();this.logger.warn(`Too many identify calls waiting to be sent; dropped the oldest (${t.userId})`)}this.persistIdentifies()}}persistIdentifies(){if(this.persistQueue)try{this.pendingIdentifies.length?this.storage.set(N,this.pendingIdentifies):this.storage.remove(N)}catch(t){this.logger.error("Failed to persist pending identify:",t)}}getPendingIdentify(){return this.pendingIdentifies[0]||null}getPendingIdentifies(){return[...this.pendingIdentifies]}removeIdentify(t){const i=this.pendingIdentifies.indexOf(t);0>i||this.pendingIdentifies.splice(i,1),this.persistIdentifies()}identifyAttemptFailed(t,i){i?(t.attempts=(t.attempts||0)+1,10>t.attempts?this.persistIdentifies():(this.logger.error(`Identify for ${t.userId} failed ${t.attempts} times; dropping it`),this.removeIdentify(t))):this.persistIdentifies()}start(){this.flushTimer?this.logger.debug("Queue manager already started"):(this.flushTimer=setInterval(()=>{this.flush().catch(t=>this.logger.error("Scheduled flush failed:",t))},this.flushInterval),this.logger.debug(`Queue manager started (batch: ${this.batchSize}, interval: ${this.flushInterval}ms)`),(this.queue.length>0||this.pendingIdentifies.length)&&this.flush().catch(t=>this.logger.error("Startup flush failed:",t)))}isStarted(){return null!==this.flushTimer}stop(){this.flushTimer&&(clearInterval(this.flushTimer),this.flushTimer=null,this.logger.debug("Queue manager stopped")),this.persistNow()}enqueue(t){this.queue.push(t),this.logger.debug(`Event queued: ${t.type} (queue size: ${this.queue.length})`),this.schedulePersist(),this.trimToMax(),this.queue.length<this.batchSize||this.isFlushing||(this.logger.debug("Batch size reached, flushing queue"),this.flush())}trimToMax(){if(this.queue.length>this.maxQueueSize){const t=this.queue.length-this.maxQueueSize;this.queue=this.queue.slice(-this.maxQueueSize),this.logger.warn(`Queue exceeded max size (${this.maxQueueSize}), dropped ${t} oldest event(s)`),this.schedulePersist()}}takeBatch(){const t=Math.min(this.batchSize,500),i=[];let e=64,s=null;for(;this.queue.length>0&&i.length<t;){const t=this.queue[0];if(i.length>0){if(t.anonymousId!==i[0].anonymousId)break;if(t.userId&&s&&t.userId!==s)break}let n;try{n=I(JSON.stringify(t))+1}catch(t){n=1/0}if(n>q)this.queue.shift(),this.logger.error(`Dropping event "${t.type}": it is too large to send (${n} bytes)`);else{if(i.length>0&&e+n>q)break;i.push(this.queue.shift()),t.userId&&(s=t.userId),e+=n}}return i}restoreToFront(t){if(!t.length)return;const i=new Set(this.queue.map(t=>t.eventId)),e=t.filter(t=>!i.has(t.eventId));this.queue.unshift(...e),this.trimToMax()}backOff(t){this.consecutiveFailures++;const i=Math.min(this.retryBackoffMs*Math.pow(2,Math.min(this.consecutiveFailures-1,20)),E),e=.2*i*Math.random(),s=Math.max(i+e,Math.min(null!=t?t:0,E));this.nextAttemptAt=Date.now()+s,t&&t>0&&(this.retryAfterUntil=Date.now()+Math.min(t,E)),this.logger.debug(`Event send failed; next attempt in ${Math.round(s)}ms`)}async sendBatch(t,i,e=[]){let s;this.inflightEvents=e.length?[...t,...e]:t,this.persistQueue&&(this.persistQueueToStorage(),this.persistInflightToStorage());try{s=await this.flushCallback(t,null!=i?i:void 0)||{status:"ok"}}catch(t){this.logger.error("Failed to flush events:",t),s={status:"retry"}}return this.inflightEvents=[],this.persistQueue&&this.storage.remove(F),s}async flush(t=!1,i=!1){var e,s;if(0===this.queue.length&&!this.pendingIdentifies.length&&!this.isFlushing)return;if(this.paused||this.suspended){if(t)throw Error(this.paused?"Sending is paused":"Sending is suspended");return}if(this.isFlushing)return await new Promise(t=>this.flushWaiters.push(t)),this.queue.length>0||this.pendingIdentifies.length?this.flush(t,i):void 0;const n=Date.now();if(n<this.retryAfterUntil||!i&&n<this.nextAttemptAt||"undefined"!=typeof navigator&&!1===navigator.onLine){if(t)throw Error("Waiting to retry");return}if(!this.flushCallback)return void this.logger.warn("No flush callback set, cannot flush queue");this.isFlushing=!0;let r=null;const o=this.generation;try{let t=null;const i=[];let n=this.queue.length;const h=new Set;for(;;){let a;i.length>0?a=i.shift():n>0?(a=this.takeBatch(),n-=a.length,0===a.length&&(n=0)):a=this.pendingIdentifies[0]&&!h.has(this.pendingIdentifies[0])&&this.pendingIdentifies[0]!==t&&this.queue.length>0&&U(this.pendingIdentifies[0],[this.queue[0]])?this.takeBatch():[];const u=this.pendingIdentifies[0]||null;let d=null;if(u&&!h.has(u)&&(0===a.length||u!==t&&U(u,a))&&(d=u),0===a.length&&!d)break;0===a.length&&d&&h.add(d),this.logger.debug(`Flushing ${a.length} events${d?" + identify":""}`);const l=await this.sendBatch(a,d,i.flat());if(this.generation!==o){if(this.logger.debug("Queue cleared during a flush; the in-flight batch is not restored"),this.clearedInflightCallback){let t=[];if("ok"===l.status){const i=new Set([...l.failedIndices||[],...l.rejectedIndices||[]]);t=a.filter((t,e)=>!i.has(e))}try{this.clearedInflightCallback(t)}catch(t){this.logger.warn("Cleared in-flight callback failed:",t)}}break}if("dropped"!==l.status){if("ok"===l.status){const t=t=>new Set((t||[]).filter(t=>Number.isInteger(t)&&t>=0&&t<a.length)),e=t(l.rejectedIndices);for(const t of e)this.logger.error(`Event "${a[t].type}" was refused by the server for good and has been dropped`);const s=[...t(l.failedIndices)].filter(t=>!e.has(t)).map(t=>a[t]);if(d&&l.identifyDropped&&(this.logger.error(`Identify for ${d.userId} was refused by the server; dropping it`),this.removeIdentify(d),d=null),d&&l.identifyFailed){this.identifyAttemptFailed(d,!1!==l.identifyAttemptCounts),this.restoreToFront([...s,...i.flat()]),this.backOff(),r="The identify was not confirmed";break}if(d&&this.removeIdentify(d),this.consecutiveFailures=0,this.nextAttemptAt=0,s.length>0){this.logger.warn(`${s.length} of ${a.length} events were not stored by the server; will retry them`),this.restoreToFront([...s,...i.flat()]),this.backOff(),r="Some events were not stored";break}continue}if("rejected"!==l.status){this.restoreToFront([...a,...i.flat()]),d&&"retry"===l.status&&this.identifyAttemptFailed(d,!0===l.counts),"suspended"===l.status?(this.suspended||(this.suspended=!0,console.warn(`[Joryio SDK] Event sending stopped for this page view (${l.reason||"refused"}). `+this.queue.length+" queued event(s) are kept.")),this.flushTimer&&(clearInterval(this.flushTimer),this.flushTimer=null),r="Sending is suspended"):(this.backOff(l.retryAfterMs),r="Events could not be delivered; will retry");break}if(d){if(0===a.length){this.logger.error(`Identify for ${d.userId} was refused by the server (HTTP ${null!==(e=l.httpStatus)&&void 0!==e?e:"4xx"}); dropping it`),this.removeIdentify(d);continue}t=d,i.unshift(a);continue}if(a.length>1){const t=Math.ceil(a.length/2);i.unshift(a.slice(0,t),a.slice(t));continue}1===a.length&&this.logger.error(`Event "${a[0].type}" was refused by the server (HTTP ${null!==(s=l.httpStatus)&&void 0!==s?s:"4xx"}) and has been dropped`)}else this.logger.error(`${a.length} event(s)${d?" and an identify":""} of a user who is no longer signed in were refused by SDK authentication (${l.reason||"401"}) and have been dropped`),d&&this.removeIdentify(d)}this.persistQueue&&this.persistQueueToStorage()}finally{this.isFlushing=!1;const t=this.flushWaiters;this.flushWaiters=[],t.forEach(t=>t())}if(r&&t)throw Error(r)}persistQueueToStorage(){this.pendingPersist=!1,null!==this.persistTimer&&(clearTimeout(this.persistTimer),this.persistTimer=null);try{this.storage.set(K,this.queue)}catch(t){this.logger.error("Failed to persist queue to storage:",t)}}schedulePersist(){this.persistQueue&&!this.pendingPersist&&(this.pendingPersist=!0,this.persistTimer=setTimeout(()=>{this.persistTimer=null,this.pendingPersist&&this.persistQueueToStorage()},150))}persistNow(){this.persistQueue&&this.pendingPersist&&this.persistQueueToStorage()}persistInflightToStorage(){try{this.inflightEvents.length>0?this.storage.set(F,this.inflightEvents):this.storage.remove(F)}catch(t){this.logger.error("Failed to persist in-flight events to storage:",t)}}getQueueSize(){return this.queue.length}getQueuedEvents(){return[...this.inflightEvents,...this.queue]}getWaitingEvents(){return[...this.queue]}getInflightEvents(){return[...this.inflightEvents]}setClearedInflightCallback(t){this.clearedInflightCallback=t}markHandedOff(t,i){const e=new Set(t.map(t=>t.eventId));this.queue=this.queue.filter(t=>!e.has(t.eventId)),this.inflightEvents=this.inflightEvents.filter(t=>!e.has(t.eventId)),i&&this.removeIdentify(i),this.persistQueue&&(this.persistQueueToStorage(),this.persistInflightToStorage())}takeBack(t,i){this.restoreToFront(t),i&&!this.pendingIdentifies.includes(i)&&(this.pendingIdentifies.unshift(i),this.persistIdentifies()),this.persistQueue&&this.persistQueueToStorage()}clear(){this.generation++,this.queue=[],this.inflightEvents=[],this.persistQueue&&(this.storage.remove(K),this.storage.remove(F),this.storage.remove(N)),this.pendingIdentifies=[],this.logger.debug("Queue cleared")}async destroy(){this.stop(),this.queue.length>0&&(this.logger.debug("Flushing remaining events before destroy"),await this.flush())}}const R="first_touch_utm",J="last_touch_utm",H="session_utm",W="session_referrer",L="session_landing_page";class B{constructor(t,i,e=!1){this.newCampaignDetected=!1,this.storage=t,this.logger=i,this.resetSessionOnNewCampaign=e,this.resetSessionOnNewCampaign&&(this.newCampaignDetected=this.detectNewCampaign()),this.captureUTMParameters()}captureUTMParameters(){if("undefined"==typeof window)return;const t=new URLSearchParams(window.location.search),i={};let e=!1;const s=["utm_source","utm_medium","utm_campaign","utm_content","utm_term"];for(const n of s){const s=t.get(n);s&&(i[n]=s,e=!0)}document.referrer&&(i.referrer=document.referrer),i.landing_page=window.location.href,i.captured_at=Date.now(),e?(this.logger.debug("Captured UTM parameters:",i),this.storage.set(H,i),this.storage.set(W,i.referrer||null),this.storage.set(L,i.landing_page),this.storage.get(R)||(this.storage.set(R,i),this.logger.debug("Set first touch UTM:",i)),this.storage.set(J,i),this.logger.debug("Updated last touch UTM:",i)):this.storage.get(H)||(this.storage.set(H,i),this.storage.set(W,i.referrer||null),this.storage.set(L,i.landing_page),this.logger.debug("Captured session referrer and landing page"))}getUTMData(){return{current:this.storage.get(H)||null,firstTouch:this.storage.get(R)||null,lastTouch:this.storage.get(J)||null}}getCurrentUTM(){return this.storage.get(H)||null}getFirstTouchUTM(){return this.storage.get(R)||null}getLastTouchUTM(){return this.storage.get(J)||null}getSessionReferrer(){return this.storage.get(W)||null}getSessionLandingPage(){return this.storage.get(L)||null}hasNewCampaign(){return this.newCampaignDetected}detectNewCampaign(){if("undefined"==typeof window)return!1;const t=new URLSearchParams(window.location.search),i=this.getCurrentUTM();if(!i)return t.has("utm_source")||t.has("utm_medium")||t.has("utm_campaign");const e=["utm_source","utm_medium","utm_campaign","utm_content","utm_term"];for(const s of e){const e=t.get(s),n=i[s];if(e&&e!==n)return!0}return!1}updateUTM(){this.resetSessionOnNewCampaign&&(this.newCampaignDetected=this.detectNewCampaign()),this.captureUTMParameters()}clearSessionUTM(){this.storage.remove(H),this.storage.remove(W),this.storage.remove(L),this.logger.debug("Cleared session UTM")}clearAllUTM(){this.storage.remove(H),this.storage.remove(R),this.storage.remove(J),this.storage.remove(W),this.storage.remove(L),this.logger.debug("Cleared all UTM data")}reset(){this.clearAllUTM()}getUTMProperties(){const t=this.getCurrentUTM(),i=this.getFirstTouchUTM(),e=this.getLastTouchUTM(),s={};return t&&(t.utm_source&&(s.utm_source=t.utm_source),t.utm_medium&&(s.utm_medium=t.utm_medium),t.utm_campaign&&(s.utm_campaign=t.utm_campaign),t.utm_content&&(s.utm_content=t.utm_content),t.utm_term&&(s.utm_term=t.utm_term),t.referrer&&(s.referrer=t.referrer),t.landing_page&&(s.landing_page=t.landing_page)),i&&(i.utm_source&&(s.first_touch_utm_source=i.utm_source),i.utm_medium&&(s.first_touch_utm_medium=i.utm_medium),i.utm_campaign&&(s.first_touch_utm_campaign=i.utm_campaign),i.utm_content&&(s.first_touch_utm_content=i.utm_content),i.utm_term&&(s.first_touch_utm_term=i.utm_term),i.referrer&&(s.first_touch_referrer=i.referrer),i.landing_page&&(s.first_touch_landing_page=i.landing_page),i.captured_at&&(s.first_touch_captured_at=new Date(i.captured_at).toISOString())),e&&e!==t&&(e.utm_source&&(s.last_touch_utm_source=e.utm_source),e.utm_medium&&(s.last_touch_utm_medium=e.utm_medium),e.utm_campaign&&(s.last_touch_utm_campaign=e.utm_campaign),e.utm_content&&(s.last_touch_utm_content=e.utm_content),e.utm_term&&(s.last_touch_utm_term=e.utm_term),e.referrer&&(s.last_touch_referrer=e.referrer),e.landing_page&&(s.last_touch_landing_page=e.landing_page),e.captured_at&&(s.last_touch_captured_at=new Date(e.captured_at).toISOString())),s}}const V="__joryioInApp",Q="inapp_impressions";function G(t,i){var e,s;const n=t=>t.split(",").map(t=>{const e=t.trim();return e?/^(?:html|body|:root)$/i.test(e)?i:`${i} ${e}`:""}).filter(Boolean).join(", "),r=[];for(let o=0;o<t.length;o++){const h=t[o];if(void 0!==h.selectorText&&h.style){const t=n(h.selectorText);t&&r.push(`${t} { ${h.style.cssText} }`)}else if(h.cssRules&&void 0!==h.conditionText){const t=(null!==(e=h.cssText)&&void 0!==e?e:"").slice(0,(null!==(s=h.cssText)&&void 0!==s?s:"").indexOf("{")).trim(),n=G(h.cssRules,i);t&&n&&r.push(`${t} { ${n} }`)}else 7===h.type&&h.cssText&&r.push(h.cssText)}return r.join("\n")}const X=new Set(["click","clicked","button","link","cta_click","link_click","button_click"]);function Y(t){if("string"!=typeof t)return;const i=t.trim();return i&&!X.has(i.toLowerCase())?i.slice(0,128):void 0}const Z=new Set(["modal","banner","slideup","fullscreen"]);function tt(t){if("string"!=typeof t)return null;const i=t.trim();return!i||i.length>100||/[;{}<>\\]/.test(i)?null:i}class it{capabilities(){const t=["content.native"];return this.allowHtmlJsInAppMessages&&t.push("content.html"),t}callHost(t,i){try{i()}catch(i){this.logger.error(`The ${t} callback threw; ignored:`,i)}}invalidate(){this.generation++,this.isSyncing&&(this.syncAgain=!0)}setAllowHtmlJsInAppMessages(t){this.allowHtmlJsInAppMessages=t}constructor(t,i,e,s,n,r,o,h,a,u){this.pendingDelays=new Map,this.campaigns=new Map,this.displayedMessages=new Map,this.impressionTimestamps=new Map,this.watchedAttributes=new Set,this.displayOptions={},this.isSyncing=!1,this.syncRetried=!1,this.generation=0,this.syncAgain=!1,this.claimed=new Set,this.iframes=new Map,this.allowHtmlJsInAppMessages=!1,this.bridge=null,this.auth=null,this.runtime={canSend:(null==u?void 0:u.canSend)||(()=>!0),requestTimeoutMs:(null==u?void 0:u.requestTimeoutMs)||1e4,syncIntervalMs:(null==u?void 0:u.syncIntervalMs)||0,evaluationMode:(null==u?void 0:u.evaluationMode)||"differential-sync",noteStatus:null==u?void 0:u.noteStatus},this.apiEndpoint=t,this.sdkKey=i,this.identity=e,this.session=s,this.logger=n,this.storage=r||null,this.displayOptions=o||{},this.bridge=h||null,this.auth=a||null,this.loadImpressionTimestamps(),this.installHostBridge()}loadImpressionTimestamps(){if(this.storage)try{const t=this.storage.get(Q);if(t&&"object"==typeof t)for(const[i,e]of Object.entries(t))Array.isArray(e)&&this.impressionTimestamps.set(i,e.filter(t=>"number"==typeof t))}catch(t){this.logger.error("Failed to load persisted impression timestamps:",t)}}persistImpressionTimestamps(){if(this.storage)try{const t={};this.impressionTimestamps.forEach((i,e)=>{t[e]=i}),this.storage.set(Q,t)}catch(t){this.logger.error("Failed to persist impression timestamps:",t)}}installHostBridge(){"undefined"!=typeof window&&(window[V]={logCustomEvent:(t,i,e)=>{var s;this.displayedMessages.has(t)&&i&&(null===(s=this.bridge)||void 0===s||s.logCustomEvent(i,e))},setCustomUserAttribute:(t,i,e)=>{var s;this.displayedMessages.has(t)&&i&&(null===(s=this.bridge)||void 0===s||s.setCustomUserAttribute(i,e))},changeUser:(t,i)=>{var e;this.displayedMessages.has(t)&&i&&(null===(e=this.bridge)||void 0===e||e.changeUser(i))},requestPushPermission:t=>{var i;this.displayedMessages.has(t)&&(null===(i=this.bridge)||void 0===i||i.requestPushPermission())},logConversion:(t,i)=>{this.displayedMessages.has(t)&&i&&this.trackConversion(t,i).catch(()=>{})},logClick:(t,i)=>{if(!this.displayedMessages.has(t))return;const e=Y(i);this.trackImpression(t,"clicked",e?{elementId:e}:void 0).catch(()=>{});const s=this.displayedMessages.get(t);s&&this.callHost("onMessageClick",()=>{var t,e;return null===(e=(t=this.displayOptions).onClick)||void 0===e?void 0:e.call(t,s,i||"click")})},navigate:(t,i,e)=>{this.displayedMessages.has(t)&&"string"==typeof i&&/^(https?:\/\/|\/(?!\/))/i.test(i)&&("_top"===e||"_self"===e?window.top&&(window.top.location.href=i):window.open(i,"_blank","noopener"))},closeMessage:t=>{this.displayedMessages.has(t)&&this.dismiss(t,"bridge_close").catch(()=>{})},submitForm:(t,i)=>this.displayedMessages.has(t)&&i&&"object"==typeof i?(this.trackImpression(t,"clicked").catch(()=>{}),this.submitForm(t,i)):Promise.resolve({ok:!1,message:"This message is no longer open."}),setSize:(t,i,e)=>{var s;const n=this.iframes.get(t);if(!n||!Number.isFinite(e)||0>=e)return;const r=null===(s=this.displayedMessages.get(t))||void 0===s?void 0:s.campaign.type;n.style.height="fullscreen"===r?"100%":Math.ceil(e)+"px",("modal"===r||"slideup"===r)&&Number.isFinite(i)&&i>0&&(n.style.width=Math.ceil(i)+"px")}})}async initialize(){this.runtime.canSend()&&(this.logger.info("Initializing in-app messaging"),this.stop(),await this.sync().catch(t=>{this.logger.error("Initial in-app sync failed:",t)}),this.startAttributeWatching(),this.startPeriodicSync())}stop(){this.syncInterval&&(clearInterval(this.syncInterval),this.syncInterval=void 0),this.periodicSyncTimer&&(clearInterval(this.periodicSyncTimer),this.periodicSyncTimer=void 0),this.syncRetryTimer&&(clearTimeout(this.syncRetryTimer),this.syncRetryTimer=void 0),this.syncRetried=!1,this.pendingDelays.forEach(t=>clearTimeout(t)),this.pendingDelays.clear()}startPeriodicSync(){this.periodicSyncTimer&&(clearInterval(this.periodicSyncTimer),this.periodicSyncTimer=void 0),"differential-sync"===this.runtime.evaluationMode&&this.runtime.syncIntervalMs>0&&(this.periodicSyncTimer=setInterval(()=>{"undefined"!=typeof document&&document.hidden||this.runtime.canSend()&&this.sync().catch(t=>this.logger.debug("Periodic in-app sync failed:",t))},this.runtime.syncIntervalMs))}subject(){const t=this.identity.getUserId();return Object.assign(Object.assign({},t?{userId:t}:{}),{anonymousId:this.identity.getAnonymousId()})}async maybeHandleSdkAuthError(t,i,e){if(!this.auth||401!==t.status)return;if((e||null)!==((this.auth.getCurrentUserId?this.auth.getCurrentUserId():this.identity.getUserId())||null))return;let s=null;try{s=await t.clone().json()}catch(t){return}if(this.auth.isSdkAuthError(t.status,s)){this.logger.warn(`In-app request rejected by SDK authentication (${(null==s?void 0:s.reason)||"invalid"}) on ${i} – refreshing token`);try{await this.auth.refreshSdkAuthToken({reason:(null==s?void 0:s.reason)||"invalid",endpoint:i,userId:e})}catch(t){this.logger.error("Failed to refresh SDK authentication token for in-app request:",t)}}}async sync(t){var i,e,s;if(!this.runtime.canSend())return{success:!1,campaigns:[],evaluatedAt:(new Date).toISOString()};if(this.isSyncing)return this.syncAgain=!0,t&&(this.syncAgainChanges=Object.assign(Object.assign({},this.syncAgainChanges||{}),t)),{success:!1,campaigns:[],evaluatedAt:(new Date).toISOString()};this.isSyncing=!0;const n=this.generation;this.logger.debug("Syncing in-app campaigns");const r=this.session.getSessionId(),o=this.identity.getAttributes(),h=new AbortController,a=this.runtime.requestTimeoutMs,u=setTimeout(()=>h.abort(),a),d=this.identity.getUserId();try{const a=await fetch(this.apiEndpoint+"/v1/in-app/sync",{method:"POST",headers:Object.assign({"Content-Type":"application/json","X-SDK-Key":this.sdkKey},(null===(i=this.auth)||void 0===i?void 0:i.getSdkAuthHeaders(d))||{}),body:JSON.stringify(Object.assign(Object.assign({},this.subject()),{sessionId:r,userAttributes:t||o,pendingAttributes:this.identity.pending.pending(this.identity.getAnonymousId()),deviceType:"web",locale:navigator.language,capabilities:this.capabilities()})),signal:h.signal});if(!a.ok)throw null===(s=(e=this.runtime).noteStatus)||void 0===s||s.call(e,a.status,null),await this.maybeHandleSdkAuthError(a,this.apiEndpoint+"/v1/in-app/sync",d),Error(`Sync failed: ${a.status} ${a.statusText}`);const u=await a.json();if(n!==this.generation)return this.logger.debug("Discarding an in-app sync answer that predates an identity or consent change"),this.syncAgain=!0,{success:!1,campaigns:[],evaluatedAt:(new Date).toISOString()};if(!u||!1===u.success||!Array.isArray(u.campaigns))throw Error("Sync failed: the server reported success: false");this.syncRetried=!1,this.campaigns.clear();for(const t of u.campaigns)this.campaigns.set(t.id,t),"differential-sync"===t.evaluationMode&&t.watchedAttributes&&t.watchedAttributes.forEach(t=>this.boundedSetAdd(this.watchedAttributes,t,200));return this.logger.info(`Synced ${u.campaigns.length} eligible campaigns`),this.processImmediateTriggers(),u}catch(t){const i="AbortError"===(null==t?void 0:t.name);throw this.logger.error(i?`Campaign sync timed out after ${a}ms`:"Failed to sync campaigns:",t),n===this.generation&&!this.syncRetried&&this.runtime.canSend()&&(this.syncRetried=!0,this.syncRetryTimer=setTimeout(()=>{this.syncRetryTimer=void 0,this.sync().catch(()=>{})},5e3)),i?Error("Campaign sync timed out"):t}finally{if(clearTimeout(u),this.isSyncing=!1,this.syncAgain){this.syncAgain=!1;const t=this.syncAgainChanges;this.syncAgainChanges=void 0,this.runtime.canSend()&&this.sync(n!==this.generation?void 0:t).catch(t=>this.logger.debug("Follow-up in-app sync failed:",t))}}}processImmediateTriggers(){for(const t of this.campaigns.values())(t.triggers||[]).some(t=>"immediate"===t.type)&&this.displayCampaign(t).catch(t=>this.logger.error("In-app display failed:",t))}onEventTracked(t,i){if(t)for(const e of this.campaigns.values())if((e.triggers||[]).find(e=>"event"===e.type&&e.event===t&&this.triggerFilterMatches(e,i)))return void this.displayCampaign(e).catch(t=>this.logger.error("In-app display failed:",t))}triggerFilterMatches(t,i){if(!t.attribute)return!0;const e=null==i?void 0:i[t.attribute],s=t.value;switch(t.operator){case void 0:case"equals":case"eq":return e===s;case"not_equals":case"neq":return e!==s;case"greater_than":case"gt":return+e>+s;case"less_than":case"lt":return+s>+e;case"contains":return((null!=e?e:"")+"").includes(s+"");case"exists":return null!=e;default:return!1}}async resolveForDisplay(t){var i,e,s;if(!this.runtime.canSend())return null;const n=this.generation,r=new AbortController,o=setTimeout(()=>r.abort(),this.runtime.requestTimeoutMs);try{const o=await fetch(this.apiEndpoint+"/v1/in-app/resolve",{method:"POST",headers:Object.assign({"Content-Type":"application/json","X-SDK-Key":this.sdkKey},(null===(i=this.auth)||void 0===i?void 0:i.getSdkAuthHeaders(this.identity.getUserId()))||{}),body:JSON.stringify(Object.assign(Object.assign({},this.subject()),{campaignId:t.id,sessionId:this.session.getSessionId(),userAttributes:this.identity.getAttributes(),pendingAttributes:this.identity.pending.pending(this.identity.getAnonymousId()),deviceType:"web"})),signal:r.signal});if(!o.ok)return null===(s=(e=this.runtime).noteStatus)||void 0===s||s.call(e,o.status,null),null;const h=await o.json();return n!==this.generation?null:(null==h?void 0:h.eligible)&&h.campaign?h.campaign:null}catch(t){return null}finally{clearTimeout(o)}}canPromptForPush(){try{return"undefined"!=typeof Notification&&"default"===Notification.permission}catch(t){return!1}}async displayCampaign(t){const i=t.id;if(this.claimed.has(i)||this.displayedMessages.has(i)||this.pendingDelays.has(i))return void this.logger.debug(`Campaign ${i} already displayed, scheduled or being prepared`);this.claimed.add(i);const e=this.generation;try{if(t.reevaluateBeforeDisplay){const i=await this.resolveForDisplay(t);if(!i)return void this.logger.info(`Campaign ${t.id} not displayed: re-check said no`);t=i}if(this.displayedMessages.has(t.id)||this.pendingDelays.has(t.id))return void this.logger.debug(`Campaign ${t.id} already displayed or scheduled`);if(!this.checkFrequencyCap(t))return void this.logger.debug(`Campaign ${t.id} blocked by frequency cap`);const i=await this.renderTemplate(t);if(e!==this.generation||!this.runtime.canSend())return void this.logger.debug(`Campaign ${t.id} not displayed: the visitor or consent changed meanwhile`);const s=this.undisplayableReason(t,i);if(s)return void this.logger.warn(`Campaign ${t.id} not displayed (${s}). No impression recorded and no frequency cap consumed, so it stays eligible.`);if(i.includes("requestPushPermission")&&!this.canPromptForPush())return void this.logger.debug(`Campaign ${t.id} is a push primer but the browser can't be prompted (permission not 'default'); suppressing.`);const n={campaign:t,renderedHtml:i,displayedAt:new Date},r=()=>{this.boundedMapSet(this.displayedMessages,t.id,n,500);const i=this.impressionTimestamps.get(t.id)||[];i.push(Date.now()),this.boundedMapSet(this.impressionTimestamps,t.id,i,500),this.persistImpressionTimestamps(),this.display(n)},o=1e3*Math.max(0,+t.delay||0);if(o>0){const i=setTimeout(()=>{this.pendingDelays.delete(t.id),e===this.generation&&this.runtime.canSend()?!this.displayedMessages.has(t.id)&&this.checkFrequencyCap(t)&&(r(),this.trackImpression(t.id,"displayed").catch(()=>{})):this.logger.debug(`Campaign ${t.id} not displayed after its delay: the visitor or consent changed`)},o);return void this.pendingDelays.set(t.id,i)}r(),await this.trackImpression(t.id,"displayed")}finally{this.claimed.delete(i)}}async renderTemplate(t){const i=t.content;return i&&"html"===i.kind?i.html:""}undisplayableReason(t,i){var e;const s=null===(e=t.content)||void 0===e?void 0:e.kind;return t.content?"native"===s?null:"html"===s?i.trim()?this.allowHtmlJsInAppMessages?null:"it is an HTML message and allowHtmlJsInAppMessages is false":"its `content.html` is empty":`this SDK cannot render content kind '${s+""}'`:"the payload carries no `content`"}display(t){var i,e,s,n,r,o,h;const{campaign:a,renderedHtml:u}=t,d=document.createElement("div");d.id="joryio-inapp-"+a.id;const l=Z.has(a.type)?null:["top","center","bottom"].find(t=>t===this.displayOptions.defaultPosition)||"center",c=["fade","slide","none"].find(t=>t===this.displayOptions.defaultAnimation)||"fade";d.className="joryio-inapp joryio-inapp-"+a.type+(l?" joryio-inapp-pos-"+l:"")+("none"!==c?" joryio-inapp-anim-"+c:"");const p=document.createElement("style");p.id="joryio-style-"+a.id;const f=Number.isFinite(this.displayOptions.zIndex)?+this.displayOptions.zIndex:999999,y=tt(this.displayOptions.backdropColor)||"rgba(0, 0, 0, 0.5)",m=tt(this.displayOptions.closeButtonColor)||"inherit";p.textContent=`\n .joryio-inapp {\n position: fixed;\n z-index: ${f};\n }\n\n /* displayOptions.defaultPosition - only for types with no placement of their own. */\n .joryio-inapp-pos-top {\n top: 20px;\n left: 50%;\n transform: translateX(-50%);\n max-width: 90%;\n }\n .joryio-inapp-pos-center {\n top: 50%;\n left: 50%;\n transform: translate(-50%, -50%);\n max-width: 90%;\n max-height: 90%;\n }\n .joryio-inapp-pos-bottom {\n bottom: 20px;\n left: 50%;\n transform: translateX(-50%);\n max-width: 90%;\n }\n\n /* displayOptions.defaultAnimation. The individual \`translate\` property\n composes with the positioning \`transform\` above instead of\n replacing it. Motion is skipped for visitors who asked for less. */\n @keyframes joryio-inapp-fade-in { from { opacity: 0; } to { opacity: 1; } }\n @keyframes joryio-inapp-slide-in { from { opacity: 0; translate: 0 16px; } to { opacity: 1; translate: 0 0; } }\n .joryio-inapp-anim-fade { animation: joryio-inapp-fade-in 200ms ease-out both; }\n .joryio-inapp-anim-slide { animation: joryio-inapp-slide-in 240ms ease-out both; }\n @media (prefers-reduced-motion: reduce) {\n .joryio-inapp-anim-fade, .joryio-inapp-anim-slide { animation: none; }\n }\n\n /* The message content lives in a sandboxed iframe; its own CSS stays\n inside it (no leak to/from the host page). Only SDK chrome is here. */\n .joryio-inapp > iframe {\n border: 0;\n width: 100%;\n display: block;\n background: transparent;\n color-scheme: normal;\n }\n\n .joryio-inapp-modal {\n top: 50%;\n left: 50%;\n transform: translate(-50%, -50%);\n max-width: 90%;\n max-height: 90%;\n }\n\n .joryio-inapp-banner {\n top: 0;\n left: 0;\n right: 0;\n }\n\n .joryio-inapp-slideup {\n bottom: 20px;\n right: 20px;\n max-width: 400px;\n }\n\n .joryio-inapp-fullscreen {\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n }\n\n /* Native card. Deliberately minimal and system-font: the host page's\n typography is the closest thing the web has to "the app's look", and\n a shipped palette would clash with every site.\n\n Every author-settable value comes through a CUSTOM PROPERTY with the\n system default as its fallback. That is what lets the campaign's own\n CSS override the colour pickers: inline styles beat a stylesheet, so\n setting the pickers inline would have made "advanced" strictly weaker\n than "basic" - the opposite of what an escape hatch is for. */\n .joryio-inapp-native {\n /* Positioning context for the close button, which sits in the card's\n top trailing corner rather than in the content flow. */\n position: relative;\n background: var(--joryio-inapp-bg, Canvas);\n color: var(--joryio-inapp-fg, CanvasText);\n color-scheme: light dark;\n border-radius: var(--joryio-inapp-radius, 14px);\n padding: 20px;\n box-shadow: 0 10px 40px rgba(0,0,0,0.18);\n font: menu;\n font-family: var(--joryio-inapp-font, system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif);\n /* Direction-relative, so a Hebrew or Arabic message reads from the\n right without the campaign having to know which way it runs. The\n card carries dir=auto, so 'start' resolves per message. */\n text-align: var(--joryio-inapp-align, start);\n max-width: 420px;\n }\n .joryio-inapp-fullscreen .joryio-inapp-native {\n border-radius: 0;\n max-width: none;\n height: 100%;\n }\n .joryio-inapp-native img {\n width: 100%;\n height: 140px;\n object-fit: cover;\n border-radius: 8px;\n display: block;\n margin-bottom: 14px;\n }\n .joryio-inapp-native h2 {\n margin: 0 0 8px;\n /* Room for the close button in the trailing corner. Logical, so in a\n Hebrew message the gap is on the left, where the button is. */\n padding-inline-end: 28px;\n /* Derived from the body size so one control keeps the hierarchy. */\n font-size: calc(var(--joryio-inapp-size, 14.5px) * 1.3);\n font-weight: var(--joryio-inapp-title-weight, 700);\n line-height: 1.3;\n }\n .joryio-inapp-native p {\n margin: 0 0 16px;\n font-size: var(--joryio-inapp-size, 14.5px);\n line-height: 1.5;\n opacity: 0.85;\n }\n .joryio-inapp-buttons {\n display: flex;\n gap: 8px;\n }\n .joryio-inapp-buttons.stacked {\n flex-direction: column;\n }\n .joryio-inapp-native button {\n flex: 1;\n min-height: 44px;\n border-radius: 8px;\n font: inherit;\n font-size: 14px;\n cursor: pointer;\n border: 1px solid transparent;\n }\n .joryio-inapp-native button.primary {\n background: var(--joryio-inapp-primary, AccentColor);\n color: var(--joryio-inapp-primary-fg, AccentColorText);\n }\n .joryio-inapp-native button.secondary {\n background: transparent;\n color: inherit;\n border-color: rgba(128,128,128,0.4);\n }\n /*\n * Native messages used to override the shared close button into a\n * full-width "Close" text row under the buttons, while HTML messages in\n * this same SDK drew an ✕ in the corner. One SDK, two dismiss designs -\n * and the text row also hardcoded the English word "Close", which is\n * wrong in a Hebrew or Arabic app. The ✕ needs no translation, so native\n * now uses the shared button and this override is gone.\n */\n\n .joryio-inapp-backdrop {\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: ${y};\n z-index: ${f-1};\n }\n\n .joryio-inapp-close {\n position: absolute;\n top: 6px;\n /* inset-inline-end, not right: the card carries dir=auto, so a Hebrew\n or Arabic message puts the ✕ in ITS trailing corner - the left one -\n without the campaign having to know which way the text runs. */\n inset-inline-end: 6px;\n display: flex;\n align-items: center;\n justify-content: center;\n /* 32px is the tap target; the glyph inside is smaller. Anything less\n is hard to hit on a phone, and it is the only way out of a\n full-screen message. */\n width: 32px;\n height: 32px;\n padding: 0;\n cursor: pointer;\n background: transparent;\n border: none;\n border-radius: 50%;\n font: inherit;\n font-size: 22px;\n line-height: 1;\n opacity: 0.55;\n color: ${m};\n }\n .joryio-inapp-close:hover,\n .joryio-inapp-close:focus-visible {\n opacity: 1;\n }\n `;const v=document.createElement("iframe");let b;if(v.id="joryio-iframe-"+a.id,"native"===(null===(i=a.content)||void 0===i?void 0:i.kind)){const i=a.content,s=document.createElement("div");s.className="joryio-inapp-native",s.dir="auto";const n=i.style;if("string"==typeof(null==n?void 0:n.customCss)&&(b=n.customCss),n){const t=(t,i,e="")=>{"string"==typeof i&&i.trim()?s.style.setProperty(t,i.trim()+e):"number"==typeof i&&Number.isFinite(i)&&s.style.setProperty(t,i+""+e)};t("--joryio-inapp-bg",n.backgroundColor),t("--joryio-inapp-fg",n.textColor),t("--joryio-inapp-font",n.fontFamily),t("--joryio-inapp-radius",n.cornerRadius,"px"),t("--joryio-inapp-size",n.fontSize,"px"),"string"==typeof n.titleWeight&&t("--joryio-inapp-title-weight",{regular:"400",medium:"500",semibold:"600",bold:"700"}[n.titleWeight]),"string"==typeof n.textAlign&&"auto"!==n.textAlign&&t("--joryio-inapp-align",n.textAlign),t("--joryio-inapp-primary",n.primaryButtonColor),t("--joryio-inapp-primary-fg","string"==typeof n.primaryButtonTextColor&&n.primaryButtonTextColor.trim()?n.primaryButtonTextColor:function(t){if("string"!=typeof t)return;const i=t.trim().replace(/^#/,""),e=3===i.length?i.replace(/(.)/g,"$1$1"):i;if(!/^[0-9a-f]{6}$/i.test(e))return;const[s,n,r]=[0,2,4].map(t=>parseInt(e.slice(t,t+2),16));return.2126*s+.7152*n+.0722*r>150?"#0A1240":"#FFFFFF"}(n.primaryButtonColor))}if(i.imageUrl&&/^https:\/\//i.test(i.imageUrl)){const t=document.createElement("img");t.src=i.imageUrl,t.alt="",t.onerror=()=>t.remove(),s.appendChild(t)}if(i.title){const t=document.createElement("h2");t.textContent=i.title,s.appendChild(t)}const r=document.createElement("p");if(r.textContent=i.body,s.appendChild(r),null===(e=i.buttons)||void 0===e?void 0:e.length){const e=document.createElement("div");e.className=i.buttons.length>2?"joryio-inapp-buttons stacked":"joryio-inapp-buttons",i.buttons.forEach((i,s)=>{const n=document.createElement("button");n.type="button",n.textContent=i.text,n.className=0===s?"primary":"secondary",n.addEventListener("click",()=>{var e;const s=Y(i.id);this.trackImpression(a.id,"clicked",Object.assign(Object.assign({},i.url&&/^https?:\/\//i.test(i.url)?{clickedUrl:i.url}:{}),s?{elementId:s}:{})).catch(()=>{}),this.callHost("onMessageClick",()=>{var e,s;return null===(s=(e=this.displayOptions).onClick)||void 0===s?void 0:s.call(e,t,i.id||i.action||"button")}),"request_push_permission"===i.action?this.canPromptForPush()&&(null===(e=this.bridge)||void 0===e||e.requestPushPermission()):("url"===i.action||"deep_link"===i.action)&&i.url&&/^https?:\/\//i.test(i.url)&&window.open(i.url,"_blank","noopener"),this.dismiss(a.id,"button").catch(()=>{})}),e.appendChild(n)}),s.appendChild(e)}if(!1!==i.closeButton){const t=document.createElement("button");t.type="button",t.className="joryio-inapp-close",t.innerHTML="×",t.setAttribute("aria-label","Close"),t.addEventListener("click",()=>{this.dismiss(a.id,"close_button").catch(()=>{})}),s.appendChild(t)}d.appendChild(s)}let g=!1;if("native"!==(null===(s=a.content)||void 0===s?void 0:s.kind)){if(!this.allowHtmlJsInAppMessages)return void this.logger.warn(`Campaign ${a.id} is an HTML in-app message, but allowHtmlJsInAppMessages is false - not displaying it.`);v.setAttribute("sandbox","allow-scripts allow-same-origin allow-popups");let t=0;if(v.addEventListener("load",()=>{var i,e;t++;let s=!0;try{const t=null===(e=null===(i=v.contentWindow)||void 0===i?void 0:i.location)||void 0===e?void 0:e.href;s=void 0===t||"about:srcdoc"===t}catch(t){s=!1}1>=t&&s||(this.logger.warn(`In-app message ${a.id} tried to navigate its frame; it has been closed`),this.dismiss(a.id,"navigation_blocked").catch(()=>{}))}),v.setAttribute("title",a.name||"Message"),v.style.height="0","banner"!==a.type&&"fullscreen"!==a.type||(v.style.width="100%"),v.srcdoc=this.buildSrcdoc(a.id,u,"html"===(null===(n=a.content)||void 0===n?void 0:n.kind)?a.content.css:"",a.type),d.appendChild(v),this.iframes.set(a.id,v),u.includes("requestPushPermission")&&(null===(o=null===(r=this.bridge)||void 0===r?void 0:r.preparePushPermission)||void 0===o||o.call(r)),!1!==this.displayOptions.closeButton){const t=document.createElement("button");t.className="joryio-inapp-close",t.innerHTML="×",t.setAttribute("aria-label","Close"),t.onclick=async()=>{g||(g=!0,await this.dismiss(a.id,"close_button").catch(()=>{}))},d.appendChild(t)}}let w=null;if("modal"===a.type||"fullscreen"===a.type){w=document.createElement("div"),w.className="joryio-inapp-backdrop",w.id="joryio-backdrop-"+a.id;const t="native"!==(null===(h=a.content)||void 0===h?void 0:h.kind)||!1!==a.content.backdropDismissible;!1!==this.displayOptions.backdropClose&&t&&(w.onclick=async()=>{g||(g=!0,await this.dismiss(a.id,"backdrop").catch(()=>{}))})}const k=this.displayOptions.container||document.documentElement;if(w&&k.appendChild(w),k.appendChild(p),"string"==typeof b&&b.trim()){const t=this.scopeCss(b,"#joryio-inapp-"+a.id);if(t){const i=document.createElement("style");i.id="joryio-css-"+a.id,i.textContent=t,k.appendChild(i)}}k.appendChild(d),this.callHost("onMessageDisplay",()=>{var i,e;return null===(e=(i=this.displayOptions).onDisplay)||void 0===e?void 0:e.call(i,t)}),this.logger.info(`Displayed campaign: ${a.name} (${a.id})`)}buildSrcdoc(t,i,e,s){const n="modal"===s||"slideup"===s?"body{display:inline-block;max-width:100vw;}":"",r=`(function(){\n var CID=${JSON.stringify(t)},KEY=${JSON.stringify(V)};\n // Per-device visibility: tag the root with the REAL device class from the\n // HOST page viewport (the iframe is message-sized, so its own innerWidth is\n // useless here). The jr-vp-* → jr-hide-* rules in <style> then hide elements\n // the dashboard marked "Mobile only" / "Desktop only". <=480 = mobile.\n try{var __vp=0;try{__vp=window.parent.innerWidth||0;}catch(e){}if(!__vp)__vp=window.innerWidth||0;document.documentElement.className+=(__vp<=480?' jr-vp-mobile':' jr-vp-desktop');}catch(e){}\n function host(){try{return window.parent[KEY]||null;}catch(e){return null;}}\n function call(m,args){var b=host();if(b&&typeof b[m]==='function'){try{return b[m].apply(b,[CID].concat(args||[]));}catch(e){}}}\n window.joryioBridge={\n logCustomEvent:function(name,props){call('logCustomEvent',[name,props]);},\n setCustomUserAttribute:function(k,v){call('setCustomUserAttribute',[k,v]);},\n changeUser:function(uid){call('changeUser',[uid]);},\n requestPushPermission:function(){call('requestPushPermission',[]);},\n logConversion:function(ev){call('logConversion',[ev||'in_app_conversion']);},\n submitForm:function(values){return call('submitForm',[values]);},\n logClick:function(action){call('logClick',[action]);},\n navigate:function(url,target){call('navigate',[url,target]);},\n closeMessage:function(){call('closeMessage',[]);}\n };\n document.addEventListener('click',function(e){\n var el=e.target;\n while(el&&el!==document.body&&el!==document.documentElement){\n var action=el.getAttribute&&el.getAttribute('data-joryio-action');\n if(action&&typeof window.joryioBridge[action]==='function'){e.preventDefault();window.joryioBridge[action](el.getAttribute('data-joryio-event')||undefined);return;}\n var tag=el.tagName;\n if(tag==='A'||tag==='BUTTON'){\n var da=el.getAttribute('data-action');\n var href=tag==='A'?el.getAttribute('href'):null;\n window.joryioBridge.logClick(da||(href?'link_click':'cta_click'));\n // Route only http(s)/root-relative links through the host (top-nav,\n // since the sandbox can't navigate the top page itself). Leave\n // #anchors, mailto:, tel:, sms: to the browser. Any other link\n // would navigate THIS frame away from the message: cancelled (rule 57).\n if(href&&/^(https?:\\/\\/|\\/(?!\\/))/i.test(href)){e.preventDefault();window.joryioBridge.navigate(href,el.getAttribute('target'));}\n else if(href&&!/^(#|mailto:|tel:|sms:)/i.test(href)){e.preventDefault();}\n return;\n }\n el=el.parentNode;\n }\n },true);\n // Forms (data-jry-form): serialize, hand the values to the host, show the\n // answer in place. A redirect goes through navigate (the sandbox cannot).\n document.addEventListener('submit',function(ev){var f=ev.target;if(!(f&&f.tagName==='FORM'&&f.hasAttribute('data-jry-form')))return;ev.preventDefault();if(f.getAttribute('data-jry-busy'))return;\n var d={},els=f.querySelectorAll('input,select,textarea');for(var i=0;i<els.length;i++){var el=els[i],n=el.name;if(!n||el.disabled)continue;if(el.type==='checkbox'){if(!el.checked)continue;if(d[n]===undefined)d[n]=[];d[n].push(el.value||'on')}else if(el.type==='radio'){if(el.checked)d[n]=el.value}else d[n]=el.value}\n function msg(text,ok){var b=f.querySelector('[data-jry-message]');if(!b){b=document.createElement('div');b.setAttribute('data-jry-message','');b.setAttribute('role','status');f.appendChild(b)}b.textContent=text;b.className=ok?'jry-form-success':'jry-form-error';reportSize()}\n f.setAttribute('data-jry-busy','1');var btn=f.querySelector('button[type="submit"],input[type="submit"]');if(btn)btn.disabled=true;\n var p=window.joryioBridge.submitForm(d);if(!p||typeof p.then!=='function'){msg('This form cannot be sent here.',false);f.removeAttribute('data-jry-busy');if(btn)btn.disabled=false;return}\n p.then(function(r){if(r&&r.ok){if(r.redirect){window.joryioBridge.navigate(r.redirect,'_top');return}var els2=f.querySelectorAll('input,select,textarea,button');for(var j=0;j<els2.length;j++){els2[j].disabled=true}msg(r.message||'Thank you.',true)}else{msg((r&&(r.message||(r.errors&&r.errors[0])))||'Something went wrong. Please try again.',false);f.removeAttribute('data-jry-busy');if(btn)btn.disabled=false}}).catch(function(){msg('Something went wrong. Please try again.',false);f.removeAttribute('data-jry-busy');if(btn)btn.disabled=false});\n },true);\n function reportSize(){try{var b=document.body,de=document.documentElement;var w=Math.max(b?b.scrollWidth:0,de.scrollWidth);var h=Math.max(b?b.scrollHeight:0,de.scrollHeight);call('setSize',[w,h]);}catch(e){}}\n if(document.readyState!=='loading')reportSize();else document.addEventListener('DOMContentLoaded',reportSize);\n window.addEventListener('load',reportSize);\n try{if(window.ResizeObserver&&document.body){new ResizeObserver(reportSize).observe(document.body);}}catch(e){}\n })();`,o=function(){const t=new Uint8Array(16),i=globalThis.crypto;if(i&&"function"==typeof i.getRandomValues)i.getRandomValues(t);else for(let i=0;i<t.length;i++)t[i]=Math.floor(256*Math.random());return Array.from(t,t=>t.toString(16).padStart(2,"0")).join("")}();return`<!doctype html><html><head><meta charset="utf-8"><meta http-equiv="Content-Security-Policy" content="${["default-src 'none'",`script-src 'nonce-${o}'`,"style-src 'unsafe-inline'; img-src https: data:; media-src https: data:; font-src https: data:; connect-src 'none'; form-action 'none'; base-uri 'none'; upgrade-insecure-requests"].join("; ")}"><meta name="viewport" content="width=device-width, initial-scale=1"><style>html,body{margin:0;padding:0;}img,video{max-width:100%;height:auto;}${n}.jr-vp-mobile .jr-hide-mobile{display:none!important}.jr-vp-desktop .jr-hide-desktop{display:none!important}${e=function(t){return"string"==typeof t?t.replace(/<\//g,"<\\/"):""}(e)}</style></head><body>${i}<script nonce="${o}">${r}<\/script></body></html>`}scopeCss(t,i){let e=null;try{e=document.createElement("style"),e.media="not all",e.textContent=t,document.head.appendChild(e);const s=e.sheet;if(!s)return this.logger.warn("Custom CSS could not be parsed; ignoring it"),"";const n=G(s.cssRules,i);return n||this.logger.warn("Custom CSS contained no rules that can be scoped; ignoring it"),n}catch(t){return this.logger.warn("Custom CSS could not be parsed; ignoring it",t),""}finally{null==e||e.remove()}}async dismiss(t,i="dismiss"){const e=this.pendingDelays.get(t);e&&(clearTimeout(e),this.pendingDelays.delete(t));const s=document.getElementById("joryio-inapp-"+t),n=document.getElementById("joryio-backdrop-"+t),r=document.getElementById("joryio-style-"+t),o=document.getElementById("joryio-css-"+t);s&&s.remove(),this.iframes.delete(t),n&&n.remove(),r&&r.remove(),o&&o.remove();const h=this.displayedMessages.get(t);h&&(await this.trackImpression(t,"dismissed").catch(()=>{}),this.callHost("onMessageDismiss",()=>{var t,e;return null===(e=(t=this.displayOptions).onDismiss)||void 0===e?void 0:e.call(t,h,i)}),this.displayedMessages.delete(t)),this.logger.info("Dismissed campaign: "+t)}async trackConversion(t,i){await this.trackImpression(t,"converted",{conversionEvent:i});const e=this.displayedMessages.get(t);e&&this.callHost("onConversion",()=>{var t,s;return null===(s=(t=this.displayOptions).onConversion)||void 0===s?void 0:s.call(t,e,i)})}async submitForm(t,i){var e,s;const n=this.displayedMessages.get(t);if(!this.runtime.canSend())return{ok:!1,message:"This form cannot be sent right now."};const r=new AbortController,o=setTimeout(()=>r.abort(),this.runtime.requestTimeoutMs),h=this.identity.getUserId();try{const o=await fetch(this.apiEndpoint+"/v1/in-app/form-submit",{method:"POST",headers:Object.assign({"Content-Type":"application/json","X-SDK-Key":this.sdkKey},(null===(e=this.auth)||void 0===e?void 0:e.getSdkAuthHeaders(h))||{}),body:JSON.stringify({campaignId:t,variantId:null===(s=null==n?void 0:n.campaign)||void 0===s?void 0:s.variantId,userId:this.identity.getUserId()||void 0,anonymousId:this.identity.getAnonymousId(),values:i}),signal:r.signal});await this.maybeHandleSdkAuthError(o,this.apiEndpoint+"/v1/in-app/form-submit",h);const a=await o.json().catch(()=>null);return a&&"object"==typeof a?a:{ok:!1,message:"Something went wrong. Please try again."}}catch(t){return{ok:!1,message:"Something went wrong. Please try again."}}finally{clearTimeout(o)}}async trackImpression(t,i,e){var s,n,r,o;const h=this.campaigns.get(t)||(null===(s=this.displayedMessages.get(t))||void 0===s?void 0:s.campaign);if(!h)return;if(!this.runtime.canSend())return;const a=this.session.getSessionId(),u=Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({campaignId:t,variantId:h.variantId},this.subject()),{sessionId:a,deviceType:"web",locale:navigator.language,userAgent:navigator.userAgent}),h.pendingId?{pendingId:h.pendingId}:{}),h.deliveryToken?{deliveryToken:h.deliveryToken}:{}),e);"displayed"===i?u.displayedAt=(new Date).toISOString():"clicked"===i?(u.clicked=!0,u.clickedAt=(new Date).toISOString(),u.action="clicked"):"dismissed"===i?(u.dismissedAt=(new Date).toISOString(),u.action="dismissed"):"converted"===i&&(u.converted=!0,u.convertedAt=(new Date).toISOString());const d=new AbortController,l=setTimeout(()=>d.abort(),this.runtime.requestTimeoutMs),c="string"==typeof u.userId&&u.userId?u.userId:null;try{const e=await fetch(this.apiEndpoint+"/v1/in-app/track",{method:"POST",headers:Object.assign({"Content-Type":"application/json","X-SDK-Key":this.sdkKey},(null===(n=this.auth)||void 0===n?void 0:n.getSdkAuthHeaders(c))||{}),body:JSON.stringify(u),signal:d.signal});e.ok||null===(o=(r=this.runtime).noteStatus)||void 0===o||o.call(r,e.status,null),await this.maybeHandleSdkAuthError(e,this.apiEndpoint+"/v1/in-app/track",c),this.logger.debug(`Tracked ${i} for campaign ${t}`)}catch(e){"AbortError"===(null==e?void 0:e.name)?this.logger.error(`Impression tracking timed out after ${this.runtime.requestTimeoutMs}ms for campaign ${t}`):this.logger.error(`Failed to track ${i}:`,e)}finally{clearTimeout(l)}}checkFrequencyCap(t){if(!t.frequencyCap)return!0;const{maxImpressions:i,timeWindow:e,minDelayBetweenImpressions:s}=t.frequencyCap;if(!i||!e)return!0;const n=this.impressionTimestamps.get(t.id)||[],r=Date.now();let o=0;if("once"===e||"lifetime"===e)return 0===n.length;if("session"===e)o=this.session.getSessionInfo().sessionStart;else{const t=[["min",6e4],["mo",2592e6],["h",36e5],["d",864e5],["w",6048e5],["m",2592e6]];let i=864e5;for(const[s,n]of t){if(!e.endsWith(s))continue;const t=parseInt(e.slice(0,-s.length),10);!Number.isNaN(t)&&t>0&&(i=t*n);break}o=r-i}return n.filter(t=>t>=o).length<i&&!(s&&n.length>0&&1e3*s>r-n[n.length-1])}startAttributeWatching(){if(this.syncInterval&&(clearInterval(this.syncInterval),this.syncInterval=void 0),0===this.watchedAttributes.size)return;this.logger.debug(`Watching ${this.watchedAttributes.size} attributes for changes`);const t={};this.watchedAttributes.forEach(i=>{t[i]=this.identity.getAttribute(i)}),this.syncInterval=window.setInterval(()=>{if("undefined"!=typeof document&&document.hidden)return;const i={};let e=!1;if(this.watchedAttributes.forEach(s=>{const n=this.identity.getAttribute(s);n!==t[s]&&(i[s]=n,t[s]=n,e=!0)}),e){if(this.checkAttributeThresholds(Object.keys(i)),"session-start-only"===this.runtime.evaluationMode||!this.runtime.canSend())return;this.logger.info("Attribute changes detected, re-syncing campaigns"),this.sync(i).catch(t=>{this.logger.error("Failed to re-sync on attribute change:",t)})}},5e3)}checkAttributeThresholds(t){if(!t.length)return;const i=this.identity.getAttributes()||{};for(const e of this.campaigns.values())if((e.triggers||[]).some(e=>"attribute_threshold"===e.type&&!!e.attribute&&t.includes(e.attribute)&&this.triggerFilterMatches(e,i)))return void this.displayCampaign(e).catch(t=>this.logger.error("In-app display failed:",t))}getCampaigns(){return Array.from(this.campaigns.values())}getCampaign(t){return this.campaigns.get(t)}clearAll(){this.logger.info("Clearing in-app messaging state"),this.invalidate(),this.stop();for(const t of this.displayedMessages.keys())this.dismiss(t,"clear").catch(t=>this.logger.error("In-app dismiss failed:",t));this.campaigns.clear(),this.displayedMessages.clear(),this.watchedAttributes.clear(),this.iframes.clear(),this.logger.info("In-app messaging state cleared")}forgetImpressions(){var t;this.impressionTimestamps.clear();try{null===(t=this.storage)||void 0===t||t.remove(Q)}catch(t){}}boundedMapSet(t,i,e,s){if(t.set(i,e),t.size>s){const i=t.keys().next().value;void 0!==i&&t.delete(i)}}boundedSetAdd(t,i,e){if(t.add(i),t.size>e){const i=t.values().next().value;void 0!==i&&t.delete(i)}}destroy(){this.logger.info("Destroying in-app messaging"),this.stop();for(const t of this.displayedMessages.keys())this.dismiss(t,"destroy").catch(t=>this.logger.error("In-app dismiss failed:",t));this.campaigns.clear(),this.displayedMessages.clear(),this.impressionTimestamps.clear(),this.watchedAttributes.clear(),this.iframes.clear(),"undefined"!=typeof window&&delete window[V]}}var et;t.SubscriptionStatus=void 0,(et=t.SubscriptionStatus||(t.SubscriptionStatus={})).OPTED_IN="optedIn",et.SUBSCRIBED="subscribed",et.UNSUBSCRIBED="unsubscribed";const st=["email","sms","whatsapp","push","viber"];class nt{constructor(t,i,e,s,n){this.logger=t,this.network=i,this.identity=e,this.apiEndpoint=s,this.runWrite=n||((t,i)=>{this.sendOnce(i).then(i=>{i.ok||this.logger.error(`${t} failed (HTTP ${i.status||"no response"})`)},i=>this.logger.error(t+" failed:",i))})}sendOnce(t){return"subscription"===t.kind?this.network.sendSubscriptionUpdate(this.apiEndpoint,t.payload):"group"===t.kind?this.network.sendSubscriptionGroupUpdate(this.apiEndpoint,t.payload):Promise.resolve({ok:!1,status:0})}ids(){const t=this.identity.getUserId();return Object.assign(Object.assign({},t?{userId:t}:{}),{anonymousId:this.identity.getAnonymousId()})}setSubscription(i,e){if(!st.includes(i))return void this.logger.error(`Invalid channel: ${i}. Must be one of: ${st.join(", ")}`);const s=Object.values(t.SubscriptionStatus);if(!s.includes(e))return void this.logger.error(`Invalid status: ${e}. Must be one of: ${s.join(", ")}`);this.logger.debug(`Setting ${i} subscription status to ${e}`);const n=Object.assign({channel:i,status:e},this.ids());this.runWrite(`Update ${i} subscription`,{kind:"subscription",payload:n})}setSubscriptions(t){if(t&&"object"==typeof t)for(const[i,e]of Object.entries(t))void 0!==e&&this.setSubscription(i,e);else this.logger.error("setSubscriptions requires an object, e.g. { email: SubscriptionStatus.OPTED_IN }")}addToSubscriptionGroup(t,i="email"){this.updateGroup(t,i,"subscribe")}removeFromSubscriptionGroup(t,i="email"){this.updateGroup(t,i,"unsubscribe")}updateGroup(t,i,e){if("string"!=typeof t||!t)return void this.logger.error(`Cannot ${e} subscription group: groupId is required`);if(!st.includes(i))return void this.logger.error(`Invalid channel: ${i}. Must be one of: ${st.join(", ")}`);this.logger.debug(`${e} subscription group ${t} for channel ${i}`);const s=Object.assign({groupId:t,channel:i,action:e},this.ids());this.runWrite(`Subscription group ${t} ${e}`,{kind:"group",payload:s})}}const rt={error:0,warn:1,info:2,debug:3};class ot{constructor(t,i="error"){this.enabled=t,this.level=i}shouldLog(t){return this.enabled&&rt[t]<=rt[this.level]}error(...t){this.shouldLog("error")&&console.error("[Joryio SDK]",...t)}warn(...t){this.shouldLog("warn")&&console.warn("[Joryio SDK]",...t)}info(...t){this.shouldLog("info")&&console.info("[Joryio SDK]",...t)}debug(...t){this.shouldLog("debug")&&console.debug("[Joryio SDK]",...t)}setEnabled(t){this.enabled=t}setLevel(t){this.level=t}}const ht=t=>t.includes("Edg/")?"Edge":t.includes("OPR/")?"Opera":t.includes("Chrome/")?"Chrome":t.includes("Safari/")&&!t.includes("Chrome/")?"Safari":t.includes("Firefox/")?"Firefox":t.includes("MSIE")||t.includes("Trident/")?"IE":"Unknown",at=t=>"string"==typeof t&&t.trim().length>0,ut=t=>"number"==typeof t&&Number.isFinite(t),dt=t=>ut(t)?t:void 0;class lt{constructor(t,i,e){this.sdk=t,this.config={currency:i&&"string"==typeof i.currency&&i.currency||"USD"},this.logger=e||new ot(!1)}guard(t,i,e){if(i)this.logger.warn(`ecommerce.${t}() not tracked: ${i}`);else try{e()}catch(i){this.logger.error(`ecommerce.${t}() failed:`,i)}}productProblem(t,i="product"){return t&&"object"==typeof t?at(t.productId)?ut(t.price)?null:i+".price must be a finite number":i+".productId is required":`a ${i} object is required`}itemsProblem(t){if(!Array.isArray(t))return"an items array is required";for(const i of t){if(null==i)continue;const t=this.productProblem(i,"item");if(t)return t}return null}cartProblem(t,i){var e;return null!==(e=this.itemsProblem(t))&&void 0!==e?e:ut(i)?null:"cartValue must be a finite number"}textProblem(t){for(const[i,e]of Object.entries(t))if(!at(e))return`a ${i} is required`;return null}amountsProblem(t){for(const[i,e]of Object.entries(t))if(null!=e&&!ut(e))return i+" must be a finite number";return null}validItems(t){return t.filter(t=>t&&"object"==typeof t)}itemCount(t){return t.reduce((t,i)=>t+(ut(i.quantity)?i.quantity:0),0)}viewProduct(t){this.guard("viewProduct",this.productProblem(t),()=>this.sdk.track("Product Viewed",{product_id:t.productId,name:t.name,price:t.price,category:t.category,brand:t.brand,variant:t.variant,variant_id:t.variantId,sku:t.sku,image_url:t.imageUrl,url:t.url,currency:this.config.currency}))}viewCategory(t,i,e){this.guard("viewCategory",this.textProblem({categoryId:t,categoryName:i}),()=>this.sdk.track("Product List Viewed",Object.assign({category_id:t,category_name:i},e&&"object"==typeof e?e:{})))}search(t,i,e){this.guard("search",this.textProblem({query:t}),()=>this.sdk.track("Products Searched",Object.assign({query:t,result_count:dt(i)},e&&"object"==typeof e?e:{})))}addToCart(t,i){var e;const s=null!==(e=this.productProblem(t,"item"))&&void 0!==e?e:this.amountsProblem({cartValue:i});this.guard("addToCart",s,()=>this.sdk.track("Product Added",{product_id:t.productId,name:t.name,price:t.price,quantity:t.quantity,category:t.category,brand:t.brand,variant:t.variant,variant_id:t.variantId,sku:t.sku,image_url:t.imageUrl,url:t.url,item_total:dt(t.price*t.quantity),cart_value:dt(i),currency:this.config.currency}))}removeFromCart(t,i=1){this.guard("removeFromCart",this.productProblem(t,"item"),()=>this.sdk.track("Product Removed",{product_id:t.productId,name:t.name,price:t.price,quantity:ut(i)?i:1,variant_id:t.variantId,sku:t.sku,currency:this.config.currency}))}cartViewed(t,i){this.guard("cartViewed",this.cartProblem(t,i),()=>{const e=this.validItems(t);this.sdk.track("Cart Viewed",{items:e.map(t=>({product_id:t.productId,name:t.name,price:t.price,quantity:t.quantity,variant_id:t.variantId,sku:t.sku})),item_count:this.itemCount(e),cart_value:dt(i),currency:this.config.currency})})}updateCart(t,i){this.guard("updateCart",this.cartProblem(t,i),()=>{const e=this.validItems(t);this.sdk.track("Cart Updated",{items:e.map(t=>({product_id:t.productId,name:t.name,price:t.price,quantity:t.quantity,variant_id:t.variantId,sku:t.sku})),item_count:this.itemCount(e),cart_value:dt(i),currency:this.config.currency})})}startCheckout(t,i,e){this.guard("startCheckout",this.cartProblem(t,i),()=>{const s=this.validItems(t);this.sdk.track("Checkout Started",Object.assign({items:s.map(t=>({product_id:t.productId,name:t.name,price:t.price,quantity:t.quantity,variant_id:t.variantId,sku:t.sku})),item_count:this.itemCount(s),value:dt(i),currency:this.config.currency},e&&"object"==typeof e?e:{}))})}addPaymentInfo(t,i){this.guard("addPaymentInfo",this.textProblem({paymentMethod:t}),()=>this.sdk.track("Payment Info Entered",Object.assign({payment_method:t},i&&"object"==typeof i?i:{})))}purchase(t){var i;const e=t&&"object"==typeof t?at(t.orderId)?ut(t.value)?null!==(i=this.itemsProblem(t.items))&&void 0!==i?i:this.amountsProblem({shipping:t.shipping,tax:t.tax,discount:t.discount}):"order.value must be a finite number":"order.orderId is required":"an order object is required";this.guard("purchase",e,()=>{const i=this.validItems(t.items);this.sdk.track("Order Completed",{orderId:t.orderId,items:i.map(t=>({product_id:t.productId,name:t.name,price:t.price,quantity:t.quantity,category:t.category,brand:t.brand,variant_id:t.variantId,sku:t.sku})),item_count:this.itemCount(i),total:t.value,currency:t.currency||this.config.currency,shipping:dt(t.shipping),tax:dt(t.tax),discount:dt(t.discount),coupon:t.coupon})})}orderFulfilled(t,i,e){this.guard("orderFulfilled",at(t)?null:"an orderId is required",()=>this.sdk.track("Order Fulfilled",{order_id:t,tracking_number:i,carrier:e}))}orderDelivered(t){this.guard("orderDelivered",at(t)?null:"an orderId is required",()=>this.sdk.track("Order Delivered",{order_id:t}))}orderCancelled(t,i){this.guard("orderCancelled",at(t)?null:"an orderId is required",()=>this.sdk.track("Order Cancelled",{order_id:t,reason:i}))}orderRefunded(t,i,e){var s;const n=null!==(s=this.textProblem({orderId:t}))&&void 0!==s?s:this.amountsProblem({refundAmount:i});this.guard("orderRefunded",n,()=>this.sdk.track("Order Refunded",{order_id:t,refund_amount:dt(i),reason:e}))}addToWishlist(t){this.guard("addToWishlist",this.productProblem(t),()=>this.sdk.track("Product Added to Wishlist",{product_id:t.productId,name:t.name,price:t.price,category:t.category,brand:t.brand,currency:this.config.currency}))}removeFromWishlist(t){this.guard("removeFromWishlist",this.productProblem(t),()=>this.sdk.track("Product Removed from Wishlist",{product_id:t.productId,name:t.name}))}shareProduct(t,i){var e;this.guard("shareProduct",null!==(e=this.productProblem(t))&&void 0!==e?e:this.textProblem({shareMethod:i}),()=>this.sdk.track("Product Shared",{product_id:t.productId,name:t.name,share_method:i}))}applyCoupon(t,i,e){var s;const n=null!==(s=this.textProblem({couponCode:t}))&&void 0!==s?s:this.amountsProblem({discountAmount:i});this.guard("applyCoupon",n,()=>this.sdk.track("Coupon Applied",{coupon_code:t,discount_amount:dt(i),discount_type:e}))}removeCoupon(t){this.guard("removeCoupon",at(t)?null:"a couponCode is required",()=>this.sdk.track("Coupon Removed",{coupon_code:t}))}submitReview(t,i,e){const s=at(t)?ut(i)?null:"rating must be a finite number":"a productId is required";this.guard("submitReview",s,()=>this.sdk.track("Product Reviewed",{product_id:t,rating:i,review_text:e}))}}function ct(t,i,e){return new lt(t,i,e)}function pt(t,i){var e={};for(var s in t)Object.prototype.hasOwnProperty.call(t,s)&&0>i.indexOf(s)&&(e[s]=t[s]);if(null!=t&&"function"==typeof Object.getOwnPropertySymbols){var n=0;for(s=Object.getOwnPropertySymbols(t);n<s.length;n++)0>i.indexOf(s[n])&&Object.prototype.propertyIsEnumerable.call(t,s[n])&&(e[s[n]]=t[s[n]])}return e}function ft(t){switch(t.kind){case"subscription":return"unsubscribed"===t.payload.status;case"group":return"unsubscribe"===t.payload.action;case"marker":return!0===t.payload.value;default:return!1}}"function"==typeof SuppressedError&&SuppressedError;const yt=[2e3,5e3,15e3,3e4,6e4,6e4,6e4,6e4,6e4],mt=3e5;function vt(t,i){const e=yt[Math.min(Math.max(t,1),yt.length)-1];return Math.min(Math.max(t>yt.length?Math.min(e*Math.pow(2,t-yt.length),mt):e,null!=i?i:0),mt)}function bt(t,i){if(t.ok)return{action:"done"};if(t.softFailure)return{action:"retry",counts:!0};const e=t.status;return 0!==e&&408!==e&&429!==e&&500>e?404===e?{action:"retry",counts:!0,notFound:!0}:401===e?i.isSdkAuthError?i.ownerIsCurrentUser?{action:"retry",counts:!0}:{action:"drop",reason:"SDK authentication refused a write of a user who is no longer signed in (401)"}:{action:"hold",reason:"the SDK key was refused (401)"}:402===e?{action:"retry",counts:!1,retryAfterMs:t.retryAfterMs}:{action:"drop",reason:`refused by the server (HTTP ${e})`}:{action:"retry",counts:!1,retryAfterMs:t.retryAfterMs}}function gt(t,i){return t>=10||i>=5}const wt="push_registration",kt="push_unregistered",St="push_pending_unregister",jt="joryio-sdk-state";class At{constructor(t,i,e,s,n={}){this.logger=t,this.network=i,this.identity=e,this.apiEndpoint=s,this.vapidKeyCache=null,this.prepared=null,this.lastPrepareError=null,this.unregisterInFlight=!1,this.unregisterTimer=null,this.canSend=n.canSend||(()=>!0),this.canWithdraw=n.canWithdraw||(()=>!0),this.withdrawalUserId=n.withdrawalUserId||(()=>this.identity.getUserId()),this.storage=n.storage||null,this.getDeviceId=n.getDeviceId||(()=>{}),this.onSubscribeSettled=n.onSubscribeSettled||null}isSupported(){return"undefined"!=typeof window&&"serviceWorker"in navigator&&"PushManager"in window&&"Notification"in window}getPermissionState(){if(!this.isSupported())return"unavailable";const t=Notification.permission;return"granted"===t||"denied"===t?t:"notDetermined"}async getExistingSubscription(t){if(!this.isSupported())return null;try{const i=await navigator.serviceWorker.getRegistration((null==t?void 0:t.scope)||"/");return i?await i.pushManager.getSubscription():null}catch(t){return this.logger.warn("Could not read the push subscription:",t),null}}async syncExistingSubscription(t=!1,i){var e,s;try{if(await this.sendPendingUnregister(),!this.canSend())return;if(!0===(null===(e=this.storage)||void 0===e?void 0:e.get(kt)))return;if(!this.isSupported()||"granted"!==Notification.permission)return;const n=await navigator.serviceWorker.getRegistration((null==i?void 0:i.scope)||"/");if(!n)return;let r=await n.pushManager.getSubscription();const o=null===(s=this.storage)||void 0===s?void 0:s.get(wt),h=this.identity.getUserId(),a=this.identity.getAnonymousId(),u=!o||Date.now()-(o.at||0)>864e5,d=!r||!o||o.endpoint!==r.endpoint||o.userId!==h||o.anonymousId!==a;if(!t&&!u&&!d)return;const l=await this.fetchVapidPublicKey();if(!l)return;r&&!this.subscriptionKeyMatches(r,l)&&(this.logger.info("VAPID key changed - re-subscribing this browser"),await r.unsubscribe().catch(()=>!1),r=null),r||(r=await n.pushManager.subscribe({userVisibleOnly:!0,applicationServerKey:It(l)})),await this.registerWithBackend(r)}catch(t){this.logger.warn("Could not refresh the push subscription:",t)}}async setTrackingOptedOut(t){try{if("undefined"==typeof caches)return;if(t){const t=await caches.open(jt);await t.put("/__joryio/tracking-opted-out",new Response("1"))}else await caches.delete(jt)}catch(t){this.logger.debug("Could not record the opt-out for the service worker:",t)}}async prepare(t){if(t=t||{},!this.isSupported())return this.lastPrepareError="unsupported",!1;if(this.prepared)return this.lastPrepareError=null,!0;const i=await this.fetchVapidPublicKey();if(!i)return this.lastPrepareError="no-key",this.logger.error("Web push is not enabled for this workspace"),!1;try{const e=await navigator.serviceWorker.register(t.swPath||"/joryio-sw.js",{scope:t.scope||"/"});return await navigator.serviceWorker.ready,this.prepared={registration:e,publicKey:i},this.lastPrepareError=null,!0}catch(t){return this.lastPrepareError="sw-failed",this.logger.error("Service worker registration failed:",t),!1}}async subscribe(t){var i;try{return await this.subscribeOnce(t)}finally{try{null===(i=this.onSubscribeSettled)||void 0===i||i.call(this)}catch(t){this.logger.warn("Push permission report failed:",t)}}}async subscribeOnce(t){var i;if(t=t||{},!this.isSupported())return console.warn("[Joryio SDK] Push not enabled: this browser/context does not support web push (needs HTTPS, a service worker, and PushManager - Safari < 16.4 and insecure origins are excluded)."),null;this.prepared||await this.prepare(t);const e=this.prepared;if(!e){this.logger.error("Web push is not enabled for this workspace");const i=t.swPath||"/joryio-sw.js";return"no-key"===this.lastPrepareError?console.warn("[Joryio SDK] Push not enabled: the server returned no VAPID key - web push is not configured for this app. Enable web push for THIS app (the one your SDK key belongs to) in the dashboard."):"sw-failed"===this.lastPrepareError?console.warn(`[Joryio SDK] Push not enabled: the service worker failed to register. The VAPID key was fetched OK, so the problem is ${i}: make sure it is hosted on your origin AND its importScripts() points at https://sdk.joryio.com/web/1/joryio-sw.js (a dead URL makes the worker's install throw and registration fail).`):console.warn("[Joryio SDK] Push not enabled: could not prepare web push."),null}null===(i=this.storage)||void 0===i||i.remove(kt);try{const t=await e.registration.pushManager.getSubscription();if(t&&this.subscriptionKeyMatches(t,e.publicKey))return await this.registerWithBackend(t).catch(t=>this.logRegisterFailure(t)),t;t&&(this.logger.info("VAPID key changed - re-subscribing this browser"),await t.unsubscribe().catch(()=>{}));const i=await e.registration.pushManager.subscribe({userVisibleOnly:!0,applicationServerKey:It(e.publicKey)});return await this.sendPendingUnregister(),await this.registerWithBackend(i).catch(t=>this.logRegisterFailure(t)),this.logger.info("Web push subscribed"),i}catch(t){return"NotAllowedError"===(null==t?void 0:t.name)?(this.logger.info("User denied push permission"),console.warn("[Joryio SDK] Push not enabled: notification permission is denied. The browser will not re-prompt - the user must re-allow notifications for this site in browser settings.")):(this.logger.error("pushManager.subscribe failed:",t),console.warn("[Joryio SDK] Push not enabled: pushManager.subscribe failed:",t)),null}}async unsubscribe(t){var i,e;const s={userId:this.withdrawalUserId()||void 0,anonymousId:this.identity.getAnonymousId()};try{if(null===(i=this.storage)||void 0===i||i.set(kt,!0),null===(e=this.storage)||void 0===e||e.remove(wt),!this.isSupported())return!1;const n=await navigator.serviceWorker.getRegistration((null==t?void 0:t.scope)||"/");if(!n)return!1;const r=await n.pushManager.getSubscription();if(!r)return!0;const o=r.endpoint,h=await r.unsubscribe().catch(()=>!1),a=this.pendingUnregisters().filter(t=>t.endpoint!==o);return a.push(Object.assign({endpoint:o},s)),this.storePendingUnregisters(a),await this.sendPendingUnregister(),h}catch(t){return this.logger.warn("Push unsubscribe failed:",t),!1}}async forget(){await this.unsubscribe(),this.prepared=null}pendingUnregisterUsers(){return this.pendingUnregisters().map(t=>t.userId).filter(t=>"string"==typeof t&&!!t)}pendingUnregisters(){var t;const i=null===(t=this.storage)||void 0===t?void 0:t.get(St);return(Array.isArray(i)?i:i?[i]:[]).filter(t=>t&&"string"==typeof t.endpoint&&t.endpoint&&"string"==typeof t.anonymousId)}storePendingUnregisters(t){var i,e;t.length?null===(i=this.storage)||void 0===i||i.set(St,t.slice(-20)):null===(e=this.storage)||void 0===e||e.remove(St)}retryPendingUnregister(){this.sendPendingUnregister().catch(()=>{})}async sendPendingUnregister(){if(!this.unregisterInFlight&&this.canWithdraw()&&("undefined"==typeof navigator||!1!==navigator.onLine)){null!==this.unregisterTimer&&(clearTimeout(this.unregisterTimer),this.unregisterTimer=null),this.unregisterInFlight=!0;try{for(;;){const[t]=this.pendingUnregisters();if(!t)return;const{attempts:i=0,notFoundAttempts:e=0,failures:s=0}=t,n=pt(t,["attempts","notFoundAttempts","failures"]),r=await this.network.request({url:this.apiEndpoint+"/v1/push/unregister",method:"POST",body:Object.assign({platform:"web"},n),subjectUserId:n.userId||null}),o=bt(r,{isSdkAuthError:this.network.isSdkAuthError(r.status,r.data),ownerIsCurrentUser:(n.userId||null)===this.withdrawalUserId()}),h=this.pendingUnregisters().filter(i=>i.endpoint!==t.endpoint);if("done"===o.action||"drop"===o.action){"drop"===o.action&&this.logger.error("Push unregister dropped: "+o.reason),this.storePendingUnregisters(h);continue}if("hold"===o.action)return;const a=Object.assign(Object.assign({},t),{failures:s+1,attempts:i+(o.counts&&!o.notFound?1:0),notFoundAttempts:e+(o.counts&&o.notFound?1:0)});if(!gt(a.attempts,a.notFoundAttempts))return this.storePendingUnregisters([a,...h]),void(this.unregisterTimer=setTimeout(()=>{this.unregisterTimer=null,this.sendPendingUnregister().catch(()=>{})},vt(a.failures,o.retryAfterMs)));this.logger.error("Push unregister failed too many times; dropping it"),this.storePendingUnregisters(h)}}catch(t){this.logger.warn("Failed to notify backend about unsubscribe:",t)}finally{this.unregisterInFlight=!1}}}destroy(){null!==this.unregisterTimer&&clearTimeout(this.unregisterTimer),this.unregisterTimer=null}logRegisterFailure(t){this.logger.warn("This browser is subscribed, but registering it with Joryio failed; it is retried on the next page load:",t)}subscriptionKeyMatches(t,i){var e;try{const s=null===(e=t.options)||void 0===e?void 0:e.applicationServerKey;if(!s)return!0;const n=new Uint8Array(s),r=It(i);if(n.byteLength!==r.byteLength)return!1;for(let t=0;t<n.byteLength;t++)if(n[t]!==r[t])return!1;return!0}catch(t){return!0}}async fetchVapidPublicKey(){var t,i;if(this.vapidKeyCache)return this.vapidKeyCache;try{const e=await this.network.request({url:this.apiEndpoint+"/v1/push/vapid-public-key",method:"GET"});return e.ok&&(null===(t=e.data)||void 0===t?void 0:t.enabled)&&(null===(i=e.data)||void 0===i?void 0:i.publicKey)?(this.vapidKeyCache=e.data.publicKey,this.vapidKeyCache):null}catch(t){return this.logger.error("Failed to fetch VAPID public key:",t),null}}async registerWithBackend(t){var i,e,s,n;if(!this.canSend())return void this.logger.debug("Push subscription not registered: tracking is off or consent is pending");const r=t.toJSON(),o=this.getDeviceId(),h=Object.assign({platform:"web",subscription:{endpoint:t.endpoint,keys:{p256dh:(null===(i=r.keys)||void 0===i?void 0:i.p256dh)||"",auth:(null===(e=r.keys)||void 0===e?void 0:e.auth)||""}},userId:this.identity.getUserId()||void 0,anonymousId:this.identity.getAnonymousId()},o?{deviceId:o}:{}),a=this.pendingUnregisters();a.some(i=>i.endpoint===t.endpoint)&&this.storePendingUnregisters(a.filter(i=>i.endpoint!==t.endpoint));const u=await this.network.request({url:this.apiEndpoint+"/v1/push/register",method:"POST",body:h,subjectUserId:h.userId||null});if(!u.ok)throw Error("Failed to register subscription: "+(u.error||u.status));null===(s=this.storage)||void 0===s||s.set(wt,{endpoint:t.endpoint,userId:null!==(n=h.userId)&&void 0!==n?n:null,anonymousId:h.anonymousId,at:Date.now()})}}function It(t){const i=(t+"=".repeat((4-t.length%4)%4)).replace(/-/g,"+").replace(/_/g,"/"),e=atob(i),s=new Uint8Array(e.length);for(let t=0;t<e.length;t++)s[t]=e.charCodeAt(t);return s}const Ot="write_outbox",$t="deferred_writes",Dt="write_outbox_removed";function _t(t){const i=t.payload;return Object.assign({anonymousId:i.anonymousId},i.userId?{userId:i.userId}:{})}function Tt(t){switch(t.kind){case"subscription":return"subscription:"+t.payload.channel;case"group":return`group:${t.payload.groupId}:${t.payload.channel}`;case"marker":return"marker";default:return null}}function Ct(t){switch(t.kind){case"alias":return"addAlias";case"subscription":return`Update ${t.payload.channel} subscription`;case"group":return`Subscription group ${t.payload.groupId} ${t.payload.action}`;case"marker":return"The tracking_opted_out marker"}}function xt(){return"undefined"!=typeof navigator&&!1===navigator.onLine}function Pt(t){return!(!t||"object"!=typeof t||"alias"!==t.kind&&"subscription"!==t.kind&&"group"!==t.kind&&"marker"!==t.kind||!t.payload||"object"!=typeof t.payload||"string"!=typeof t.payload.anonymousId)}function Mt(t){if(!t||!Pt(t.record))return null;const i=t=>Number.isInteger(t)&&t>=0?t:0;return{id:"string"==typeof t.id?t.id:o(),record:t.record,withdrawal:ft(t.record),attempts:i(t.attempts),notFoundAttempts:i(t.notFoundAttempts),failures:i(t.failures),notBefore:0,createdAt:"number"==typeof t.createdAt&&Number.isFinite(t.createdAt)?t.createdAt:0}}class Kt{constructor(t){this.deps=t,this.entries=[],this.inFlight=null,this.timer=null,this.stopped=!1,this.handedOffAt=new Map,this.destroyed=!1,this.knownIds=new Set,this.load()}enqueue(t){if(this.destroyed)return;const i={id:o(),record:t,withdrawal:ft(t),attempts:0,notFoundAttempts:0,failures:0,notBefore:0,createdAt:Date.now()};this.knownIds.add(i.id);const e=Tt(t);e&&(this.entries=this.entries.filter(i=>i===this.inFlight||Tt(i.record)!==e||!this.sameOwner(i.record,t))),this.entries.push(i),this.trim(),this.persist(),this.kick()}discardNonWithdrawals(){this.entries=this.entries.filter(t=>t.withdrawal),this.persist({discardNonWithdrawals:!0})}persistNow(){this.persist()}find(t){return this.entries.find(t)}findLast(t){for(let i=this.entries.length-1;i>=0;i--)if(t(this.entries[i]))return this.entries[i]}cancel(t){const i=this.entries.length;this.entries=this.entries.filter(i=>i===this.inFlight||!t(i)),this.entries.length!==i&&this.persist()}pinOwner(t,i){let e=!1;for(const s of this.entries){const n=s.record.payload;n.anonymousId!==t||n.userId||(s.record=Object.assign(Object.assign({},s.record),{payload:Object.assign(Object.assign({},n),{userId:i})}),e=!0)}e&&this.persist()}isInFlight(t){return this.inFlight===t}size(){return this.entries.length}records(){return this.entries.map(t=>t.record)}kick(){if(this.destroyed||this.stopped||this.inFlight)return;if(null!==this.timer&&(clearTimeout(this.timer),this.timer=null),xt())return;const t=Date.now(),i=new Set;let e=1/0,s=null;for(const n of[...this.entries]){const r=this.blockKey(n);if(i.has(r))continue;const o=this.safeGate(n);if("drop"!==o)if("hold"!==o){if(n.notBefore<=t){s=n;break}i.add(r),e=Math.min(e,n.notBefore)}else i.add(r);else this.remove(n)}s?this.run(s):1/0>e&&(this.timer=setTimeout(()=>{this.timer=null,this.kick()},Math.max(0,e-t)))}handOffAtUnload(t){let i=0;if(!this.deps.keepalive||this.destroyed||this.stopped||xt())return i;this.persist();const e=Date.now(),s=new Set;this.inFlight&&s.add(this.blockKey(this.inFlight));for(const n of[...this.entries]){const r=this.blockKey(n);if(s.has(r))continue;if(n!==this.inFlight&&this.removedElsewhere(n)){this.deps.logger.debug(Ct(n.record)+" not handed off: another tab settled or replaced it");const t=this.entries.indexOf(n);0>t||this.entries.splice(t,1);continue}if(s.add(r),n===this.inFlight||"send"!==this.safeGate(n))continue;const o=this.handedOffAt.get(n.id);if(void 0===o||e-o>=1e4)try{const s=this.deps.keepalive(n,this.deps.resolveOwner(_t(n.record)));if(null===s)break;if(this.handedOffAt.set(n.id,e),i+=s,i>=t)break}catch(t){break}}return this.persist(),i}destroy(){this.destroyed=!0,null!==this.timer&&clearTimeout(this.timer),this.timer=null}async run(t){this.inFlight=t;const i=Ct(t.record);try{if(await this.deps.beforeSend(t).catch(()=>{}),!this.entries.includes(t))return;const e=this.safeGate(t);if("drop"===e)return void this.remove(t);if("hold"===e)return;if(this.removedElsewhere(t))return this.deps.logger.debug(i+" not sent: another tab settled or replaced it"),void this.remove(t);const s=this.deps.resolveOwner(_t(t.record)),n=await this.deps.send(t,s);if(!this.entries.includes(t))return;const r=bt(n,{isSdkAuthError:this.deps.isSdkAuthError(n.status,n.data),ownerIsCurrentUser:this.deps.ownerIsCurrentUser(s)});switch(r.action){case"done":return void this.settle(t,"done");case"drop":return this.deps.logger.error(`${i} dropped: ${r.reason}`),void this.settle(t,"drop");case"hold":return this.deps.logger.error(`${i} not sent: ${r.reason}; kept for the next page view`),void(this.stopped=!0);case"retry":return this.hasNewerOfSameSubject(t)?void this.remove(t):(t.failures++,r.counts&&(r.notFound?t.notFoundAttempts++:t.attempts++),gt(t.attempts,t.notFoundAttempts)?(this.deps.logger.error(`${i} failed (HTTP ${n.status||"no response"}) too many times; dropping it`),void this.settle(t,"drop")):(t.notBefore=Date.now()+vt(t.failures,r.retryAfterMs),void this.deps.logger.debug(`${i} failed with HTTP ${n.status||"no response"}; retrying`)))}}catch(e){this.deps.logger.error(i+" failed:",e),t.failures++,t.notBefore=Date.now()+vt(t.failures)}finally{this.inFlight===t&&(this.inFlight=null),this.persist(),this.kick()}}safeGate(t){try{return this.deps.gate(t)}catch(t){return"hold"}}settle(t,i){var e,s;this.remove(t);try{null===(s=(e=this.deps).onSettled)||void 0===s||s.call(e,t,i)}catch(t){this.deps.logger.error("Outbox bookkeeping failed:",t)}}remove(t){const i=this.entries.indexOf(t);0>i||(this.entries.splice(i,1),this.persist())}hasNewerOfSameSubject(t){const i=Tt(t.record);if(!i)return!1;const e=this.entries.indexOf(t);return this.entries.slice(e+1).some(e=>Tt(e.record)===i&&this.sameOwner(e.record,t.record))}effectiveUser(t){if(t.userId)return t.userId;const i=this.deps.currentIdentity();return t.anonymousId===i.anonymousId?i.userId:null}sameOwner(t,i){const e=_t(t),s=_t(i);return e.anonymousId===s.anonymousId&&this.effectiveUser(e)===this.effectiveUser(s)}blockKey(t){var i;const e=_t(t.record);return`${null!==(i=Tt(t.record))&&void 0!==i?i:`${t.record.kind}:${t.id}`}|${e.anonymousId}`}trim(){for(;this.entries.length>200;){let t=this.entries.findIndex(t=>!t.withdrawal&&t!==this.inFlight);if(0>t&&(t=this.entries.findIndex(t=>t!==this.inFlight)),0>t)break;const[i]=this.entries.splice(t,1);this.deps.logger.warn(`Too many profile writes waiting; dropped the oldest (${Ct(i.record)})`)}}persist(t={}){try{const i=this.deps.storage.get(Ot),e=Array.isArray(i)?i.filter(t=>t&&"string"==typeof t.id).map(t=>t.id):[],s=this.readRemoved();this.entries=this.entries.filter(t=>t===this.inFlight||!s.has(t.id));let n=this.foreignStoredEntries(i).filter(t=>!s.has(t.id));t.discardNonWithdrawals&&(n=n.filter(t=>t.withdrawal));let r=this.entries;if(n.length){const t=[...this.entries,...n].sort((t,i)=>t.createdAt-i.createdAt),i=(i,e)=>{const s=Tt(i.record);return!!s&&i!==this.inFlight&&t.slice(e+1).some(t=>Tt(t.record)===s&&this.sameOwner(t.record,i.record))};for(r=t.filter((t,e)=>!i(t,e));r.length>200;){let t=r.findIndex(t=>!t.withdrawal&&t!==this.inFlight);if(0>t&&(t=r.findIndex(t=>t!==this.inFlight)),0>t)break;this.deps.logger.warn(`Too many profile writes waiting; dropped the oldest (${Ct(r[t].record)})`),r=r.filter((i,e)=>e!==t)}this.entries=this.entries.filter(t=>t===this.inFlight||r.includes(t))}const o=r.filter(t=>!s.has(t.id));this.write(o);const h=new Set(o.map(t=>t.id)),a=e.filter(t=>!h.has(t)&&!s.has(t));a.length&&this.writeRemoved(s,a)}catch(t){this.deps.logger.error("Failed to store pending profile writes:",t)}}removedElsewhere(t){try{if(this.readRemoved().has(t.id))return!0;const i=Tt(t.record);if(!i)return!1;const e=this.deps.storage.get(Ot);return!!Array.isArray(e)&&e.some(e=>e&&e.id!==t.id&&Pt(e.record)&&"number"==typeof e.createdAt&&e.createdAt>t.createdAt&&Tt(e.record)===i&&this.sameOwner(e.record,t.record))}catch(t){return!1}}readRemoved(){const t=new Map,i=this.deps.storage.get(Dt);if(!Array.isArray(i))return t;const e=Date.now();for(const s of i)Array.isArray(s)&&"string"==typeof s[0]&&"number"==typeof s[1]&&(e-s[1]>2592e6||t.set(s[0],s[1]));return t}writeRemoved(t,i){const e=Date.now(),s=[...t.entries(),...i.map(t=>[t,e])];this.deps.storage.set(Dt,s.slice(-500))}write(t){t.length?this.deps.storage.set(Ot,t.map(t=>({id:t.id,record:t.record,attempts:t.attempts,notFoundAttempts:t.notFoundAttempts,failures:t.failures,createdAt:t.createdAt}))):this.deps.storage.remove(Ot)}foreignStoredEntries(t){if(!Array.isArray(t))return[];const i=[];for(const e of t){if(!e||"string"!=typeof e.id||this.knownIds.has(e.id)||!Pt(e.record))continue;const t=Mt(e);t&&i.push(t)}return i}load(){const t=this.deps.storage.get(Ot);if(Array.isArray(t))for(const i of t){const t=Mt(i);t&&(this.entries.push(t),this.knownIds.add(t.id))}const i=this.deps.storage.get($t);if(Array.isArray(i)){for(const t of i){if(!Pt(t))continue;const i={id:o(),record:t,withdrawal:ft(t),attempts:0,notFoundAttempts:0,failures:0,notBefore:0,createdAt:0};this.entries.push(i),this.knownIds.add(i.id)}this.deps.storage.remove($t),this.trim(),this.persist()}else this.entries.length>200&&(this.trim(),this.persist())}}function Ft(t){const i=[],e=(t,s)=>{switch(typeof t){case"number":return Number.isFinite(t)?null:"a non-finite number (NaN or Infinity)";case"bigint":return"a BigInt";case"function":return"a function";case"symbol":return"a symbol";case"object":if(null===t)return null;if(s>100)return"a value nested deeper than 100 levels";if("function"==typeof t.toJSON)try{return JSON.stringify(t),null}catch(t){return"a value that cannot be serialized"}if(i.includes(t))return"a circular reference";i.push(t);try{const i=Array.isArray(t)?t:Object.values(t);for(const t of i){const i=e(t,s+1);if(i)return i}}finally{i.pop()}return null;default:return null}};try{return e(t,1)}catch(t){return"a value that cannot be serialized"}}function Nt(t,i){const e={};for(const s of Object.keys(t)){const n=Ft(t[s]);n?i(s,n):e[s]=t[s]}return e}const qt="tracking_opted_out",Et="tracking_consent",Ut="tracking_consent_granted_at",zt="tracking_consent_denied_at",Rt="tracking_opted_out_at",Jt="tracking_opt_in_at",Ht="reported_tracking_opted_out",Wt="tracking_opted_out_marker_given_up",Lt="session_start_sent",Bt="withdrawal_user_id",Vt="retired_sdk_auth_tokens",Qt=[K,F,N,Ot,St,"held_attribute_writes"];function Gt(t,i,e=0){if(t&&"object"==typeof t&&6>=e)if(Array.isArray(t))for(const s of t)Gt(s,i,e+1);else for(const[s,n]of Object.entries(t))"userId"===s&&"string"==typeof n&&n?i.add(n):Gt(n,i,e+1)}const Xt=new WeakMap;function Yt(t,i,e){const s=t,n=s.dataGate;s.dataGate=new Set([...n,...i]);try{e()}finally{s.dataGate=n}}const Zt="anonymous_id",ti="user_id",ii=["jry_sdk_ios_","jry_sdk_android_"],ei="tracking_opted_out",si="held_attribute_writes",ni="joryio_reported_push_permission",ri="push_permission";class oi{constructor(t,n){if(this.attributeFlushTimer=null,this.attributeFlushInFlight=!1,this.attributeFlushAgain=!1,this.attributeGeneration=0,this.attributeFailures=0,this.t=null,this.isInitialized=!1,this.isOptedOut=!1,this.disabled=!1,this.consentPending=!1,this.userOptedOut=!1,this.dntEnabled=!1,this.trackingConsent="granted",this.lastTrackedUrl=null,this.boundHandlePageUnload=null,this.boundHandleOnline=null,this.boundHandleStorage=null,this.withdrawalUserId=null,this.optedOutAt=0,this.consentDeniedAt=0,this.lastDecisionStamp=0,this.awaitingSessionOf=null,this.pruneTimer=null,this.dataGate=new Set,this.inflightSessionStartAtClear=null,oi.instance)return console.warn("[Joryio] SDK already initialized. Returning existing instance."),oi.instance;const o=t&&"object"==typeof t&&"string"==typeof t.sdkKey&&t.sdkKey?t.sdkKey.startsWith("jry_sdk_")?ii.some(i=>t.sdkKey.startsWith(i))?"this is a mobile app key - use the web SDK key (jry_sdk_web_...) from Settings -> Apps":null:"invalid SDK key format, expected jry_sdk_*":"sdkKey is required";o&&(console.error(`[Joryio] SDK not started: ${o}. Calls on this instance are ignored.`),this.disabled=!0),this.config=function(t){var i,n,r,o,h,a,u,d,l,c,p,f,y,m,v,b,g;!function(t){const i=t;for(const[t,e]of Object.entries(s))void 0!==i[t]&&console.warn(`[Joryio] \`${t}\` must be nested under \`${e}\`, not passed at the top level - as written it is IGNORED. Use: { ${e}: { ${t}: ${JSON.stringify(i[t])} } }`);void 0!==i.disablePlugins&&console.warn("[Joryio] `disablePlugins` was removed in 1.3.0 and is ignored - leave a plugin out of `plugins` instead.")}(t);const w={enabled:!1!==(null===(i=t.inApp)||void 0===i?void 0:i.enabled),evaluationMode:"session-start-only"===(null===(n=t.inApp)||void 0===n?void 0:n.evaluationMode)?"session-start-only":"differential-sync",syncInterval:(null===(r=t.inApp)||void 0===r?void 0:r.syncInterval)&&t.inApp.syncInterval>0?Math.max(3e4,t.inApp.syncInterval):0,displayOptions:{defaultPosition:(null===(h=null===(o=t.inApp)||void 0===o?void 0:o.displayOptions)||void 0===h?void 0:h.defaultPosition)||"center",defaultAnimation:(null===(u=null===(a=t.inApp)||void 0===a?void 0:a.displayOptions)||void 0===u?void 0:u.defaultAnimation)||"fade",backdropColor:(null===(l=null===(d=t.inApp)||void 0===d?void 0:d.displayOptions)||void 0===l?void 0:l.backdropColor)||"rgba(0, 0, 0, 0.5)",closeButtonColor:(null===(p=null===(c=t.inApp)||void 0===c?void 0:c.displayOptions)||void 0===p?void 0:p.closeButtonColor)||void 0,zIndex:(null===(y=null===(f=t.inApp)||void 0===f?void 0:f.displayOptions)||void 0===y?void 0:y.zIndex)||999999},allowHtmlJsInAppMessages:!0===(null===(m=t.inApp)||void 0===m?void 0:m.allowHtmlJsInAppMessages),onMessageDisplay:(null===(v=t.inApp)||void 0===v?void 0:v.onMessageDisplay)||(()=>{}),onMessageClick:(null===(b=t.inApp)||void 0===b?void 0:b.onMessageClick)||(()=>{}),onMessageDismiss:(null===(g=t.inApp)||void 0===g?void 0:g.onMessageDismiss)||(()=>{})};return{sdkKey:t.sdkKey,apiEndpoint:e(t.apiEndpoint),userId:t.userId,anonymousId:t.anonymousId||"",batchSize:t.batchSize||50,batchFlushInterval:"number"==typeof t.batchFlushInterval&&t.batchFlushInterval>0?Math.max(1e3,t.batchFlushInterval):5e3,sendImmediately:t.sendImmediately||!1,maxQueueSize:t.maxQueueSize||1e3,sessionTimeout:t.sessionTimeout||18e5,trackSessionStart:!1!==t.trackSessionStart,trackPageViews:!0===t.trackPageViews,captureUTM:!1!==t.captureUTM,resetSessionOnNewCampaign:t.resetSessionOnNewCampaign||!1,trackPageProperties:!1!==t.trackPageProperties,trackDeviceProperties:!1!==t.trackDeviceProperties,inApp:w,persistQueue:!1!==t.persistQueue,maxRetries:"number"!=typeof t.maxRetries||0>t.maxRetries?3:Math.floor(t.maxRetries),retryBackoffMs:t.retryBackoffMs||1e3,requestTimeout:t.requestTimeout&&t.requestTimeout>0?t.requestTimeout:1e4,respectDoNotTrack:!1!==t.respectDoNotTrack,optOut:!0===t.optOut,trackingConsent:"granted"===t.trackingConsent||"denied"===t.trackingConsent||"pending"===t.trackingConsent?t.trackingConsent:void 0,enableSdkAuthentication:!0===t.enableSdkAuthentication,sdkAuthenticationToken:t.sdkAuthenticationToken,enableDebug:t.enableDebug||!1,logLevel:t.logLevel||(t.enableDebug?"debug":"error"),loggingEnabled:!0===t.enableDebug||!!t.logLevel,plugins:t.plugins||[]}}(o?Object.assign(Object.assign({},t&&"object"==typeof t?t:{}),{sdkKey:"jry_sdk_invalid",optOut:!1}):t),this.logger=new ot(this.config.loggingEnabled,this.config.logLevel),this.logger.info("Initializing Joryio SDK v"+i),this.storage=new r(this.config.sdkKey,this.logger),this.dntEnabled=this.config.respectDoNotTrack&&this.isDoNotTrackEnabled(),this.dntEnabled&&this.logger.warn("Do Not Track is enabled, SDK will not track events"),this.config.optOut&&this.writeOptOut(),this.userOptedOut=this.config.optOut||this.storedOptOut(),this.userOptedOut&&(this.optedOutAt=this.storedStamp(Rt)),this.trackingConsent=this.initialConsent(this.config.trackingConsent),this.utm=new B(this.storage,this.logger,this.config.resetSessionOnNewCampaign);const h=this.config.resetSessionOnNewCampaign&&this.config.captureUTM&&this.utm.hasNewCampaign();this.session=new c(this.storage,this.logger,this.config.sessionTimeout),h&&(this.logger.info("New campaign detected, resetting session"),this.session.resetSession()),this.identity=new S(this.storage,this.logger,this.config.userId,this.config.anonymousId),this.deviceId=this.getOrCreateDeviceId(),this.queue=new z(this.storage,this.logger,this.config.batchSize,this.config.batchFlushInterval,this.config.persistQueue,this.config.maxQueueSize,this.config.retryBackoffMs),this.network=new M(this.config.sdkKey,this.logger,{maxRetries:this.config.maxRetries,backoffMs:this.config.retryBackoffMs,timeoutMs:this.config.requestTimeout}),this.network.setRetiredTokenStore({load:()=>this.storage.get(Vt),update:t=>{const i=this.storage.get(Vt),e=t(i&&"object"==typeof i&&!Array.isArray(i)?i:{});Object.keys(e).length?this.storage.set(Vt,e):this.storage.remove(Vt)}});const a=this.storage.get(Bt),u="string"==typeof this.config.userId&&this.config.userId?this.config.userId:null;this.withdrawalUserId="string"==typeof a&&a&&a!==this.identity.getUserId()&&!u?a:null,!this.withdrawalUserId&&a&&this.storage.remove(Bt),this.network.setCurrentUserId(this.withdrawalUserId||this.identity.getUserId()),this.config.enableSdkAuthentication&&(this.network.setSdkAuthenticationEnabled(!0),this.config.sdkAuthenticationToken&&this.network.setSdkAuthenticationToken(this.config.sdkAuthenticationToken)),this.outbox=this.createOutbox(),this.inapp=new it(this.config.apiEndpoint,this.config.sdkKey,this.identity,this.session,this.logger,this.storage,Object.assign(Object.assign({closeButton:!0,backdropClose:!0},this.config.inApp.displayOptions),{onDisplay:this.config.inApp.onMessageDisplay,onClick:this.config.inApp.onMessageClick,onDismiss:this.config.inApp.onMessageDismiss}),{logCustomEvent:(t,i)=>this.track(t,i),setCustomUserAttribute:(t,i)=>this.setAttribute(t,i),changeUser:t=>this.identify(t),requestPushPermission:()=>{this.i.subscribe().catch(t=>{this.logger.warn("Push subscribe failed:",t)})},preparePushPermission:()=>{this.i.prepare().catch(t=>{this.logger.warn("Push prepare failed:",t)})}},this.network,{canSend:()=>this.canSend(),requestTimeoutMs:this.config.requestTimeout,syncIntervalMs:this.config.inApp.syncInterval,evaluationMode:this.config.inApp.evaluationMode,noteStatus:(t,i)=>{this.network.noteSuspended(t,i)}}),this.inapp.setAllowHtmlJsInAppMessages(this.config.inApp.allowHtmlJsInAppMessages),this.o=new nt(this.logger,this.network,this.identity,this.config.apiEndpoint,(t,i)=>this.runWrite(t,i)),this.i=new At(this.logger,this.network,this.identity,this.config.apiEndpoint,{canSend:()=>this.canSend(),canWithdraw:()=>this.isInitialized&&!this.disabled,withdrawalUserId:()=>this.effectiveUserId(),storage:this.storage,getDeviceId:()=>this.deviceId,onSubscribeSettled:()=>this.reportPushPermissionIfChanged()}),this.queue.setClearedInflightCallback(t=>{const i=this.inflightSessionStartAtClear;i&&(this.inflightSessionStartAtClear=null,t.some(t=>"Session Start"===t.type&&t.sessionId===i)||this.storage.get(Lt)!==i||this.storage.set(Lt,""))}),this.queue.setFlushCallback(async(t,i)=>{try{return await this.flushEvents(t,i)}finally{this.scheduleRetiredTokenPrune()}}),Xt.set(this,{optedOut:this.userOptedOut,consent:this.trackingConsent});for(const t of n||[])this.applyPreInitDecision(t);this.recomputePrivacy(),this.isOptedOut&&this.logger.warn("Tracking is off (opt-out, Do Not Track or consent denied)"),this.queue.setPaused(this.consentPending),this.isOptedOut&&this.queue.clear(),this.restoreAttributeWrites(),this.disabled||"undefined"==typeof window||"function"!=typeof window.addEventListener||(this.boundHandlePageUnload=this.handlePageUnload.bind(this),window.addEventListener("pagehide",this.boundHandlePageUnload),window.addEventListener("beforeunload",this.boundHandlePageUnload),this.boundHandleOnline=()=>{this.queue.resetBackoff(),this.canSend()&&this.queue.flush().catch(t=>this.logger.error("Flush failed:",t)),this.outbox.kick(),this.i.retryPendingUnregister(),!this.identity.pending.isEmpty()&&this.canSend()&&(this.attributeFailures=0,null!==this.attributeFlushTimer&&(clearTimeout(this.attributeFlushTimer),this.attributeFlushTimer=null),this.scheduleAttributeFlush(0))},window.addEventListener("online",this.boundHandleOnline),this.boundHandleStorage=t=>this.handleStorageEvent(t),window.addEventListener("storage",this.boundHandleStorage)),this.disabled||this.loadPlugins().catch(t=>this.logger.error("Plugin load failed:",t)),this.isInitialized=!0,this.disabled||(oi.instance=this),this.logger.info("SDK initialized successfully"),this.reportPushPermissionIfChanged();let d=!1;if(this.session.ensureSession(),this.config.trackSessionStart&&!this.isOptedOut){const t=this.session.getSessionInfo(),i=this.storage.get(Lt),e=null!==i&&i!==t.sessionId;(t.isNewSession||h||e)&&(this.trackSessionStart(),d=!0)}!this.config.trackPageViews||this.isOptedOut||d||(this.trackPageView(),"undefined"!=typeof document&&"loading"===document.readyState&&document.addEventListener("DOMContentLoaded",()=>{this.trackPageView()},{once:!0})),this.session.onNewSession(()=>{this.isOptedOut||(this.config.trackSessionStart&&(this.logger.debug("New session created (mid-visit), tracking session start"),this.trackSessionStart()),this.resyncInApp())}),this.canSend()&&(this.queue.start(),this.config.inApp.enabled&&this.inapp.initialize().catch(t=>{this.logger.error("Failed to initialize in-app messaging:",t)}),this.i.syncExistingSubscription().catch(()=>{}),this.releaseHeldWrites()),this.syncWorkerReporting(),this.isOptedOut||this.releaseDeferredIdentify(),this.syncOptOutMarker(),this.scheduleRetiredTokenPrune(),this.outbox.kick(),this.i.retryPendingUnregister()}createOutbox(){return new Kt({storage:this.storage,logger:this.logger,gate:t=>!this.isInitialized||this.disabled?"hold":t.withdrawal?"send":this.network.isSuspended()?"hold":this.isOptedOut?"drop":this.consentPending?"hold":"send",resolveOwner:t=>this.resolveOwner(t),ownerIsCurrentUser:t=>(t.userId||null)===this.effectiveUserId(),currentIdentity:()=>({anonymousId:this.identity.getAnonymousId(),userId:this.effectiveUserId()}),send:(t,i)=>this.sendWrite(t.record,i),beforeSend:()=>this.flushQueueForWrite(),isSdkAuthError:(t,i)=>this.network.isSdkAuthError(t,i),onSettled:(t,i)=>{this.onWriteSettled(t,i),this.scheduleRetiredTokenPrune()},keepalive:(t,i)=>{const e=this.writeRequest(t.record,i),s=JSON.stringify(e.body);return this.network.postKeepalive(e.url,e.body)?I(s)+256:null}})}currentOwner(){const t=this.effectiveUserId();return Object.assign({anonymousId:this.identity.getAnonymousId()},t?{userId:t}:{})}effectiveUserId(){return this.withdrawalUserId||this.identity.getUserId()}deferIdentify(t){t!==this.effectiveUserId()&&(this.network.switchUser(t),this.withdrawalUserId=t===this.identity.getUserId()?null:t,this.withdrawalUserId?this.storage.set(Bt,this.withdrawalUserId):this.storage.remove(Bt),this.logger.debug("Tracking is off: identify kept on this device for withdrawals only, not sent"))}releaseDeferredIdentify(){const t=this.withdrawalUserId;t&&(this.forgetDeferredIdentify(),this.identify(t))}forgetDeferredIdentify(){this.withdrawalUserId=null,this.storage.remove(Bt)}scheduleRetiredTokenPrune(t=0){null!==this.pruneTimer||this.disabled||(this.pruneTimer=setTimeout(()=>{this.pruneTimer=null,this.pruneRetiredTokens()},t))}pruneRetiredTokens(){var t;try{if(!this.network.retiredSdkAuthUsers().length)return;const i=new Set,e=this.network.getCurrentUserId();e&&i.add(e),this.withdrawalUserId&&i.add(this.withdrawalUserId);for(const t of this.queue.getQueuedEvents())t.userId&&i.add(t.userId);for(const t of this.queue.getPendingIdentifies())i.add(t.userId);for(const t of this.outbox.records()){const e=t.payload.userId;"string"==typeof e&&e&&i.add(e)}for(const e of this.identity.pending.serialize())(null===(t=e.owner)||void 0===t?void 0:t.userId)&&i.add(e.owner.userId);for(const t of this.i.pendingUnregisterUsers())i.add(t);for(const t of Qt)Gt(this.storage.get(t),i);const s=this.network.forgetRetiredSdkAuthTokensExcept(i);null!==s&&this.scheduleRetiredTokenPrune(s+50)}catch(t){this.logger.warn("Could not prune stored SDK authentication tokens:",t)}}handleStorageEvent(t){var i;try{if(!this.isInitialized||this.disabled||!t)return;const e=null!==(i=t.key)&&void 0!==i?i:null,s=t=>null===e||e===this.storage.storageKeyFor(t);if(null===e)this.repersistPrivacyDecisions(),this.outbox.persistNow();else if(s(qt)||s(Rt)||s(Jt)||s(Et)||s(zt)||s(Ut)){const t=this.storedOptOut(),i=this.storedDenial();t&&(this.optedOutAt=this.storedStamp(Rt)),i&&(this.consentDeniedAt=this.storedStamp(zt)),this.noteDecisionStamps();let e=!1;t!==this.userOptedOut&&(this.userOptedOut=t,e=!0),i&&"denied"!==this.trackingConsent?(this.trackingConsent="denied",e=!0):i||"denied"!==this.trackingConsent?!i&&"pending"===this.trackingConsent&&s(Ut)&&null!==this.storage.get(Ut)&&(this.trackingConsent="granted",e=!0):(this.trackingConsent="granted",e=!0),e&&this.applyPrivacyState()}if(null!==e&&s(Bt)){const t=this.storage.get(Bt),i="string"==typeof t&&t&&t!==this.identity.getUserId()?t:null;i!==this.withdrawalUserId&&(this.network.switchUser(i||this.identity.getUserId()),this.withdrawalUserId=i)}if(null!==e&&s(a)&&this.awaitingSessionOf&&(this.awaitingSessionOf===this.identity.getAnonymousId()&&this.storage.get(a)&&this.session.followStoredSession(),this.awaitingSessionOf=null),s(Zt)||s(ti)){const t=this.storage.get(Zt),i=this.storage.get(ti)||null;if(!t)return;if(t===this.identity.getAnonymousId()&&i===this.identity.getUserId())return;this.logger.info("Another tab changed the visitor identity; following it");const e=t!==this.identity.getAnonymousId();this.config.inApp.enabled?this.inapp.clearAll():this.inapp.invalidate(),this.pinAnonymousWrites(),this.network.switchUser(i),this.identity.adopt(t,i),this.withdrawalUserId=null,e&&(this.utm.reset(),this.session.followStoredSession(),this.awaitingSessionOf=t),this.resyncInApp(!0)}}catch(t){this.logger.error("Could not follow a change made in another tab:",t)}}repersistPrivacyDecisions(){this.userOptedOut&&!0!==this.storage.get(qt)&&this.writeOptOut(this.optedOutAt),"denied"===this.trackingConsent&&"denied"!==this.storage.get(Et)&&this.writeDenial(this.consentDeniedAt),this.withdrawalUserId&&this.storage.get(Bt)!==this.withdrawalUserId&&this.storage.set(Bt,this.withdrawalUserId)}storedStamp(t){const i=this.storage.get(t);return"number"==typeof i&&Number.isFinite(i)?i:0}noteDecisionStamps(){for(const t of[Rt,Jt,zt,Ut])this.lastDecisionStamp=Math.max(this.lastDecisionStamp,this.storedStamp(t))}nextDecisionStamp(){return this.noteDecisionStamps(),this.lastDecisionStamp=Math.max(Date.now(),this.lastDecisionStamp+1,this.optedOutAt+1,this.consentDeniedAt+1),this.lastDecisionStamp}storedOptOut(){return!0===this.storage.get(qt)&&!(this.storedStamp(Jt)>this.storedStamp(Rt))}storedDenial(){return"denied"===this.storage.get(Et)&&!(this.storedStamp(Ut)>this.storedStamp(zt))}writeOptOut(t){const i=void 0===t?this.nextDecisionStamp():t;this.optedOutAt=i,this.storage.set(qt,!0),this.storage.set(Rt,i)}writeOptIn(){const t=this.nextDecisionStamp();this.optedOutAt=0,this.storage.remove(qt),this.storage.remove(Rt),this.storage.set(Jt,t)}writeDenial(t){const i=void 0===t?this.nextDecisionStamp():t;this.consentDeniedAt=i,this.storage.set(Et,"denied"),this.storage.set(zt,i)}writeGrant(){const t=this.nextDecisionStamp();this.consentDeniedAt=0,this.storage.remove(Et),this.storage.remove(zt),this.storage.set(Ut,t)}resolveOwner(t){if(t.userId)return t;const i=this.effectiveUserId();return i&&t.anonymousId===this.identity.getAnonymousId()?this.queue.getPendingIdentifies().some(i=>i.anonymousId===t.anonymousId)?t:{anonymousId:t.anonymousId,userId:i}:t}pinAnonymousWrites(){const t=this.identity.getUserId();if(!t)return;const i=this.identity.getAnonymousId();this.identity.pending.pinOwner(i,t),this.persistAttributeWrites(),this.outbox.pinOwner(i,t)}writeRequest(t,i){const e=this.config.apiEndpoint,s=Object.assign(Object.assign({},i.userId?{userId:i.userId}:{}),{anonymousId:i.anonymousId});switch(t.kind){case"alias":return{url:e+"/v1/alias/add",body:Object.assign(Object.assign({},t.payload),s)};case"subscription":return{url:e+"/v1/subscriptions/channel",body:Object.assign(Object.assign({},t.payload),s)};case"group":return{url:e+"/v1/subscriptions/group",body:Object.assign(Object.assign({},t.payload),s)};default:return{url:e+"/v1/attributes",body:Object.assign(Object.assign({},i.userId?{userId:i.userId}:{anonymousId:i.anonymousId}),this.markerOps(t))}}}markerOps(t){const i=t.payload.value;return{attributes:{[ei]:i}}}sendWrite(t,i){const e=this.config.apiEndpoint,s=Object.assign(Object.assign({},i.userId?{userId:i.userId}:{}),{anonymousId:i.anonymousId});switch(t.kind){case"alias":return this.network.sendAddAlias(e,Object.assign(Object.assign({},t.payload),s));case"subscription":return this.network.sendSubscriptionUpdate(e,Object.assign(Object.assign({},t.payload),s));case"group":return this.network.sendSubscriptionGroupUpdate(e,Object.assign(Object.assign({},t.payload),s));default:return this.network.sendSetAttributes(e,this.markerOps(t),i.userId,i.anonymousId)}}onWriteSettled(t,i){if("marker"!==t.record.kind)return;const e=t.record.payload.value;"done"===i?(e?this.storage.set(Ht,!0):this.storage.remove(Ht),this.storage.remove(Wt)):this.storage.set(Wt,e),this.syncOptOutMarker()}syncWorkerReporting(){this.disabled||this.i.setTrackingOptedOut(this.isOptedOut||this.consentPending).catch(()=>{})}initialConsent(t){const i=this.storedDenial();return"granted"===t?(this.storage.remove(Et),this.storage.remove(zt),"granted"):"denied"===t?(this.writeDenial(),"denied"):i?(this.consentDeniedAt=this.storedStamp(zt),"denied"):"pending"===t?"pending":"granted"}storeConsent(t){return"granted"===t?(this.writeGrant(),"granted"):"denied"===t?(this.writeDenial(),"denied"):this.storedDenial()?(this.logger.info("updateConsent('pending') ignored: consent was denied, and only 'granted' lifts that"),"denied"):"pending"}applyPreInitDecision(t){try{switch(t.method){case"optOut":this.userOptedOut=!0,this.writeOptOut();break;case"optIn":this.userOptedOut=!1,this.writeOptIn();break;case"updateConsent":"granted"!==t.consent&&"denied"!==t.consent&&"pending"!==t.consent||(this.trackingConsent=this.storeConsent(t.consent));break;case"wipeData":this.i.forget().catch(()=>{}),this.wipeLocalState(),this.config.userId&&(this.identity.identify(this.config.userId),this.network.setCurrentUserId(this.config.userId)),this.config.enableSdkAuthentication&&this.config.sdkAuthenticationToken&&this.network.setSdkAuthenticationToken(this.config.sdkAuthenticationToken)}}catch(i){this.logger.error(`Applying ${t.method} from before init failed:`,i)}}getTrackingConsent(){return this.trackingConsent}isUserOptedOut(){return this.userOptedOut}syncOptOutMarker(){if(this.disabled||!this.isInitialized)return;const t=this.userOptedOut,i=!0===this.storage.get(Ht),e=this.identity.getAnonymousId(),s=this.outbox.findLast(t=>"marker"===t.record.kind&&t.record.payload.anonymousId===e);if(s){if("marker"===s.record.kind&&s.record.payload.value===t)return;if(t===i&&!this.outbox.isInFlight(s))return void this.outbox.cancel(t=>"marker"===t.record.kind&&t.record.payload.anonymousId===e)}else{if(t===i)return;if(this.storage.get(Wt)===t)return}this.outbox.enqueue({kind:"marker",payload:Object.assign({value:t},this.currentOwner())})}recomputePrivacy(){this.isOptedOut=this.disabled||this.userOptedOut||this.dntEnabled||"denied"===this.trackingConsent,this.consentPending=!this.isOptedOut&&"pending"===this.trackingConsent}canSend(){return this.isInitialized&&!this.isOptedOut&&!this.consentPending&&!this.network.isSuspended()}applyPrivacyState(){const t=this.isOptedOut,i=this.consentPending;if(this.recomputePrivacy(),this.syncWorkerReporting(),t===this.isOptedOut&&i===this.consentPending||this.inapp.invalidate(),this.isOptedOut){const t=this.session.getSessionId(),i=i=>"Session Start"===i.type&&i.sessionId===t;return this.queue.getWaitingEvents().some(i)?this.storage.set(Lt,""):t&&this.queue.getInflightEvents().some(i)&&(this.inflightSessionStartAtClear=t),this.queue.stop(),this.queue.clear(),this.queue.setPaused(!1),this.clearPendingAttributeWrites(),this.outbox.discardNonWithdrawals(),this.outbox.kick(),void(this.config.inApp.enabled&&this.inapp.stop())}if(t&&this.releaseDeferredIdentify(),t&&this.trackSessionStartIfMissing(),this.consentPending)return this.queue.stop(),this.queue.setPaused(!0),void(this.config.inApp.enabled&&this.inapp.stop());this.queue.setPaused(!1),this.queue.isStarted()||this.queue.start(),this.queue.flush().catch(t=>this.logger.error("Flush failed:",t)),this.releaseHeldWrites(),this.config.inApp.enabled&&this.inapp.initialize().catch(t=>{this.logger.error("Failed to initialize in-app messaging:",t)}),this.i.syncExistingSubscription().catch(()=>{})}releaseHeldWrites(){this.identity.pending.isEmpty()||this.scheduleAttributeFlush(0),this.outbox.kick()}runWrite(t,i){this.isInitialized&&!this.disabled?!this.isOptedOut&&0>=this.dataGate.size||ft(i)?(this.withdrawalUserId&&ft(i)&&i.payload.anonymousId===this.identity.getAnonymousId()&&(i=Object.assign(Object.assign({},i),{payload:Object.assign(Object.assign({},i.payload),{userId:this.withdrawalUserId})})),this.outbox.enqueue(i)):this.logger.debug(t+" not sent: tracking is off"):this.logger.error(t+": SDK not initialized")}restoreAttributeWrites(){const t=this.storage.get(si);if(this.isOptedOut)return this.storage.remove(si),void this.outbox.discardNonWithdrawals();t&&"object"==typeof t&&(Array.isArray(t.entries)?this.identity.pending.restore(t.entries):(t.ops&&"object"==typeof t.ops&&this.identity.pending.mark(t.ops),t.increment&&"object"==typeof t.increment&&this.identity.pending.mark({increment:t.increment})))}persistAttributeWrites(){this.identity.pending.isEmpty()?this.storage.remove(si):this.storage.set(si,{entries:this.identity.pending.serialize()})}async flushQueueForWrite(){this.canSend()&&(this.queue.getPendingIdentify()||this.queue.getQueueSize()>0)&&await this.queue.flush().catch(()=>{})}trackSessionStart(){this.logger.debug("Tracking session start");const t={};this.config.trackDeviceProperties&&(Object.assign(t,(()=>{var t,i;if("undefined"==typeof window||"undefined"==typeof navigator)return{};const e=navigator.userAgent||"",s=navigator.language||"",n=Array.isArray(navigator.languages)?navigator.languages:void 0;return{$user_agent:e,$timezone:Intl.DateTimeFormat().resolvedOptions().timeZone,$screen_width:null===(t=window.screen)||void 0===t?void 0:t.width,$screen_height:null===(i=window.screen)||void 0===i?void 0:i.height,$viewport_width:window.innerWidth,$viewport_height:window.innerHeight,$language:s,$languages:n,$platform:navigator.platform,$browser:ht(e)}})()),t.$device_id=this.deviceId),"undefined"!=typeof window&&window.location&&(t.landing_page=window.location.href,t.landing_path=window.location.pathname,t.landing_search=window.location.search,t.landing_title="undefined"!=typeof document?document.title:"",t.landing_referrer="undefined"!=typeof document&&document.referrer||null),this.track("Session Start",t),this.storage.set(Lt,this.session.getSessionId())}trackSessionStartIfMissing(){this.config.trackSessionStart&&!this.isOptedOut&&(this.session.ensureSession(),this.storage.get(Lt)!==this.session.getSessionId()&&this.trackSessionStart())}getOrCreateDeviceId(){const t="device_id",i=this.storage.get(t);if(i)return i;const e=o();return this.storage.set(t,e),e}trackPageView(){if("undefined"==typeof window||!window.location)return;const t=window.location.href;if(this.lastTrackedUrl===t)return;const i={url:t,path:window.location.pathname,search:window.location.search,title:"undefined"!=typeof document?document.title:""};this.config.trackPageProperties&&"undefined"!=typeof document&&(i.referrer=document.referrer||null,i.landing_page=this.utm.getSessionLandingPage()||null),this.lastTrackedUrl=t,this.track("Page Viewed",i)}track(t,i){var e;if(this.isInitialized){if(!this.isDroppingDataCalls("track"))if(this.isOptedOut)this.logger.debug("Tracking disabled, event not tracked:",t);else if("string"!=typeof t||1>t.length||t.length>255)this.logger.error("track() needs an event name of 1-255 characters; event dropped");else try{"Session Start"!==t&&this.session.refreshIfExpired(),this.session.ensureSession(),this.session.updateActivity();const s=i&&"object"==typeof i&&!Array.isArray(i)?Object.assign({},i):{};this.config.captureUTM&&Object.assign(s,this.utm.getUTMProperties()),this.deviceId&&!s.$device_id&&(s.$device_id=this.deviceId);let n={eventId:o(),type:t,properties:s,timestamp:(new Date).toISOString(),userId:this.identity.getUserId(),anonymousId:this.identity.getAnonymousId(),sessionId:this.session.getSessionId()};for(const t of this.config.plugins)if(t.beforeTrack){try{n=t.beforeTrack(n)}catch(i){this.logger.error(`Plugin ${t.name} beforeTrack threw; event kept unchanged:`,i)}if(null===n)return void this.logger.debug("Event blocked by plugin: "+t.name)}n&&n.properties&&"object"==typeof n.properties&&(n=Object.assign(Object.assign({},n),{properties:Nt(n.properties,(i,e)=>this.logger.warn(`Event "${t}": property "${i}" dropped - ${e}`))}));const r=n&&n.properties&&"object"==typeof n.properties?function(t){const i=Object.keys(t).length;if(i>200)return i+" property keys (the limit is 200)";const e=(t,i)=>i>5||null!==t&&"object"==typeof t&&(Array.isArray(t)?t:Object.values(t)).some(t=>null!==t&&"object"==typeof t&&e(t,i+1));if(e(t,1))return"properties nested deeper than 5 levels";let s;try{s=JSON.stringify(t)}catch(t){return"properties that cannot be serialized (a circular reference?)"}return s.length>51200?s.length+" characters of properties (the limit is 51200)":null}(n.properties):null;if(r)return void this.logger.error(`Event "${t}" dropped: ${r}`);if(this.queue.enqueue(n),this.canSend())try{null===(e=this.inapp)||void 0===e||e.onEventTracked(t,s)}catch(t){this.logger.error("In-app trigger evaluation failed:",t)}for(const t of this.config.plugins)if(t.afterTrack)try{t.afterTrack(n)}catch(i){this.logger.error(`Plugin ${t.name} afterTrack threw:`,i)}this.config.sendImmediately&&this.canSend()&&this.flush().catch(t=>this.logger.error("Immediate flush failed:",t))}catch(t){this.logger.error("track() failed:",t)}}else this.logger.error("SDK not initialized")}identify(t){if(!this.isInitialized)return void this.logger.error("SDK not initialized");if("string"!=typeof t||!t.trim()||t.length>255)return void this.logger.error("identify() needs a userId of 1-255 characters");if(this.isOptedOut)return void(this.disabled||this.deferIdentify(t));this.withdrawalUserId&&this.forgetDeferredIdentify();const i=this.identity.getUserId(),e=this.identity.getAnonymousId();this.queue.setPendingIdentify({userId:t,anonymousId:e,attributes:{}});const s=!!i&&i!==t;s&&(this.pinAnonymousWrites(),this.config.inApp.enabled&&this.inapp.clearAll()),this.identity.identify(t),this.network.switchUser(t),i!==t&&this.inapp.invalidate(),this.canSend()&&this.queue.flush(!1,!0).catch(t=>{this.logger.error("Failed to flush with identify:",t)}).then(()=>{i!==t&&this.resyncInApp(s)})}addAlias(t,i){if(!this.isInitialized)return void this.logger.error("SDK not initialized");if(this.isDroppingDataCalls("addAlias"))return;if("string"!=typeof t||!t.trim()||"string"!=typeof i||!i.trim())return void this.logger.error("addAlias(aliasLabel, aliasName) needs two non-empty strings");const e=this.identity.getUserId(),s=Object.assign(Object.assign({anonymousId:this.identity.getAnonymousId()},e?{userId:e}:{}),{aliasLabel:t,aliasName:i});this.runWrite("addAlias",{kind:"alias",payload:s})}setAttributes(t){if(!this.isInitialized)return void this.logger.error("SDK not initialized");if(this.isDroppingDataCalls("setAttributes"))return;if(!t||"object"!=typeof t||Array.isArray(t))return void this.logger.error('setAttributes requires a plain object, e.g. setAttributes({ email: "user@example.com" })');const i={},e=[];for(const[s,n]of Object.entries(t)){if(!s)continue;if(null==n){e.push(s);continue}const t=Ft(n);t?this.logger.warn(`Attribute "${s}" not set: its value is ${t}`):i[s]=n}this.identity.setAttributes(i);for(const t of e)this.identity.unsetAttribute(t);this.isOptedOut||!Object.keys(i).length&&!e.length||this.sendAttributesAfterPendingIdentify(Object.assign(Object.assign({},Object.keys(i).length?{attributes:i}:{}),e.length?{unset:e}:{}))}sendAttributesAfterPendingIdentify(t){this.identity.pending.mark(t,this.currentOwner()),this.persistAttributeWrites(),this.scheduleAttributeFlush(oi.ATTRIBUTE_FLUSH_DEBOUNCE_MS)}scheduleAttributeFlush(t){null===this.attributeFlushTimer&&(this.attributeFlushTimer=setTimeout(()=>{this.attributeFlushTimer=null,this.canSend()&&this.flushAttributeOps()},t))}clearPendingAttributeWrites(){null!==this.attributeFlushTimer&&(clearTimeout(this.attributeFlushTimer),this.attributeFlushTimer=null),this.identity.pending.clear(),this.attributeGeneration++,this.attributeFlushInFlight=!1,this.attributeFlushAgain=!1,this.attributeFailures=0,this.storage.remove(si)}flushAttributeOps(){(this.queue.getPendingIdentify()?this.queue.flush(!1,!0).catch(()=>{}):Promise.resolve()).then(()=>{var t;if(!this.canSend())return;if(this.queue.getPendingIdentify())return void this.scheduleAttributeFlush(this.attributeRetryDelay());if(this.attributeFlushInFlight)return void(this.attributeFlushAgain=!0);const i=this.identity.pending.nextRequest(t=>this.resolveOwner(null!=t?t:this.currentOwner()));if(!i)return;this.attributeFlushInFlight=!0;const e=this.attributeGeneration,{ops:s,entries:n}=i,r=this.resolveOwner(null!==(t=i.owner)&&void 0!==t?t:this.currentOwner());this.network.sendSetAttributes(this.config.apiEndpoint,s,r.userId,r.anonymousId).then(t=>{var i,o;if(e!==this.attributeGeneration)return;const h=bt(t,{isSdkAuthError:this.network.isSdkAuthError(t.status,t.data),ownerIsCurrentUser:(r.userId||null)===this.identity.getUserId()});if("done"===h.action){this.attributeFailures=0,this.identity.pending.acknowledge(n),this.persistAttributeWrites();const t=null===(i=s.attributes)||void 0===i?void 0:i[ri];return"string"==typeof t&&this.storage.set(ni,t),this.identity.pending.hasUnsent()&&(this.attributeFlushAgain=!0),void this.scheduleRetiredTokenPrune()}if("drop"===h.action)return this.logger.error("Attributes dropped: "+h.reason,t.error),this.identity.pending.drop(n),this.persistAttributeWrites(),this.identity.pending.hasUnsent()&&(this.attributeFlushAgain=!0),void this.scheduleRetiredTokenPrune();const a=!(t.softFailure||0!==t.status&&500>t.status),u=this.identity.pending.release(n,a);if(u>0&&this.logger.error(`Failed to send attributes (HTTP ${t.status||"no response"}); ${u} increment(s) are LOST (an $inc cannot be safely retried).`),"hold"===h.action)return this.persistAttributeWrites(),void this.logger.error(`Attributes not sent: ${h.reason}; they are kept for the next page view.`);if(h.counts){const i=n.filter(t=>(t.attempts=(t.attempts||0)+1,t.attempts>=10));i.length&&(this.logger.error(`Attributes failed (HTTP ${t.status}) too many times; dropping them`),this.identity.pending.drop(i))}this.persistAttributeWrites(),this.logger.warn(`Failed to send attributes (HTTP ${t.status||"no response"}); will retry`),this.attributeFailures++,this.scheduleAttributeFlush(Math.max(this.attributeRetryDelay(),Math.min(null!==(o=h.retryAfterMs)&&void 0!==o?o:0,3e5)))}).then(()=>{e===this.attributeGeneration&&(this.attributeFlushInFlight=!1,this.attributeFlushAgain&&(this.attributeFlushAgain=!1,this.flushAttributeOps()))}).catch(t=>{e===this.attributeGeneration&&(this.attributeFlushInFlight=!1),this.logger.error("Attribute flush bookkeeping failed:",t)})})}attributeRetryDelay(){const t=Math.max(1,this.attributeFailures);return Math.min(5e3*Math.pow(2,t-1),3e5)}reportPushPermissionIfChanged(){if(this.isInitialized&&!this.isOptedOut)try{const t=this.i.getPermissionState(),i="notDetermined"===t?"not_determined":t;if(this.storage.get(ni)===i)return;this.logger.debug(`Push permission changed to ${i}; reporting`),this.setAttribute(ri,i)}catch(t){this.logger.warn("Could not report push permission:",t)}}setAttribute(t,i){"string"==typeof t&&t?this.setAttributes({[t]:i}):this.logger.error("setAttribute(key, value) needs a non-empty key")}incrementAttribute(t,i=1){this.isInitialized?this.isDroppingDataCalls("incrementAttribute")||("string"==typeof t&&t&&"number"==typeof i&&Number.isFinite(i)?(this.identity.incrementAttribute(t,i),this.isOptedOut||this.sendAttributesAfterPendingIdentify({increment:{[t]:i}})):this.logger.error("incrementAttribute(key, value) needs a key and a finite number")):this.logger.error("SDK not initialized")}unsetAttribute(t){this.isInitialized?this.isDroppingDataCalls("unsetAttribute")||("string"==typeof t&&t?(this.identity.unsetAttribute(t),this.isOptedOut||this.sendAttributesAfterPendingIdentify({unset:[t]})):this.logger.error("unsetAttribute() needs a non-empty attribute key")):this.logger.error("SDK not initialized")}addToArray(t,i){if(!this.isInitialized)return void this.logger.error("SDK not initialized");if(this.isDroppingDataCalls("addToArray"))return;if("string"!=typeof t||!t)return void this.logger.error("addToArray() needs a non-empty attribute key");const e=Ft(i);e?this.logger.warn(`addToArray("${t}") ignored: the value is ${e}`):(this.identity.addToArray(t,i),this.isOptedOut||this.sendAttributesAfterPendingIdentify({append:{[t]:i}}))}removeFromArray(t,i){if(!this.isInitialized)return void this.logger.error("SDK not initialized");if(this.isDroppingDataCalls("removeFromArray"))return;if("string"!=typeof t||!t)return void this.logger.error("removeFromArray() needs a non-empty attribute key");const e=Ft(i);e?this.logger.warn(`removeFromArray("${t}") ignored: the value is ${e}`):(this.identity.removeFromArray(t,i),this.isOptedOut||this.sendAttributesAfterPendingIdentify({remove:{[t]:i}}))}async reset(){this.isInitialized?(this.logger.info("Resetting user identity"),this.config.inApp.enabled&&this.inapp.clearAll(),this.network.retireSdkAuthToken(),this.forgetDeferredIdentify(),this.pinAnonymousWrites(),this.identity.reset(),this.network.setCurrentUserId(this.identity.getUserId()),this.utm.reset(),this.session.resetSession(),await this.flush().catch(()=>{}),this.canSend()&&(this.resyncInApp(!0),this.i.syncExistingSubscription(!0).catch(()=>{})),this.outbox.kick(),this.logger.info("User identity reset")):this.logger.error("SDK not initialized")}async wipeData(){if(!this.isInitialized)return void this.logger.error("SDK not initialized");this.logger.info("Wiping local SDK data");const t=this.i.forget().catch(()=>{});this.wipeLocalState(),this.session.ensureSession(),this.trackSessionStartIfMissing(),await t,this.canSend()&&this.resyncInApp(!0),this.logger.info("Local SDK data wiped")}wipeLocalState(){this.clearPendingAttributeWrites(),this.outbox.discardNonWithdrawals(),this.storage.remove(ni),this.storage.set(Lt,""),this.queue.clear(),this.config.inApp.enabled?this.inapp.clearAll():this.inapp.invalidate(),this.inapp.forgetImpressions();const t=new Set;for(const i of[this.effectiveUserId(),this.identity.getUserId(),this.network.getCurrentUserId()])i&&t.add(i);for(const i of this.outbox.records()){const e=i.payload.userId;"string"==typeof e&&e&&t.add(e)}for(const i of this.i.pendingUnregisterUsers())t.add(i);for(const i of[Ot,St])Gt(this.storage.get(i),t);this.network.retireSdkAuthToken(),this.network.dropStandbySdkAuthTokens(t),this.forgetDeferredIdentify(),this.pinAnonymousWrites(),this.identity.reset(),this.network.setCurrentUserId(null),this.utm.reset(),this.session.clear(),this.lastTrackedUrl=null,this.storage.remove("device_id"),this.deviceId=this.getOrCreateDeviceId()}resyncInApp(t=!1){this.config.inApp.enabled&&this.canSend()&&(t?this.inapp.initialize():this.inapp.sync().then(()=>{})).catch(t=>this.logger.debug("In-app re-sync failed:",t))}async flush(){this.isInitialized?await this.queue.flush(!1,!0):this.logger.error("SDK not initialized")}async flushEvents(t,i){var e,s,n,r;if(!this.canSend())return{status:"retry"};this.logger.debug(`Sending ${t.length} events${i?" + identify":""} to backend`);const o=await this.network.sendEvents(this.config.apiEndpoint,t,i);if(o.ok||o.softFailure){const h=Array.isArray(null===(e=o.data)||void 0===e?void 0:e.rejectedIndices)?o.data.rejectedIndices:void 0;let a=!1,u=!1,d=!0;if(i&&!(null===(s=o.data)||void 0===s?void 0:s.identified)&&o.softFailure)a=!0;else if(i&&!(null===(n=o.data)||void 0===n?void 0:n.identified)){this.logger.debug("Backend did not confirm atomic identify, falling back to standalone");const t=await this.network.sendIdentify(this.config.apiEndpoint,i.userId,i.attributes||{},i.anonymousId);if(!t.ok){const e=!(t.softFailure||0!==t.status&&408!==t.status&&429!==t.status&&500>t.status);!0===t.softFailure||e||401===t.status&&this.network.isSdkAuthError(t.status,t.data)&&i.userId===this.identity.getUserId()||402===t.status?(this.logger.error("Standalone identify fallback failed; it is kept and retried:",t.error),a=!0,d=!e&&402!==t.status):(this.logger.error(`Standalone identify fallback refused (HTTP ${t.status}); dropping it:`,t.error),u=!0)}}return o.softFailure?{status:"ok",failedIndices:Array.isArray(null===(r=o.data)||void 0===r?void 0:r.failedIndices)?o.data.failedIndices:t.map((t,i)=>i),rejectedIndices:h,identifyFailed:a,identifyAttemptCounts:d,identifyDropped:u}:(this.logger.debug("Events sent successfully"),{status:"ok",rejectedIndices:h,identifyFailed:a,identifyAttemptCounts:d,identifyDropped:u})}return this.classifyFailure(o,t,i)}classifyFailure(t,i=[],e){var s,n;const r=t.status;if(400===r||413===r||422===r)return{status:"rejected",httpStatus:r};if(401===r){if(this.network.isSdkAuthError(r,t.data)){const r=null===(s=t.data)||void 0===s?void 0:s.reason,o=(null==e?void 0:e.userId)||(null===(n=i.find(t=>t.userId))||void 0===n?void 0:n.userId)||null;return o&&o!==this.identity.getUserId()?{status:"dropped",reason:"401 "+(r||"sdk_authentication_error")}:{status:"retry",counts:!0}}return{status:"suspended",reason:"the SDK key was refused (401)"}}return 402===r?{status:"suspended",reason:"event ingestion is paused for this workspace (402)"}:403===r?{status:"suspended",reason:"the request was forbidden (403)"}:0!==r&&408!==r&&429!==r&&500>r?{status:"suspended",reason:"the API answered HTTP "+r}:{status:"retry",retryAfterMs:t.retryAfterMs}}handlePageUnload(){if(this.isInitialized)if("undefined"==typeof navigator||!1!==navigator.onLine){try{this.outbox.handOffAtUnload(8192)}catch(t){this.logger.error("Page-unload write hand-off failed:",t)}if(!this.canSend()||this.queue.isSuspended()||this.queue.isBackingOff())this.queue.persistNow();else try{this.sendAttributesAtUnload();const t=Math.max(0,this.network.keepaliveBudget()-256),i=this.queue.getQueuedEvents(),e=this.queue.getPendingIdentify();if(0===i.length&&!e)return;if(!this.network.supportsKeepalive())return void this.queue.persistNow();const s=i[0],n=!e||s&&(s.anonymousId!==e.anonymousId||s.userId&&s.userId!==e.userId)?null:e;let r=64+(n?I(JSON.stringify(n)):0);const o=[];let h=null;for(const e of i){if(s&&e.anonymousId!==s.anonymousId)break;if(e.userId&&h&&e.userId!==h)break;if(n&&(e.anonymousId!==n.anonymousId||e.userId&&e.userId!==n.userId))break;const i=I(JSON.stringify(e))+1;if(r+i>t)break;o.push(e),e.userId&&(h=e.userId),r+=i}if(0===o.length&&!n)return void this.queue.persistNow();this.logger.debug(`Page unload: handing ${o.length} of ${i.length} events${n?" + identify":""} to keepalive`);const a=this.network.sendEventsKeepalive(this.config.apiEndpoint,o,n||void 0);if(!a)return void this.queue.persistNow();this.queue.markHandedOff(o,n),a.then(t=>{t.ok||!t.softFailure&&0!==t.status&&429!==t.status&&500>t.status||this.queue.takeBack(o,n)}).catch(()=>{})}catch(t){this.logger.error("Page-unload send failed:",t),this.queue.persistNow()}}else this.queue.persistNow()}sendAttributesAtUnload(){var t;if(this.queue.getPendingIdentify())return 0;const i=this.identity.pending.peekRequest(t=>this.resolveOwner(null!=t?t:this.currentOwner()));if(!i||!this.network.supportsKeepalive())return 0;try{const e=this.resolveOwner(null!==(t=i.owner)&&void 0!==t?t:this.currentOwner()),s=Object.assign({userId:e.userId||void 0,anonymousId:e.userId?void 0:e.anonymousId},i.ops),n=this.network.postKeepalive(this.config.apiEndpoint+"/v1/attributes",s);return n?(n.catch(()=>{}),this.identity.pending.dropIncrements(i.entries),this.persistAttributeWrites(),I(JSON.stringify(s))+256):0}catch(t){return 0}}optOut(){this.isInitialized?(this.logger.info("User opted out of tracking"),this.userOptedOut=!0,this.writeOptOut(),this.storage.remove(Wt),this.syncOptOutMarker(),this.applyPrivacyState()):this.logger.error("SDK not initialized")}optIn(){this.isInitialized?(this.logger.info("User opted in to tracking"),this.userOptedOut=!1,this.liftDataGate("optedOut"),this.writeOptIn(),this.applyPrivacyState(),this.storage.remove(Wt),this.syncOptOutMarker()):this.logger.error("SDK not initialized")}updateConsent(t){this.isInitialized?"granted"===t||"denied"===t||"pending"===t?(this.trackingConsent=this.storeConsent(t),this.config.trackingConsent=this.trackingConsent,"granted"===t&&this.liftDataGate("denied"),this.applyPrivacyState(),this.syncOptOutMarker()):this.logger.error("updateConsent expects 'granted', 'denied' or 'pending', got "+t):this.logger.error("SDK not initialized")}isDoNotTrackEnabled(){if("undefined"==typeof window||"undefined"==typeof navigator)return!1;const t=navigator.doNotTrack||window.doNotTrack||navigator.msDoNotTrack;return"1"===t||"yes"===t}async loadPlugins(){for(const t of this.config.plugins)try{this.logger.debug(`Loading plugin: ${t.name} v${t.version}`),await t.load(this),this.logger.info("Plugin loaded: "+t.name)}catch(i){this.logger.error(`Failed to load plugin ${t.name}:`,i)}}async unloadPlugins(){for(const t of this.config.plugins)try{this.logger.debug("Unloading plugin: "+t.name),await t.unload()}catch(i){this.logger.error(`Failed to unload plugin ${t.name}:`,i)}}get user(){var t;return this.isInitialized||null===(t=this.logger)||void 0===t||t.error("SDK not initialized"),this.o}get push(){var t;return this.isInitialized||null===(t=this.logger)||void 0===t||t.error("SDK not initialized"),this.i}ecommerce(t){var i;return this.isInitialized||null===(i=this.logger)||void 0===i||i.error("SDK not initialized"),this.t&&!t||(this.t=ct(this,t,this.logger)),this.t}setSdkAuthenticationToken(t){var i;this.isInitialized?this.config.enableSdkAuthentication?this.network.setSdkAuthenticationToken(t):this.logger.warn("setSdkAuthenticationToken called but enableSdkAuthentication is false - ignoring"):null===(i=this.logger)||void 0===i||i.error("SDK not initialized")}setSdkAuthenticationErrorCallback(t){var i;this.isInitialized?this.network.setSdkAuthenticationFailureCallback(t):null===(i=this.logger)||void 0===i||i.error("SDK not initialized")}getAnonymousId(){return this.identity?this.identity.getAnonymousId():""}getUserId(){return this.identity?this.identity.getUserId():null}liftDataGate(t){if(!this.dataGate.has(t))return;const i=new Set(this.dataGate);i.delete(t),this.dataGate=i}isDroppingDataCalls(t){return 0!==this.dataGate.size&&(this.logger.debug(t+"() in a ready() callback queued while tracking was off: dropped"),!0)}ready(t){if("function"==typeof t)try{t(this)}catch(t){this.logger.error("Error in ready() callback:",t)}else this.logger.error("ready(callback) requires a function")}getIdentity(){return this.identity.getIdentity()}getSessionInfo(){return this.session.getSessionInfo()}getUTMData(){return this.utm.getUTMData()}updateUTM(){this.isInitialized?(this.utm.updateUTM(),this.config.resetSessionOnNewCampaign&&this.utm.hasNewCampaign()&&(this.logger.info("New campaign detected, resetting session"),this.session.resetSession())):this.logger.error("SDK not initialized")}async syncInAppCampaigns(t){if(this.isInitialized)if(this.config.inApp.enabled)if(this.canSend())try{await this.inapp.sync(t)}catch(t){this.logger.error("In-app sync failed:",t)}else this.logger.debug("Tracking disabled or consent pending, not syncing in-app campaigns");else this.logger.warn("In-app messaging is not enabled");else this.logger.error("SDK not initialized")}getInAppCampaigns(){return this.isInitialized?this.config.inApp.enabled?this.inapp.getCampaigns():[]:(this.logger.error("SDK not initialized"),[])}async displayInAppCampaign(t){if(!this.isInitialized)return void this.logger.error("SDK not initialized");if(!this.config.inApp.enabled)return void this.logger.warn("In-app messaging is not enabled");if(!this.canSend())return void this.logger.debug("Tracking disabled or consent pending, not displaying in-app campaign");const i=this.inapp.getCampaigns().find(i=>i.id===t);if(i)try{await this.inapp.displayCampaign(i)}catch(t){this.logger.error("In-app display failed:",t)}else this.logger.error(`Campaign ${t} not found`)}dismissInAppMessage(t){this.isInitialized?this.config.inApp.enabled&&this.inapp.dismiss(t).catch(t=>this.logger.error("In-app dismiss failed:",t)):this.logger.error("SDK not initialized")}async trackInAppConversion(t,i){if(this.isInitialized){if(!this.isDroppingDataCalls("trackInAppConversion"))if(this.config.inApp.enabled)if(this.canSend())try{await this.inapp.trackConversion(t,i)}catch(t){this.logger.error("In-app conversion failed:",t)}else this.logger.debug("Tracking disabled or consent pending, not tracking in-app conversion");else this.logger.warn("In-app messaging is not enabled")}else this.logger.error("SDK not initialized")}async destroy(){this.isInitialized&&(this.logger.info("Destroying SDK instance"),null!==this.attributeFlushTimer&&(clearTimeout(this.attributeFlushTimer),this.attributeFlushTimer=null,this.canSend()&&this.flushAttributeOps()),this.outbox.destroy(),this.i.destroy(),"undefined"!=typeof window&&"function"==typeof window.removeEventListener&&(this.boundHandlePageUnload&&(window.removeEventListener("pagehide",this.boundHandlePageUnload),window.removeEventListener("beforeunload",this.boundHandlePageUnload)),this.boundHandleOnline&&window.removeEventListener("online",this.boundHandleOnline),this.boundHandleStorage&&window.removeEventListener("storage",this.boundHandleStorage)),this.boundHandlePageUnload=null,this.boundHandleOnline=null,this.boundHandleStorage=null,null!==this.pruneTimer&&(clearTimeout(this.pruneTimer),this.pruneTimer=null),await this.queue.flush().catch(()=>{}),this.queue.stop(),await this.unloadPlugins(),this.session.destroy(),this.inapp.clearAll(),this.inapp.destroy(),this.isInitialized=!1,oi.instance===this&&(oi.instance=null),this.logger.info("SDK destroyed"))}static getInstance(){return oi.instance}}oi.instance=null,oi.ATTRIBUTE_FLUSH_DEBOUNCE_MS=800;const hi=["init","optOut","optIn","updateConsent","wipeData"],ai=["track","setAttributes","setAttribute","incrementAttribute","unsetAttribute","addToArray","removeFromArray","addAlias","trackInAppConversion"];function ui(t){var i,e;try{const s=t&&t.joryio;if(!Array.isArray(s))return;const n=s.find(t=>Array.isArray(t)&&"init"===t[0]);if(!n){if(s.__joryioWaitingForInit)return;return s.__joryioWaitingForInit=!0,void(s.push=function(...i){for(let t=s.length+i.length-1e3;t>0;t--){const t=s.findIndex(t=>!(Array.isArray(t)&&hi.includes(t[0])));if(0>t)break;s.splice(t,1)}const e=Array.prototype.push.apply(s,i);return i.some(t=>Array.isArray(t)&&"init"===t[0])&&ui(t),e})}const r=s.slice(),o=r.indexOf(n),h=[],a=new Set;r.forEach((t,i)=>{if(!Array.isArray(t))return;const[e,s]=t;if("optOut"===e||"optIn"===e)h.push({method:e});else if("updateConsent"===e)h.push({method:e,consent:s});else{if("wipeData"!==e||i>=o)return;h.push({method:e})}a.add(t)});let u=null;try{u=new oi(n[1],h)}catch(t){console.error("[Joryio] init failed:",t)}if(!u||oi.getInstance()!==u){const i=s.indexOf(n);return 0>i||s.splice(i,1),s.__joryioWaitingForInit=!1,void ui(t)}const d=new Map,l=function(t,i,e=t.length,s=new Map){const n=new Set,r=(t,i)=>{n.add(t);const e=s.get(t)||new Set;e.add(i),s.set(t,e)};let o=!!(null==i?void 0:i.optedOut),h=(null==i?void 0:i.consent)||"granted";const a=[],u=(t=!1)=>{const i=a.filter(i=>t&&"ready"===i[0]);a.forEach(t=>{i.includes(t)||r(t,"purged")}),a.length=0,a.push(...i)};return t.forEach((t,i)=>{if(!Array.isArray(t))return;const[s,n]=t;"optOut"===s?(o=!0,u()):"optIn"===s?o=!1:"updateConsent"===s?("granted"===n||"denied"===n?h=n:"pending"===n&&"denied"!==h&&(h="pending"),"denied"===n&&u()):"wipeData"===s&&e>i?u(!0):(ai.includes(s)||"ready"===s)&&(o&&r(t,"optedOut"),"denied"===h&&r(t,"denied"),o||"denied"===h||a.push(t))}),n}(r,Xt.get(u),o,d);t.joryio=u;for(const t of r){if(!Array.isArray(t)||a.has(t))continue;const[s,...n]=t;if("init"===s)continue;const r=l.has(t);if(r&&"ready"!==s){null===(e=null===(i=u.logger)||void 0===i?void 0:i.debug)||void 0===e||e.call(i,s+" queued before load dropped: tracking was off when it was called");continue}const o=u[s];if("function"==typeof o)try{let i;r?Yt(u,d.get(t)||[],()=>i=o.apply(u,n)):i=o.apply(u,n),i&&"function"==typeof i.catch&&i.catch(t=>{console.error(`[Joryio] Error executing ${s+""}:`,t)})}catch(t){console.error(`[Joryio] Error executing ${s+""}:`,t)}else console.warn("[Joryio] Unknown method queued before load: "+s)}}catch(t){console.error("[Joryio] Could not process the snippet queue:",t)}}"undefined"!=typeof window&&(window.Joryio=oi,ui(window)),t.EcommerceTracker=lt,t.JoryioSDK=oi,t.PushManager=At,t.SDK_VERSION=i,t.User=nt,t.createEcommerceTracker=ct,t.default=oi,t.installSnippetQueue=ui,Object.defineProperty(t,"__esModule",{value:!0})});
|
|
6
|
+
!function(t,i){"object"==typeof exports&&"undefined"!=typeof module?i(exports):"function"==typeof define&&define.amd?define(["exports"],i):i((t="undefined"!=typeof globalThis?globalThis:t||self).JoryioSDK={})}(this,function(t){"use strict";const i="1.3.1";function e(t){const i=(t||"").trim();if(!i)return"https://api-eu1.joryio.com/api";const e=(/^https?:\/\//i.test(i)?i:"https://"+i).replace(/\/+$/,"");try{const t=new URL(e);if(""===t.pathname||"/"===t.pathname)return e+"/api"}catch(t){}return e}const s={allowHtmlJsInAppMessages:"inApp",evaluationMode:"inApp",syncInterval:"inApp",displayOptions:"inApp"};const n=16777619;class r{static hashKey(t){return function(t){let i=2166136261;for(let e=0;e<t.length;e++){const s=t.charCodeAt(e);i^=255&s,i=Math.imul(i,n),i^=s>>>8&255,i=Math.imul(i,n)}return e=i>>>0,e=Math.imul(e^=e>>>16,2246822507),e=Math.imul(e^=e>>>13,3266489909),(e^=e>>>16)>>>0;var e}(t).toString(36)}constructor(t,i){this.memoryStore=new Map,this.prefix=`jry_${r.hashKey(t)}_`,this.logger=i,this.isLocalStorageAvailable=this.checkLocalStorageAvailable(),this.isLocalStorageAvailable||this.logger.warn("LocalStorage not available, using in-memory storage")}checkLocalStorageAvailable(){try{const t="__jry_test__";return localStorage.setItem(t,"test"),localStorage.removeItem(t),!0}catch(t){return!1}}getKey(t){return`${this.prefix}${t}`}storageKeyFor(t){return this.getKey(t)}set(t,i,e){const s={value:i,expiresAt:e?Date.now()+864e5*e:null};if(this.isLocalStorageAvailable)try{localStorage.setItem(this.getKey(t),JSON.stringify(s)),this.memoryStore.delete(t)}catch(i){this.logger.error("Failed to write to localStorage:",i);try{localStorage.removeItem(this.getKey(t))}catch(t){}this.memoryStore.set(t,s)}else this.memoryStore.set(t,s)}get(t){var i;let e=null;if(this.isLocalStorageAvailable)try{const i=localStorage.getItem(this.getKey(t));i&&(e=JSON.parse(i))}catch(i){this.logger.error("Failed to read from localStorage:",i);try{localStorage.removeItem(this.getKey(t))}catch(t){}}return e||(e=this.memoryStore.get(t)||null),e&&e.expiresAt&&e.expiresAt<Date.now()?(this.remove(t),null):null!==(i=null==e?void 0:e.value)&&void 0!==i?i:null}remove(t){if(this.isLocalStorageAvailable)try{localStorage.removeItem(this.getKey(t))}catch(t){this.logger.error("Failed to remove from localStorage:",t)}this.memoryStore.delete(t)}clear(){if(this.isLocalStorageAvailable)try{const t=[];for(let i=0;i<localStorage.length;i++){const e=localStorage.key(i);e&&e.startsWith(this.prefix)&&t.push(e)}t.forEach(t=>localStorage.removeItem(t))}catch(t){this.logger.error("Failed to clear localStorage:",t)}this.memoryStore.clear()}}function o(){return"undefined"!=typeof crypto&&crypto.randomUUID?crypto.randomUUID():"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g,t=>{const i=16*Math.random()|0;return("x"===t?i:3&i|8).toString(16)})}function h(){if("undefined"!=typeof crypto&&crypto.getRandomValues){const t=new Uint8Array(6);return crypto.getRandomValues(t),Date.now().toString(36)+Array.from(t,t=>t.toString(16).padStart(2,"0")).join("")}return Date.now().toString(36)+Math.random().toString(36).substr(2,9)}const a="session_id",u="session_start",d="last_activity",l=864e5;class c{constructor(t,i,e){this.currentSessionId=null,this.lastActivityAt=0,this.lastActivityPersistedAt=0,this.isNewSession=!1,this.onNewSessionCallback=null,this.boundVisibilityHandler=null,this.storage=t,this.logger=i,this.sessionTimeoutMs=e||18e5,this.initializeSession(),"undefined"!=typeof document&&(this.boundVisibilityHandler=()=>{"visible"===document.visibilityState&&this.checkAndRefreshSession()},document.addEventListener("visibilitychange",this.boundVisibilityHandler))}onNewSession(t){this.onNewSessionCallback=t}initializeSession(){const t=this.storage.get(a),i=this.storage.get(d),e=this.storage.get(u);if(t&&i){const s=Date.now(),n=s-i,r=e?s-e:1/0;if(n<this.sessionTimeoutMs&&l>r)return this.currentSessionId=t,this.isNewSession=!1,this.updateActivity(),void this.logger.debug("Resumed session: "+this.currentSessionId);l>r?this.logger.debug(`Session expired (${n}ms since last activity)`):this.logger.debug(`Session too old (${Math.round(r/1e3/60/60)}h), creating new session`)}this.startNewSession()}startNewSession(){const t=this.currentSessionId;this.currentSessionId=h(),this.isNewSession=!0;const i=Date.now();this.storage.set(a,this.currentSessionId),this.storage.set(u,i),this.storage.set(d,i),this.lastActivityAt=i,this.lastActivityPersistedAt=i,this.logger.debug("Started new session: "+this.currentSessionId),t&&this.onNewSessionCallback&&this.onNewSessionCallback()}checkAndRefreshSession(){const t=this.storage.get(d),i=this.storage.get(u);if(t&&i){const e=Date.now(),s=e-t,n=e-i;s<this.sessionTimeoutMs?l>n||(this.logger.debug(`Session too old on tab focus (${Math.round(n/1e3/60/60)}h old)`),this.startNewSession()):(this.logger.debug(`Session expired on tab focus (${Math.round(s/1e3/60)} min inactive)`),this.startNewSession())}}refreshIfExpired(){if(!this.currentSessionId)return!1;const t=Date.now(),i=Math.max(this.lastActivityAt,this.storage.get(d)||0)||t,e=this.storage.get(u)||t;return t-i<this.sessionTimeoutMs?t-e>=l&&(this.logger.debug("Session reached its maximum age"),this.startNewSession(),!0):(this.logger.debug(`Session expired (${Math.round((t-i)/1e3/60)} min inactive)`),this.startNewSession(),!0)}updateActivity(){if(!this.currentSessionId)return;const t=Date.now();this.lastActivityAt=t,3e4>t-this.lastActivityPersistedAt||(this.lastActivityPersistedAt=t,this.storage.set(d,t))}getSessionInfo(){return{sessionId:this.currentSessionId||this.storage.get(a)||"",sessionStart:this.storage.get(u)||Date.now(),lastActivity:this.lastActivityAt||this.storage.get(d)||Date.now(),isNewSession:this.isNewSession}}getSessionId(){return this.currentSessionId||this.storage.get(a)||""}ensureSession(){if(this.currentSessionId)return this.currentSessionId;const t=this.storage.get(a);if(t)return this.currentSessionId=t,t;this.currentSessionId=h(),this.isNewSession=!0;const i=Date.now();return this.storage.set(a,this.currentSessionId),this.storage.set(u,i),this.storage.set(d,i),this.lastActivityAt=i,this.lastActivityPersistedAt=i,this.logger.debug("Started new session: "+this.currentSessionId),this.onNewSessionCallback&&this.onNewSessionCallback(),this.currentSessionId}followStoredSession(){const t=this.storage.get(a);return t!==this.currentSessionId&&(this.currentSessionId=t||null,this.isNewSession=!1,this.lastActivityAt=t?this.storage.get(d)||Date.now():0,this.lastActivityPersistedAt=this.lastActivityAt,this.logger.debug("Following the session another tab started: "+(t||"(none)")),!0)}renewSession(){this.updateActivity(),this.logger.debug("Session renewed: "+this.currentSessionId)}resetSession(){this.logger.debug(`Resetting session (was: ${this.currentSessionId})`),this.startNewSession()}clear(){this.currentSessionId=null,this.isNewSession=!1,this.lastActivityAt=0,this.lastActivityPersistedAt=0,this.storage.remove(a),this.storage.remove(u),this.storage.remove(d)}destroy(){this.boundVisibilityHandler&&"undefined"!=typeof document&&(document.removeEventListener("visibilitychange",this.boundVisibilityHandler),this.boundVisibilityHandler=null)}}function p(t,i){return t&&i?t.anonymousId===i.anonymousId&&(t.userId||null)===(i.userId||null):!t&&!i}class f{constructor(t=500){this.maxEntries=t,this.entries=[]}add(t,i,e,s){if(!i)return;const n=s?Object.assign({},s):void 0;if("set"===t||"unset"===t)return this.entries=this.entries.filter(t=>t.key!==i||t.inFlight||!p(t.owner,n)),this.entries.push("set"===t?{key:i,kind:t,value:e,owner:n}:{key:i,kind:t,owner:n}),void this.trim();const r=this.lastFor(i);if(r&&!r.inFlight&&r.kind===t&&p(r.owner,n))if("increment"===t)r.value=(+r.value||0)+ +e;else for(const t of y(e))m(r.values,t)||r.values.push(t);else"increment"===t?this.entries.push({key:i,kind:t,value:+e,owner:n}):this.entries.push({key:i,kind:t,values:v(y(e)),owner:n}),this.trim()}mark(t,i){for(const[e,s]of Object.entries(t.attributes||{}))this.add("set",e,s,i);for(const e of t.unset||[])this.add("unset",e,void 0,i);for(const[e,s]of Object.entries(t.increment||{}))"number"==typeof s&&Number.isFinite(s)&&this.add("increment",e,s,i);for(const[e,s]of Object.entries(t.append||{}))this.add("append",e,s,i);for(const[e,s]of Object.entries(t.remove||{}))this.add("remove",e,s,i)}isEmpty(){return 0===this.entries.length}hasUnsent(){return this.entries.some(t=>!t.inFlight)}nextRequest(t){return this.build(!0,t)}peekRequest(t){return this.build(!1,t)}toOps(){var t,i;return null!==(i=null===(t=this.peekRequest())||void 0===t?void 0:t.ops)&&void 0!==i?i:null}acknowledge(t){const i=new Set(t);this.entries=this.entries.filter(t=>!i.has(t))}release(t,i){let e=0;const s=new Set(t);return this.entries=this.entries.filter(t=>!s.has(t)||(t.inFlight=!1,!i||"increment"!==t.kind||(e++,!1))),e}drop(t){this.acknowledge(t)}dropIncrements(t){const i=new Set(t.filter(t=>"increment"===t.kind));this.entries=this.entries.filter(t=>!i.has(t))}pending(t){const i={};for(const e of this.entries)t&&e.owner&&e.owner.anonymousId!==t||("set"===e.kind?i[e.key]=e.value:"unset"===e.kind&&delete i[e.key]);return i}serialize(){return this.entries.map(t=>{const i={key:t.key,kind:t.kind};return"set"!==t.kind&&"increment"!==t.kind||(i.value=t.value),t.values&&(i.values=[...t.values]),t.owner&&(i.owner=Object.assign({},t.owner)),t.attempts&&(i.attempts=t.attempts),i})}restore(t){if(Array.isArray(t))for(const i of t){if(!i||"object"!=typeof i||"string"!=typeof i.key)continue;const t=i.kind,e=i.owner&&"object"==typeof i.owner&&"string"==typeof i.owner.anonymousId?Object.assign({anonymousId:i.owner.anonymousId},"string"==typeof i.owner.userId?{userId:i.owner.userId}:{}):void 0,s=this.entries.length;"set"===t?this.add("set",i.key,i.value,e):"unset"===t?this.add("unset",i.key,void 0,e):"increment"===t&&"number"==typeof i.value&&Number.isFinite(i.value)?this.add("increment",i.key,i.value,e):"append"!==t&&"remove"!==t||!Array.isArray(i.values)||this.add(t,i.key,i.values,e);const n=this.entries.length>s?this.entries[this.entries.length-1]:void 0;n&&Number.isInteger(i.attempts)&&i.attempts>0&&(n.attempts=i.attempts)}}pinOwner(t,i){for(const e of this.entries)e.owner&&(e.owner.anonymousId!==t||e.owner.userId)||(e.owner={anonymousId:t,userId:i})}clear(){this.entries=[]}build(t,i=t=>t){var e,s,n,r,o;const h=new Set(this.entries.filter(t=>t.inFlight).map(t=>t.key)),a=new Set,u={},d=[];let l,c=!1;for(const t of this.entries){if(t.inFlight||h.has(t.key)||a.has(t.key)){a.add(t.key);continue}const f=i(t.owner);if(!c||p(f,l))switch(c||(c=!0,l=f),a.add(t.key),d.push(t),t.kind){case"set":(null!==(e=u.attributes)&&void 0!==e?e:u.attributes={})[t.key]=t.value;break;case"unset":(null!==(s=u.unset)&&void 0!==s?s:u.unset=[]).push(t.key);break;case"increment":(null!==(n=u.increment)&&void 0!==n?n:u.increment={})[t.key]=t.value;break;case"append":(null!==(r=u.append)&&void 0!==r?r:u.append={})[t.key]=[...t.values];break;case"remove":(null!==(o=u.remove)&&void 0!==o?o:u.remove={})[t.key]=[...t.values]}else a.add(t.key)}if(!d.length)return null;if(t)for(const t of d)t.inFlight=!0;return Object.assign({ops:u,entries:d},l?{owner:Object.assign({},l)}:{})}lastFor(t){for(let i=this.entries.length-1;i>=0;i--)if(this.entries[i].key===t)return this.entries[i]}trim(){for(;this.entries.length>this.maxEntries;){const t=this.entries.findIndex(t=>!t.inFlight);if(0>t)break;this.entries.splice(t,1)}}}function y(t){return Array.isArray(t)?[...t]:[t]}function m(t,i){if(null!==i&&"object"==typeof i){const e=b(i);return t.some(t=>null!==t&&"object"==typeof t&&b(t)===e)}return t.some(t=>Object.is(t,i))}function v(t){const i=[];for(const e of t)m(i,e)||i.push(e);return i}function b(t){try{return JSON.stringify(t)}catch(i){return t+""}}const g="user_id",w="anonymous_id",k="user_attributes";class S{constructor(t,i,e,s){this.pending=new f,this.userId=null,this.attributes={},this.storage=t,this.logger=i,this.anonymousId=s||this.storage.get(w)||o(),this.storage.get(w)||(this.storage.set(w,this.anonymousId),this.logger.debug("Generated new anonymous ID: "+this.anonymousId)),this.userId=e||this.storage.get(g)||null,this.userId&&this.logger.debug("Loaded user ID: "+this.userId),this.attributes={},this.storage.remove(k)}identify(t,i){const e=this.userId;this.userId=t,this.storage.set(g,t),i&&this.setAttributes(i),e!==t&&this.logger.info(`User identified: ${t} (was: ${e||"anonymous"})`)}reset(){this.logger.debug(`Resetting identity (was: ${this.userId||"anonymous"})`),this.userId=null,this.attributes={},this.anonymousId=o(),this.storage.remove(g),this.storage.remove(k),this.storage.set(w,this.anonymousId),this.logger.debug("New anonymous ID: "+this.anonymousId)}adopt(t,i){t!==this.anonymousId&&(this.attributes={}),this.anonymousId=t,this.userId=i}setAttributes(t){t&&"object"==typeof t&&!Array.isArray(t)?(this.attributes=Object.assign(Object.assign({},this.attributes),t),this.logger.debug("Updated user attributes:",this.attributes)):this.logger.error("setAttributes requires a plain object")}setAttribute(t,i){this.attributes[t]=i,this.logger.debug(`Set attribute: ${t} = ${i}`)}incrementAttribute(t,i=1){const e=this.attributes[t],s="number"==typeof e?e:0;this.setAttribute(t,s+i),this.logger.debug(`Incremented attribute: ${t} by ${i} (now: ${this.attributes[t]})`)}unsetAttribute(t){delete this.attributes[t],this.logger.debug("Unset attribute: "+t)}addToArray(t,i){const e=this.attributes[t];let s=[];Array.isArray(e)?s=[...e]:null!=e&&(this.logger.warn(`Attribute ${t} is not an array, converting to array`),s=[e]),s.includes(i)?this.logger.debug(`Value already exists in array: ${t} = ${i}`):(s.push(i),this.setAttribute(t,s),this.logger.debug(`Added to array: ${t} = ${i}`))}removeFromArray(t,i){const e=this.attributes[t];if(!Array.isArray(e))return void this.logger.warn(`Attribute ${t} is not an array, cannot remove value`);const s=e.filter(t=>t!==i);s.length!==e.length?(this.setAttribute(t,s),this.logger.debug(`Removed from array: ${t} = ${i}`)):this.logger.debug(`Value not found in array: ${t} = ${i}`)}getIdentity(){return{userId:this.userId,anonymousId:this.anonymousId,attributes:Object.assign({},this.attributes)}}getUserId(){return this.userId}getAnonymousId(){return this.anonymousId}getAttributes(){return Object.assign({},this.attributes)}getAttribute(t){return this.attributes[t]}isIdentified(){return null!==this.userId}}function j(t){return!!t&&"object"==typeof t&&!Array.isArray(t)&&!1===t.success}function A(t){return{userId:t.userId,anonymousId:t.anonymousId,attributes:t.attributes||{}}}function I(t){let i=0;for(let e=0;e<t.length;e++){const s=t.charCodeAt(e);128>s?i+=1:2048>s?i+=2:55296>s||s>56319?i+=3:(i+=4,e++)}return i}function O(t,i=Date.now()){if(!t)return;const e=+t;if(Number.isFinite(e)&&e>=0)return Math.round(1e3*e);const s=Date.parse(t);return Number.isFinite(s)?Math.max(0,s-i):void 0}const $="X-Joryio-Auth",D=2592e6;function _(t,i=Date.now()){if("string"==typeof t)return t?{token:t,at:i}:null;if(!t||"object"!=typeof t)return null;const{token:e,at:s,standby:n}=t;return"string"==typeof e&&e&&"number"==typeof s&&Number.isFinite(s)?!0===n?{token:e,at:s,standby:!0}:{token:e,at:s}:null}function T(t){var i;const e=null===(i=C(t))||void 0===i?void 0:i.sub;return"string"==typeof e&&e?e:null}function C(t){if(!t)return null;try{const i=t.split(".")[1];if(!i)return null;const e=i.replace(/-/g,"+").replace(/_/g,"/"),s=e+"=".repeat((4-e.length%4)%4),n="function"==typeof atob?atob:t=>globalThis.Buffer.from(t,"base64").toString("binary"),r=decodeURIComponent(Array.prototype.map.call(n(s),t=>"%"+("00"+t.charCodeAt(0).toString(16)).slice(-2)).join("")),o=JSON.parse(r);return o&&"object"==typeof o&&!Array.isArray(o)?o:null}catch(t){return null}}function M(t,i){const e=((t||"")+"").split("?")[0],s=i&&"object"==typeof i?i:{};if(e.endsWith("/v1/push/unregister"))return!0;if(e.endsWith("/v1/subscriptions/channel"))return"unsubscribed"===s.status;if(e.endsWith("/v1/subscriptions/group"))return"unsubscribe"===s.action;if(e.endsWith("/v1/attributes")){if(["increment","append","remove","unset"].some(t=>null!=s[t]&&Object.keys(s[t]).length>0))return!1;const t=s.attributes;if(!t||"object"!=typeof t||Array.isArray(t))return!1;const i=Object.keys(t);return i.length>0&&i.every(i=>"tracking_opted_out"===i&&!0===t[i])}return!1}const x={failureThreshold:5,cooldownMs:3e4};class P{constructor(t,i,e,s){this.circuitState="closed",this.consecutiveFailures=0,this.circuitOpenedAt=0,this.sdkAuthEnabled=!1,this.sdkAuthFailureCallback=null,this.retiredSdkAuthTokens=new Map,this.retiredTokenStore=null,this.sdkAuthTokenUser=null,this.keepaliveBytesInFlight=0,this.currentUserId=null,this.suspended=!1,this.sdkKey=t,this.logger=i,this.retryConfig=e,this.circuitBreakerConfig=Object.assign(Object.assign({},x),s)}setSdkAuthenticationEnabled(t){this.sdkAuthEnabled=t}setSdkAuthenticationToken(t){const i="string"==typeof t&&t?t:void 0,e=this.sdkAuthToken;if(e&&i&&e!==i){const t=T(e),s=T(i),n=t||this.sdkAuthTokenUser,r=t&&s?t!==s:!!n&&n!==this.currentUserId;n&&r&&this.retireToken(n,e)}this.sdkAuthToken=i,this.sdkAuthTokenUser=i?this.currentUserId:null}retireSdkAuthToken(){const t=T(this.sdkAuthToken),i=t||this.currentUserId,e=!!t&&t!==this.currentUserId;i&&this.sdkAuthToken&&this.retireToken(i,this.sdkAuthToken,e),this.sdkAuthToken=void 0,this.sdkAuthTokenUser=null}retireToken(t,i,e=!1){const s=new Map,n=this.retiredSdkAuthTokens.get(t);for(n&&n.token!==i&&s.set(t,n.token),this.retiredSdkAuthTokens.delete(t),this.retiredSdkAuthTokens.set(t,e?{token:i,at:Date.now(),standby:!0}:{token:i,at:Date.now()});this.retiredSdkAuthTokens.size>4;){const t=this.retiredSdkAuthTokens.keys().next().value;s.set(t,this.retiredSdkAuthTokens.get(t).token),this.retiredSdkAuthTokens.delete(t)}this.saveRetiredTokens(s)}switchUser(t){const i=this.currentUserId;if(i&&i!==t&&this.sdkAuthToken){const i=T(this.sdkAuthToken);t&&i===t||this.retireSdkAuthToken()}if(this.currentUserId=t,!this.sdkAuthToken&&t){const i=this.retiredSdkAuthTokens.get(t);i&&T(i.token)===t&&(this.sdkAuthToken=i.token,this.sdkAuthTokenUser=t)}this.adoptStandbyToken(t)}adoptStandbyToken(t){if(!t)return;const i=this.retiredSdkAuthTokens.get(t);i&&i.standby&&T(i.token)===t&&(this.retiredSdkAuthTokens.set(t,{token:i.token,at:i.at}),this.saveRetiredTokens())}dropStandbySdkAuthTokens(t=new Set){if(this.retiredSdkAuthTokens.forEach((i,e)=>{i.standby&&!t.has(e)&&this.retiredSdkAuthTokens.delete(e)}),this.retiredTokenStore)try{this.retiredTokenStore.update(i=>{const e={},s=Date.now();for(const n of Object.keys(i||{})){const r=_(i[n],s);!r||r.standby&&!t.has(n)||s-r.at>D||(e[n]=r)}return e})}catch(t){this.logger.warn("Could not store the SDK authentication tokens:",t)}}setRetiredTokenStore(t){if(this.retiredTokenStore=t,!t)return;let i=null;try{i=t.load()}catch(t){this.logger.warn("Could not read the stored SDK authentication tokens:",t)}if(!i||"object"!=typeof i)return;const e=Date.now();for(const t of Object.keys(i)){const s=_(i[t],e);s&&e-s.at<=D&&(this.retiredSdkAuthTokens.has(t)||this.retiredSdkAuthTokens.set(t,s))}}retiredSdkAuthUsers(){return Array.from(this.retiredSdkAuthTokens.keys())}forgetRetiredSdkAuthTokensExcept(t,i=Date.now()){const e=new Map;let s=null;return this.retiredSdkAuthTokens.forEach((n,r)=>{const o=i-n.at;o>D?e.set(r,n.token):n.standby||t.has(r)||(6e4>o?s=Math.min(null!=s?s:1/0,6e4-o):e.set(r,n.token))}),e.forEach((t,i)=>this.retiredSdkAuthTokens.delete(i)),e.size&&this.saveRetiredTokens(e),s}saveRetiredTokens(t=new Map){if(this.retiredTokenStore)try{this.retiredTokenStore.update(i=>{const e={},s=Date.now();for(const n of Object.keys(i||{})){const r=_(i[n],s);r&&s-r.at<=D&&t.get(n)!==r.token&&(e[n]=r)}return this.retiredSdkAuthTokens.forEach((t,i)=>{const n=_(e[i],s);if(!n||n.token===t.token)return void(e[i]=Object.assign({},t));const r=function(t,i){const e=C(t),s=C(i),n=t=>"number"==typeof t&&Number.isFinite(t)?t:null;for(const r of["exp","iat"]){const o=n(null==e?void 0:e[r]),h=n(null==s?void 0:s[r]);if(null!==o&&null!==h&&o!==h)return o>h?t:i}return null}(n.token,t.token);(r?r!==t.token:n.at>t.at)?this.retiredSdkAuthTokens.set(i,n):e[i]=Object.assign({},t)}),e})}catch(t){this.logger.warn("Could not store the SDK authentication tokens:",t)}}sdkAuthTokenFor(t){var i;const e=void 0===t?this.currentUserId:t;if(!e)return;const s=this.sdkAuthEnabled?this.sdkAuthToken:void 0,n=T(s);return s&&n===e?s:!s||n||e!==this.currentUserId||null!==this.sdkAuthTokenUser&&this.sdkAuthTokenUser!==e?null===(i=this.retiredSdkAuthTokens.get(e))||void 0===i?void 0:i.token:s}getCurrentUserId(){return this.currentUserId}setSdkAuthenticationFailureCallback(t){this.sdkAuthFailureCallback=t}setCurrentUserId(t){this.currentUserId=t,this.adoptStandbyToken(t)}isSuspended(){return this.suspended}noteSuspended(t,i){return 402===t&&(this.suspended||(this.suspended=!0,console.warn(`[Joryio SDK] The API refused this request with 402 ${(null==i?void 0:i.code)||""} - event ingestion is paused for this workspace. Nothing more will be sent this page view; queued events are kept.`)),!0)}getSdkAuthHeaders(t){const i=this.sdkAuthTokenFor(t);return i?{[$]:i}:{}}keepaliveBudget(){return Math.max(0,61440-this.keepaliveBytesInFlight)}isSdkAuthError(t,i){return 401===t&&!!i&&"object"==typeof i&&"sdk_authentication_error"===i.error}async refreshSdkAuthToken(t){if(!this.sdkAuthEnabled||!this.sdkAuthFailureCallback)return;const i=this.sdkAuthToken;let e;try{e=await Promise.resolve(this.sdkAuthFailureCallback(t))}catch(t){return void this.logger.error("SDK authentication failure callback threw:",t)}"string"==typeof e&&e&&this.setSdkAuthenticationToken(e);const s=this.sdkAuthToken;return s&&s!==i?s:void 0}async request(t){var i,e;if(this.suspended&&!M(t.url,t.body))return{ok:!1,status:402,error:"Ingestion suspended",data:{code:"SDK_INGESTION_SUSPENDED"}};if("open"===this.circuitState){const t=Date.now()-this.circuitOpenedAt;if(t<this.circuitBreakerConfig.cooldownMs)return this.logger.warn(`Circuit breaker OPEN – failing fast (${Math.round((this.circuitBreakerConfig.cooldownMs-t)/1e3)}s remaining)`),{ok:!1,status:0,error:"Circuit breaker is open – API requests are temporarily blocked"};this.circuitState="half-open",this.logger.info("Circuit breaker transitioning to HALF-OPEN – allowing probe request")}const{url:s,method:n="POST",headers:r={}}=t;let o;try{o=t.body?JSON.stringify(t.body):void 0}catch(t){return this.logger.error(`Request to ${s} not sent: its body cannot be serialized`,t),{ok:!1,status:400,error:"The request body cannot be serialized"}}const h=void 0===t.subjectUserId||(t.subjectUserId||null)===this.currentUserId;let a,u,d=null,l=0,c=0,p=!1;for(;c<=this.retryConfig.maxRetries;){try{this.logger.debug(`Request attempt ${c+1}/${this.retryConfig.maxRetries+1}: ${n} ${s}`);let{response:f,responseData:y}=await this.performFetch(s,n,r,o,t.subjectUserId);if(!p&&this.sdkAuthEnabled&&h&&this.isSdkAuthError(f.status,y)&&(p=!0,this.logger.warn(`SDK authentication rejected (${(null==y?void 0:y.reason)||"invalid"}) on ${s} – refreshing token`),await this.refreshSdkAuthToken({reason:(null==y?void 0:y.reason)||(this.sdkAuthToken?"invalid":"missing"),endpoint:s,userId:void 0===t.subjectUserId?this.currentUserId:t.subjectUserId||null})&&(this.logger.debug("SDK authentication token refreshed – retrying request once"),({response:f,responseData:y}=await this.performFetch(s,n,r,o,t.subjectUserId)))),f.ok)return this.onRequestSuccess(),j(y)?(this.logger.warn(`Request to ${s} answered ${f.status} with success: false`),{ok:!1,status:f.status,data:y,error:(null==y?void 0:y.error)||(null==y?void 0:y.message)||"The server reported success: false",softFailure:!0}):(this.logger.debug("Request successful: "+f.status),{ok:!0,status:f.status,data:y});if(!this.shouldRetry(f.status))return this.logger.warn("Request failed with non-retryable status: "+f.status),this.noteSuspended(f.status,y),{ok:!1,status:f.status,error:(null==y?void 0:y.message)||f.statusText,data:y};l=f.status,a=y,u=O(null===(e=null===(i=f.headers)||void 0===i?void 0:i.get)||void 0===e?void 0:e.call(i,"retry-after")),d=Error(`HTTP ${f.status}: ${f.statusText}`),this.logger.warn(`Request failed (attempt ${c+1}): ${d.message}`)}catch(t){d=t,l=0,a=void 0,u=void 0,this.logger.error(`Request error (attempt ${c+1}):`,t)}if(c<this.retryConfig.maxRetries){const t=Math.max(this.calculateBackoff(c),Math.min(null!=u?u:0,3e4));this.logger.debug(`Retrying in ${t}ms...`),await this.sleep(t)}c++}return this.onRequestFailure(),this.logger.error(`Request failed after ${this.retryConfig.maxRetries+1} attempts`),Object.assign({ok:!1,status:l,data:a,error:(null==d?void 0:d.message)||"Network request failed"},void 0!==u?{retryAfterMs:u}:{})}onRequestSuccess(){(this.consecutiveFailures>0||"closed"!==this.circuitState)&&this.logger.info(`Circuit breaker CLOSED – request succeeded after ${this.consecutiveFailures} consecutive failure(s)`),this.consecutiveFailures=0,this.circuitState="closed",this.circuitOpenedAt=0}onRequestFailure(){if(this.consecutiveFailures++,"half-open"===this.circuitState)return this.circuitState="open",this.circuitOpenedAt=Date.now(),void this.logger.warn(`Circuit breaker re-OPENED – probe request failed (${this.consecutiveFailures} consecutive failures)`);this.consecutiveFailures<this.circuitBreakerConfig.failureThreshold||(this.circuitState="open",this.circuitOpenedAt=Date.now(),this.logger.warn(`Circuit breaker OPENED – ${this.consecutiveFailures} consecutive failures reached threshold of ${this.circuitBreakerConfig.failureThreshold}`))}getCircuitBreakerState(){return{state:this.circuitState,consecutiveFailures:this.consecutiveFailures,openedAt:this.circuitOpenedAt}}async performFetch(t,i,e,s,n){const r=new AbortController,o=setTimeout(()=>r.abort(),this.retryConfig.timeoutMs||1e4),h=Object.assign({"Content-Type":"application/json","X-SDK-Key":this.sdkKey},e),a=this.sdkAuthTokenFor(n);let u;a&&(h[$]=a);try{u=await fetch(t,{method:i,headers:h,body:s,signal:r.signal,credentials:"omit"})}finally{clearTimeout(o)}return{response:u,responseData:await this.parseResponse(u)}}async parseResponse(t){var i,e;const s=null===(e=null===(i=t.headers)||void 0===i?void 0:i.get)||void 0===e?void 0:e.call(i,"content-type");if(s&&s.includes("application/json"))try{return await t.json()}catch(t){return this.logger.warn("Failed to parse JSON response"),null}return await t.text()}shouldRetry(t){return 408===t||429===t||t>=500}calculateBackoff(t){const{backoffMs:i,maxBackoffMs:e=3e4}=this.retryConfig,s=Math.min(i*Math.pow(2,t),e),n=.25*s*(2*Math.random()-1);return Math.max(0,Math.floor(s+n))}sleep(t){return new Promise(i=>setTimeout(i,t))}async sendEvents(t,i,e){var s;const n={events:i};return e&&(n.identify=A(e)),this.request({url:t+"/v1/track/batch",method:"POST",body:n,subjectUserId:(null==e?void 0:e.userId)||(null===(s=i.find(t=>t&&t.userId))||void 0===s?void 0:s.userId)||null})}supportsKeepalive(){try{return"function"==typeof fetch&&"undefined"!=typeof Request&&"keepalive"in Request.prototype}catch(t){return!1}}sendEventsKeepalive(t,i,e){const s={events:i};return e&&(s.identify=A(e)),this.postKeepalive(t+"/v1/track/batch",s)}postKeepalive(t,i){if(this.suspended&&!M(t,i)||!this.supportsKeepalive())return null;let e;try{e=JSON.stringify(i)}catch(t){return null}const s=I(e)+256;if(this.keepaliveBytesInFlight+s>61440)return null;const n={"Content-Type":"application/json","X-SDK-Key":this.sdkKey},r=this.sdkAuthTokenFor(function(t){if(!t||"object"!=typeof t)return null;if("string"==typeof t.userId&&t.userId)return t.userId;if("string"==typeof t.externalId&&t.externalId)return t.externalId;if(t.identify&&"string"==typeof t.identify.userId&&t.identify.userId)return t.identify.userId;for(const i of[t.events,t.impressions])if(Array.isArray(i)){const t=i.find(t=>t&&"string"==typeof t.userId&&t.userId);if(t)return t.userId}return null}(i));r&&(n[$]=r);try{this.keepaliveBytesInFlight+=s;let i=!1;const r=()=>{i||(i=!0,this.keepaliveBytesInFlight=Math.max(0,this.keepaliveBytesInFlight-s))};return fetch(t,{method:"POST",headers:n,body:e,keepalive:!0,credentials:"omit"}).then(async t=>{r();const i=await this.parseResponse(t).catch(()=>null),e=t.ok&&j(i);return Object.assign({ok:t.ok&&!e,status:t.status,data:i},e?{softFailure:!0}:{})},t=>(r(),{ok:!1,status:0,error:((null==t?void 0:t.message)||t)+""}))}catch(t){return this.keepaliveBytesInFlight=Math.max(0,this.keepaliveBytesInFlight-s),this.logger.warn("keepalive request could not be started:",t),null}}async sendIdentify(t,i,e,s){return this.request({url:t+"/v1/identify",method:"POST",body:{userId:i,attributes:e,anonymousId:s},subjectUserId:i})}async sendAddAlias(t,i){return this.request({url:t+"/v1/alias/add",method:"POST",body:i,subjectUserId:i.userId||null})}async sendDeviceSession(t,i){return this.request({url:t+"/v1/device/session",method:"POST",body:i})}async sendSetAttributes(t,i,e,s){return this.request({url:t+"/v1/attributes",method:"POST",body:Object.assign({userId:e||void 0,anonymousId:e?void 0:s},i),subjectUserId:e||null})}async sendSubscriptionUpdate(t,i){return this.request({url:t+"/v1/subscriptions/channel",method:"POST",body:i,subjectUserId:i.userId||null})}async sendSubscriptionGroupUpdate(t,i){return this.request({url:t+"/v1/subscriptions/group",method:"POST",body:i,subjectUserId:i.userId||null})}}const K="event_queue",F="event_queue_inflight",E="pending_identify",N=921600,q=3e5;function U(t,i){return i.every(i=>i.anonymousId===t.anonymousId&&(!i.userId||i.userId===t.userId))}class z{constructor(t,i,e,s,n=!0,r=1e3,o=1e3){if(this.queue=[],this.flushTimer=null,this.flushCallback=null,this.pendingPersist=!1,this.persistTimer=null,this.isFlushing=!1,this.flushWaiters=[],this.pendingIdentifies=[],this.inflightEvents=[],this.paused=!1,this.suspended=!1,this.consecutiveFailures=0,this.nextAttemptAt=0,this.retryAfterUntil=0,this.generation=0,this.clearedInflightCallback=null,this.storage=t,this.logger=i,this.batchSize=e>0?Math.floor(e):50,this.flushInterval=s,this.persistQueue=n,this.maxQueueSize=r>0?Math.floor(r):1e3,this.retryBackoffMs=o>0?o:1e3,this.persistQueue){const t=this.storage.get(F)||[],i=this.storage.get(K)||[];this.queue=[...t,...i],t.length>0&&(this.storage.remove(F),this.logger.debug(`Recovered ${t.length} in-flight events from previous page`)),this.queue.length>this.maxQueueSize&&(this.queue=this.queue.slice(-this.maxQueueSize)),this.queue.length>0&&(this.logger.debug(`Loaded ${this.queue.length} events from storage`),this.persistQueueToStorage());const e=this.storage.get(E),s=Array.isArray(e)?e:e?[e]:[];this.pendingIdentifies=s.filter(t=>t&&"string"==typeof t.userId&&"string"==typeof t.anonymousId).slice(-20),this.pendingIdentifies.length&&this.logger.debug(`Recovered ${this.pendingIdentifies.length} pending identify(s) from a previous page`)}}setFlushCallback(t){this.flushCallback=t}setPaused(t){this.paused=t}isPaused(){return this.paused}isSuspended(){return this.suspended}isBackingOff(){return this.consecutiveFailures>0||Date.now()<this.retryAfterUntil}resetBackoff(){this.consecutiveFailures=0,this.nextAttemptAt=0}setPendingIdentify(t){const i=this.pendingIdentifies[this.pendingIdentifies.length-1],e={userId:t.userId,anonymousId:t.anonymousId,attributes:t.attributes||{}};if(!i||i.userId!==e.userId||i.anonymousId!==e.anonymousId){if(this.pendingIdentifies.push(e),this.pendingIdentifies.length>20){const t=this.pendingIdentifies.shift();this.logger.warn(`Too many identify calls waiting to be sent; dropped the oldest (${t.userId})`)}this.persistIdentifies()}}persistIdentifies(){if(this.persistQueue)try{this.pendingIdentifies.length?this.storage.set(E,this.pendingIdentifies):this.storage.remove(E)}catch(t){this.logger.error("Failed to persist pending identify:",t)}}getPendingIdentify(){return this.pendingIdentifies[0]||null}getPendingIdentifies(){return[...this.pendingIdentifies]}removeIdentify(t){const i=this.pendingIdentifies.indexOf(t);0>i||this.pendingIdentifies.splice(i,1),this.persistIdentifies()}identifyAttemptFailed(t,i){i?(t.attempts=(t.attempts||0)+1,10>t.attempts?this.persistIdentifies():(this.logger.error(`Identify for ${t.userId} failed ${t.attempts} times; dropping it`),this.removeIdentify(t))):this.persistIdentifies()}start(){this.flushTimer?this.logger.debug("Queue manager already started"):(this.flushTimer=setInterval(()=>{this.flush().catch(t=>this.logger.error("Scheduled flush failed:",t))},this.flushInterval),this.logger.debug(`Queue manager started (batch: ${this.batchSize}, interval: ${this.flushInterval}ms)`),(this.queue.length>0||this.pendingIdentifies.length)&&this.flush().catch(t=>this.logger.error("Startup flush failed:",t)))}isStarted(){return null!==this.flushTimer}stop(){this.flushTimer&&(clearInterval(this.flushTimer),this.flushTimer=null,this.logger.debug("Queue manager stopped")),this.persistNow()}enqueue(t){this.queue.push(t),this.logger.debug(`Event queued: ${t.type} (queue size: ${this.queue.length})`),this.schedulePersist(),this.trimToMax(),this.queue.length<this.batchSize||this.isFlushing||(this.logger.debug("Batch size reached, flushing queue"),this.flush())}trimToMax(){if(this.queue.length>this.maxQueueSize){const t=this.queue.length-this.maxQueueSize;this.queue=this.queue.slice(-this.maxQueueSize),this.logger.warn(`Queue exceeded max size (${this.maxQueueSize}), dropped ${t} oldest event(s)`),this.schedulePersist()}}takeBatch(){const t=Math.min(this.batchSize,500),i=[];let e=64,s=null;for(;this.queue.length>0&&i.length<t;){const t=this.queue[0];if(i.length>0){if(t.anonymousId!==i[0].anonymousId)break;if(t.userId&&s&&t.userId!==s)break}let n;try{n=I(JSON.stringify(t))+1}catch(t){n=1/0}if(n>N)this.queue.shift(),this.logger.error(`Dropping event "${t.type}": it is too large to send (${n} bytes)`);else{if(i.length>0&&e+n>N)break;i.push(this.queue.shift()),t.userId&&(s=t.userId),e+=n}}return i}restoreToFront(t){if(!t.length)return;const i=new Set(this.queue.map(t=>t.eventId)),e=t.filter(t=>!i.has(t.eventId));this.queue.unshift(...e),this.trimToMax()}backOff(t){this.consecutiveFailures++;const i=Math.min(this.retryBackoffMs*Math.pow(2,Math.min(this.consecutiveFailures-1,20)),q),e=.2*i*Math.random(),s=Math.max(i+e,Math.min(null!=t?t:0,q));this.nextAttemptAt=Date.now()+s,t&&t>0&&(this.retryAfterUntil=Date.now()+Math.min(t,q)),this.logger.debug(`Event send failed; next attempt in ${Math.round(s)}ms`)}async sendBatch(t,i,e=[]){let s;this.inflightEvents=e.length?[...t,...e]:t,this.persistQueue&&(this.persistQueueToStorage(),this.persistInflightToStorage());try{s=await this.flushCallback(t,null!=i?i:void 0)||{status:"ok"}}catch(t){this.logger.error("Failed to flush events:",t),s={status:"retry"}}return this.inflightEvents=[],this.persistQueue&&this.storage.remove(F),s}async flush(t=!1,i=!1){var e,s;if(0===this.queue.length&&!this.pendingIdentifies.length&&!this.isFlushing)return;if(this.paused||this.suspended){if(t)throw Error(this.paused?"Sending is paused":"Sending is suspended");return}if(this.isFlushing)return await new Promise(t=>this.flushWaiters.push(t)),this.queue.length>0||this.pendingIdentifies.length?this.flush(t,i):void 0;const n=Date.now();if(n<this.retryAfterUntil||!i&&n<this.nextAttemptAt||"undefined"!=typeof navigator&&!1===navigator.onLine){if(t)throw Error("Waiting to retry");return}if(!this.flushCallback)return void this.logger.warn("No flush callback set, cannot flush queue");this.isFlushing=!0;let r=null;const o=this.generation;try{let t=null;const i=[];let n=this.queue.length;const h=new Set;for(;;){let a;i.length>0?a=i.shift():n>0?(a=this.takeBatch(),n-=a.length,0===a.length&&(n=0)):a=this.pendingIdentifies[0]&&!h.has(this.pendingIdentifies[0])&&this.pendingIdentifies[0]!==t&&this.queue.length>0&&U(this.pendingIdentifies[0],[this.queue[0]])?this.takeBatch():[];const u=this.pendingIdentifies[0]||null;let d=null;if(u&&!h.has(u)&&(0===a.length||u!==t&&U(u,a))&&(d=u),0===a.length&&!d)break;0===a.length&&d&&h.add(d),this.logger.debug(`Flushing ${a.length} events${d?" + identify":""}`);const l=await this.sendBatch(a,d,i.flat());if(this.generation!==o){if(this.logger.debug("Queue cleared during a flush; the in-flight batch is not restored"),this.clearedInflightCallback){let t=[];if("ok"===l.status){const i=new Set([...l.failedIndices||[],...l.rejectedIndices||[]]);t=a.filter((t,e)=>!i.has(e))}try{this.clearedInflightCallback(t)}catch(t){this.logger.warn("Cleared in-flight callback failed:",t)}}break}if("dropped"!==l.status){if("ok"===l.status){const t=t=>new Set((t||[]).filter(t=>Number.isInteger(t)&&t>=0&&t<a.length)),e=t(l.rejectedIndices);for(const t of e)this.logger.error(`Event "${a[t].type}" was refused by the server for good and has been dropped`);const s=[...t(l.failedIndices)].filter(t=>!e.has(t)).map(t=>a[t]);if(d&&l.identifyDropped&&(this.logger.error(`Identify for ${d.userId} was refused by the server; dropping it`),this.removeIdentify(d),d=null),d&&l.identifyFailed){this.identifyAttemptFailed(d,!1!==l.identifyAttemptCounts),this.restoreToFront([...s,...i.flat()]),this.backOff(),r="The identify was not confirmed";break}if(d&&this.removeIdentify(d),this.consecutiveFailures=0,this.nextAttemptAt=0,s.length>0){this.logger.warn(`${s.length} of ${a.length} events were not stored by the server; will retry them`),this.restoreToFront([...s,...i.flat()]),this.backOff(),r="Some events were not stored";break}continue}if("rejected"!==l.status){this.restoreToFront([...a,...i.flat()]),d&&"retry"===l.status&&this.identifyAttemptFailed(d,!0===l.counts),"suspended"===l.status?(this.suspended||(this.suspended=!0,console.warn(`[Joryio SDK] Event sending stopped for this page view (${l.reason||"refused"}). `+this.queue.length+" queued event(s) are kept.")),this.flushTimer&&(clearInterval(this.flushTimer),this.flushTimer=null),r="Sending is suspended"):(this.backOff(l.retryAfterMs),r="Events could not be delivered; will retry");break}if(d){if(0===a.length){this.logger.error(`Identify for ${d.userId} was refused by the server (HTTP ${null!==(e=l.httpStatus)&&void 0!==e?e:"4xx"}); dropping it`),this.removeIdentify(d);continue}t=d,i.unshift(a);continue}if(a.length>1){const t=Math.ceil(a.length/2);i.unshift(a.slice(0,t),a.slice(t));continue}1===a.length&&this.logger.error(`Event "${a[0].type}" was refused by the server (HTTP ${null!==(s=l.httpStatus)&&void 0!==s?s:"4xx"}) and has been dropped`)}else this.logger.error(`${a.length} event(s)${d?" and an identify":""} of a user who is no longer signed in were refused by SDK authentication (${l.reason||"401"}) and have been dropped`),d&&this.removeIdentify(d)}this.persistQueue&&this.persistQueueToStorage()}finally{this.isFlushing=!1;const t=this.flushWaiters;this.flushWaiters=[],t.forEach(t=>t())}if(r&&t)throw Error(r)}persistQueueToStorage(){this.pendingPersist=!1,null!==this.persistTimer&&(clearTimeout(this.persistTimer),this.persistTimer=null);try{this.storage.set(K,this.queue)}catch(t){this.logger.error("Failed to persist queue to storage:",t)}}schedulePersist(){this.persistQueue&&!this.pendingPersist&&(this.pendingPersist=!0,this.persistTimer=setTimeout(()=>{this.persistTimer=null,this.pendingPersist&&this.persistQueueToStorage()},150))}persistNow(){this.persistQueue&&this.pendingPersist&&this.persistQueueToStorage()}persistInflightToStorage(){try{this.inflightEvents.length>0?this.storage.set(F,this.inflightEvents):this.storage.remove(F)}catch(t){this.logger.error("Failed to persist in-flight events to storage:",t)}}getQueueSize(){return this.queue.length}getQueuedEvents(){return[...this.inflightEvents,...this.queue]}getWaitingEvents(){return[...this.queue]}getInflightEvents(){return[...this.inflightEvents]}setClearedInflightCallback(t){this.clearedInflightCallback=t}markHandedOff(t,i){const e=new Set(t.map(t=>t.eventId));this.queue=this.queue.filter(t=>!e.has(t.eventId)),this.inflightEvents=this.inflightEvents.filter(t=>!e.has(t.eventId)),i&&this.removeIdentify(i),this.persistQueue&&(this.persistQueueToStorage(),this.persistInflightToStorage())}takeBack(t,i){this.restoreToFront(t),i&&!this.pendingIdentifies.includes(i)&&(this.pendingIdentifies.unshift(i),this.persistIdentifies()),this.persistQueue&&this.persistQueueToStorage()}clear(){this.generation++,this.queue=[],this.inflightEvents=[],this.persistQueue&&(this.storage.remove(K),this.storage.remove(F),this.storage.remove(E)),this.pendingIdentifies=[],this.logger.debug("Queue cleared")}async destroy(){this.stop(),this.queue.length>0&&(this.logger.debug("Flushing remaining events before destroy"),await this.flush())}}const R="first_touch_utm",J="last_touch_utm",H="session_utm",W="session_referrer",L="session_landing_page";class B{constructor(t,i,e=!1){this.newCampaignDetected=!1,this.storage=t,this.logger=i,this.resetSessionOnNewCampaign=e,this.resetSessionOnNewCampaign&&(this.newCampaignDetected=this.detectNewCampaign()),this.captureUTMParameters()}captureUTMParameters(){if("undefined"==typeof window)return;const t=new URLSearchParams(window.location.search),i={};let e=!1;const s=["utm_source","utm_medium","utm_campaign","utm_content","utm_term"];for(const n of s){const s=t.get(n);s&&(i[n]=s,e=!0)}document.referrer&&(i.referrer=document.referrer),i.landing_page=window.location.href,i.captured_at=Date.now(),e?(this.logger.debug("Captured UTM parameters:",i),this.storage.set(H,i),this.storage.set(W,i.referrer||null),this.storage.set(L,i.landing_page),this.storage.get(R)||(this.storage.set(R,i),this.logger.debug("Set first touch UTM:",i)),this.storage.set(J,i),this.logger.debug("Updated last touch UTM:",i)):this.storage.get(H)||(this.storage.set(H,i),this.storage.set(W,i.referrer||null),this.storage.set(L,i.landing_page),this.logger.debug("Captured session referrer and landing page"))}getUTMData(){return{current:this.storage.get(H)||null,firstTouch:this.storage.get(R)||null,lastTouch:this.storage.get(J)||null}}getCurrentUTM(){return this.storage.get(H)||null}getFirstTouchUTM(){return this.storage.get(R)||null}getLastTouchUTM(){return this.storage.get(J)||null}getSessionReferrer(){return this.storage.get(W)||null}getSessionLandingPage(){return this.storage.get(L)||null}hasNewCampaign(){return this.newCampaignDetected}detectNewCampaign(){if("undefined"==typeof window)return!1;const t=new URLSearchParams(window.location.search),i=this.getCurrentUTM();if(!i)return t.has("utm_source")||t.has("utm_medium")||t.has("utm_campaign");const e=["utm_source","utm_medium","utm_campaign","utm_content","utm_term"];for(const s of e){const e=t.get(s),n=i[s];if(e&&e!==n)return!0}return!1}updateUTM(){this.resetSessionOnNewCampaign&&(this.newCampaignDetected=this.detectNewCampaign()),this.captureUTMParameters()}clearSessionUTM(){this.storage.remove(H),this.storage.remove(W),this.storage.remove(L),this.logger.debug("Cleared session UTM")}clearAllUTM(){this.storage.remove(H),this.storage.remove(R),this.storage.remove(J),this.storage.remove(W),this.storage.remove(L),this.logger.debug("Cleared all UTM data")}reset(){this.clearAllUTM()}getUTMProperties(){const t=this.getCurrentUTM(),i=this.getFirstTouchUTM(),e=this.getLastTouchUTM(),s={};return t&&(t.utm_source&&(s.utm_source=t.utm_source),t.utm_medium&&(s.utm_medium=t.utm_medium),t.utm_campaign&&(s.utm_campaign=t.utm_campaign),t.utm_content&&(s.utm_content=t.utm_content),t.utm_term&&(s.utm_term=t.utm_term),t.referrer&&(s.referrer=t.referrer),t.landing_page&&(s.landing_page=t.landing_page)),i&&(i.utm_source&&(s.first_touch_utm_source=i.utm_source),i.utm_medium&&(s.first_touch_utm_medium=i.utm_medium),i.utm_campaign&&(s.first_touch_utm_campaign=i.utm_campaign),i.utm_content&&(s.first_touch_utm_content=i.utm_content),i.utm_term&&(s.first_touch_utm_term=i.utm_term),i.referrer&&(s.first_touch_referrer=i.referrer),i.landing_page&&(s.first_touch_landing_page=i.landing_page),i.captured_at&&(s.first_touch_captured_at=new Date(i.captured_at).toISOString())),e&&e!==t&&(e.utm_source&&(s.last_touch_utm_source=e.utm_source),e.utm_medium&&(s.last_touch_utm_medium=e.utm_medium),e.utm_campaign&&(s.last_touch_utm_campaign=e.utm_campaign),e.utm_content&&(s.last_touch_utm_content=e.utm_content),e.utm_term&&(s.last_touch_utm_term=e.utm_term),e.referrer&&(s.last_touch_referrer=e.referrer),e.landing_page&&(s.last_touch_landing_page=e.landing_page),e.captured_at&&(s.last_touch_captured_at=new Date(e.captured_at).toISOString())),s}}const V={modal:600,slideup:400};function Q(t,i,e=16){const s=Math.max(0,Math.floor(i)-2*e);return Math.max(0,Math.min(Math.floor(t),s))}const G="__joryioInApp",X="inapp_impressions";function Y(t,i){var e,s;const n=t=>t.split(",").map(t=>{const e=t.trim();return e?/^(?:html|body|:root)$/i.test(e)?i:`${i} ${e}`:""}).filter(Boolean).join(", "),r=[];for(let o=0;o<t.length;o++){const h=t[o];if(void 0!==h.selectorText&&h.style){const t=n(h.selectorText);t&&r.push(`${t} { ${h.style.cssText} }`)}else if(h.cssRules&&void 0!==h.conditionText){const t=(null!==(e=h.cssText)&&void 0!==e?e:"").slice(0,(null!==(s=h.cssText)&&void 0!==s?s:"").indexOf("{")).trim(),n=Y(h.cssRules,i);t&&n&&r.push(`${t} { ${n} }`)}else 7===h.type&&h.cssText&&r.push(h.cssText)}return r.join("\n")}const Z=new Set(["click","clicked","button","link","cta_click","link_click","button_click"]);function tt(t){if("string"!=typeof t)return;const i=t.trim();return i&&!Z.has(i.toLowerCase())?i.slice(0,128):void 0}const it=new Set(["modal","banner","slideup","fullscreen"]);function et(t){if("string"!=typeof t)return null;const i=t.trim();return!i||i.length>100||/[;{}<>\\]/.test(i)?null:i}class st{capabilities(){const t=["content.native"];return this.allowHtmlJsInAppMessages&&t.push("content.html"),t}callHost(t,i){try{i()}catch(i){this.logger.error(`The ${t} callback threw; ignored:`,i)}}invalidate(){this.generation++,this.isSyncing&&(this.syncAgain=!0)}setAllowHtmlJsInAppMessages(t){this.allowHtmlJsInAppMessages=t}constructor(t,i,e,s,n,r,o,h,a,u){this.pendingDelays=new Map,this.campaigns=new Map,this.displayedMessages=new Map,this.impressionTimestamps=new Map,this.watchedAttributes=new Set,this.displayOptions={},this.isSyncing=!1,this.syncRetried=!1,this.generation=0,this.syncAgain=!1,this.claimed=new Set,this.iframes=new Map,this.frameMaxWidths=new Map,this.allowHtmlJsInAppMessages=!1,this.bridge=null,this.auth=null,this.runtime={canSend:(null==u?void 0:u.canSend)||(()=>!0),requestTimeoutMs:(null==u?void 0:u.requestTimeoutMs)||1e4,syncIntervalMs:(null==u?void 0:u.syncIntervalMs)||0,evaluationMode:(null==u?void 0:u.evaluationMode)||"differential-sync",noteStatus:null==u?void 0:u.noteStatus},this.apiEndpoint=t,this.sdkKey=i,this.identity=e,this.session=s,this.logger=n,this.storage=r||null,this.displayOptions=o||{},this.bridge=h||null,this.auth=a||null,this.loadImpressionTimestamps(),this.installHostBridge()}loadImpressionTimestamps(){if(this.storage)try{const t=this.storage.get(X);if(t&&"object"==typeof t)for(const[i,e]of Object.entries(t))Array.isArray(e)&&this.impressionTimestamps.set(i,e.filter(t=>"number"==typeof t))}catch(t){this.logger.error("Failed to load persisted impression timestamps:",t)}}persistImpressionTimestamps(){if(this.storage)try{const t={};this.impressionTimestamps.forEach((i,e)=>{t[e]=i}),this.storage.set(X,t)}catch(t){this.logger.error("Failed to persist impression timestamps:",t)}}installHostBridge(){"undefined"!=typeof window&&(window[G]={logCustomEvent:(t,i,e)=>{var s;this.displayedMessages.has(t)&&i&&(null===(s=this.bridge)||void 0===s||s.logCustomEvent(i,e))},setCustomUserAttribute:(t,i,e)=>{var s;this.displayedMessages.has(t)&&i&&(null===(s=this.bridge)||void 0===s||s.setCustomUserAttribute(i,e))},changeUser:(t,i)=>{var e;this.displayedMessages.has(t)&&i&&(null===(e=this.bridge)||void 0===e||e.changeUser(i))},requestPushPermission:t=>{var i;this.displayedMessages.has(t)&&(null===(i=this.bridge)||void 0===i||i.requestPushPermission())},logConversion:(t,i)=>{this.displayedMessages.has(t)&&i&&this.trackConversion(t,i).catch(()=>{})},logClick:(t,i)=>{if(!this.displayedMessages.has(t))return;const e=tt(i);this.trackImpression(t,"clicked",e?{elementId:e}:void 0).catch(()=>{});const s=this.displayedMessages.get(t);s&&this.callHost("onMessageClick",()=>{var t,e;return null===(e=(t=this.displayOptions).onClick)||void 0===e?void 0:e.call(t,s,i||"click")})},navigate:(t,i,e)=>{this.displayedMessages.has(t)&&"string"==typeof i&&/^(https?:\/\/|\/(?!\/))/i.test(i)&&("_top"===e||"_self"===e?window.top&&(window.top.location.href=i):window.open(i,"_blank","noopener"))},closeMessage:t=>{this.displayedMessages.has(t)&&this.dismiss(t,"bridge_close").catch(()=>{})},submitForm:(t,i)=>this.displayedMessages.has(t)&&i&&"object"==typeof i?(this.trackImpression(t,"clicked").catch(()=>{}),this.submitForm(t,i)):Promise.resolve({ok:!1,message:"This message is no longer open."}),setSize:(t,i,e)=>{var s;const n=this.iframes.get(t);if(!n||!Number.isFinite(e)||0>=e)return;const r=null===(s=this.displayedMessages.get(t))||void 0===s?void 0:s.campaign.type;n.style.height="fullscreen"===r?"100%":Math.ceil(e)+"px"}})}async initialize(){this.runtime.canSend()&&(this.logger.info("Initializing in-app messaging"),this.stop(),await this.sync().catch(t=>{this.logger.error("Initial in-app sync failed:",t)}),this.startAttributeWatching(),this.startPeriodicSync())}stop(){this.syncInterval&&(clearInterval(this.syncInterval),this.syncInterval=void 0),this.periodicSyncTimer&&(clearInterval(this.periodicSyncTimer),this.periodicSyncTimer=void 0),this.syncRetryTimer&&(clearTimeout(this.syncRetryTimer),this.syncRetryTimer=void 0),this.syncRetried=!1,this.pendingDelays.forEach(t=>clearTimeout(t)),this.pendingDelays.clear()}startPeriodicSync(){this.periodicSyncTimer&&(clearInterval(this.periodicSyncTimer),this.periodicSyncTimer=void 0),"differential-sync"===this.runtime.evaluationMode&&this.runtime.syncIntervalMs>0&&(this.periodicSyncTimer=setInterval(()=>{"undefined"!=typeof document&&document.hidden||this.runtime.canSend()&&this.sync().catch(t=>this.logger.debug("Periodic in-app sync failed:",t))},this.runtime.syncIntervalMs))}subject(){const t=this.identity.getUserId();return Object.assign(Object.assign({},t?{userId:t}:{}),{anonymousId:this.identity.getAnonymousId()})}async maybeHandleSdkAuthError(t,i,e){if(!this.auth||401!==t.status)return;if((e||null)!==((this.auth.getCurrentUserId?this.auth.getCurrentUserId():this.identity.getUserId())||null))return;let s=null;try{s=await t.clone().json()}catch(t){return}if(this.auth.isSdkAuthError(t.status,s)){this.logger.warn(`In-app request rejected by SDK authentication (${(null==s?void 0:s.reason)||"invalid"}) on ${i} – refreshing token`);try{await this.auth.refreshSdkAuthToken({reason:(null==s?void 0:s.reason)||"invalid",endpoint:i,userId:e})}catch(t){this.logger.error("Failed to refresh SDK authentication token for in-app request:",t)}}}async sync(t){var i,e,s;if(!this.runtime.canSend())return{success:!1,campaigns:[],evaluatedAt:(new Date).toISOString()};if(this.isSyncing)return this.syncAgain=!0,t&&(this.syncAgainChanges=Object.assign(Object.assign({},this.syncAgainChanges||{}),t)),{success:!1,campaigns:[],evaluatedAt:(new Date).toISOString()};this.isSyncing=!0;const n=this.generation;this.logger.debug("Syncing in-app campaigns");const r=this.session.getSessionId(),o=this.identity.getAttributes(),h=new AbortController,a=this.runtime.requestTimeoutMs,u=setTimeout(()=>h.abort(),a),d=this.identity.getUserId();try{const a=await fetch(this.apiEndpoint+"/v1/in-app/sync",{method:"POST",headers:Object.assign({"Content-Type":"application/json","X-SDK-Key":this.sdkKey},(null===(i=this.auth)||void 0===i?void 0:i.getSdkAuthHeaders(d))||{}),body:JSON.stringify(Object.assign(Object.assign({},this.subject()),{sessionId:r,userAttributes:t||o,pendingAttributes:this.identity.pending.pending(this.identity.getAnonymousId()),deviceType:"web",locale:navigator.language,capabilities:this.capabilities()})),signal:h.signal});if(!a.ok)throw null===(s=(e=this.runtime).noteStatus)||void 0===s||s.call(e,a.status,null),await this.maybeHandleSdkAuthError(a,this.apiEndpoint+"/v1/in-app/sync",d),Error(`Sync failed: ${a.status} ${a.statusText}`);const u=await a.json();if(n!==this.generation)return this.logger.debug("Discarding an in-app sync answer that predates an identity or consent change"),this.syncAgain=!0,{success:!1,campaigns:[],evaluatedAt:(new Date).toISOString()};if(!u||!1===u.success||!Array.isArray(u.campaigns))throw Error("Sync failed: the server reported success: false");this.syncRetried=!1,this.campaigns.clear();for(const t of u.campaigns)this.campaigns.set(t.id,t),"differential-sync"===t.evaluationMode&&t.watchedAttributes&&t.watchedAttributes.forEach(t=>this.boundedSetAdd(this.watchedAttributes,t,200));return this.logger.info(`Synced ${u.campaigns.length} eligible campaigns`),this.processImmediateTriggers(),u}catch(t){const i="AbortError"===(null==t?void 0:t.name);throw this.logger.error(i?`Campaign sync timed out after ${a}ms`:"Failed to sync campaigns:",t),n===this.generation&&!this.syncRetried&&this.runtime.canSend()&&(this.syncRetried=!0,this.syncRetryTimer=setTimeout(()=>{this.syncRetryTimer=void 0,this.sync().catch(()=>{})},5e3)),i?Error("Campaign sync timed out"):t}finally{if(clearTimeout(u),this.isSyncing=!1,this.syncAgain){this.syncAgain=!1;const t=this.syncAgainChanges;this.syncAgainChanges=void 0,this.runtime.canSend()&&this.sync(n!==this.generation?void 0:t).catch(t=>this.logger.debug("Follow-up in-app sync failed:",t))}}}processImmediateTriggers(){for(const t of this.campaigns.values())(t.triggers||[]).some(t=>"immediate"===t.type)&&this.displayCampaign(t).catch(t=>this.logger.error("In-app display failed:",t))}onEventTracked(t,i){if(t)for(const e of this.campaigns.values())if((e.triggers||[]).find(e=>"event"===e.type&&e.event===t&&this.triggerFilterMatches(e,i)))return void this.displayCampaign(e).catch(t=>this.logger.error("In-app display failed:",t))}triggerFilterMatches(t,i){if(!t.attribute)return!0;const e=null==i?void 0:i[t.attribute],s=t.value;switch(t.operator){case void 0:case"equals":case"eq":return e===s;case"not_equals":case"neq":return e!==s;case"greater_than":case"gt":return+e>+s;case"less_than":case"lt":return+s>+e;case"contains":return((null!=e?e:"")+"").includes(s+"");case"exists":return null!=e;default:return!1}}async resolveForDisplay(t){var i,e,s;if(!this.runtime.canSend())return null;const n=this.generation,r=new AbortController,o=setTimeout(()=>r.abort(),this.runtime.requestTimeoutMs);try{const o=await fetch(this.apiEndpoint+"/v1/in-app/resolve",{method:"POST",headers:Object.assign({"Content-Type":"application/json","X-SDK-Key":this.sdkKey},(null===(i=this.auth)||void 0===i?void 0:i.getSdkAuthHeaders(this.identity.getUserId()))||{}),body:JSON.stringify(Object.assign(Object.assign({},this.subject()),{campaignId:t.id,sessionId:this.session.getSessionId(),userAttributes:this.identity.getAttributes(),pendingAttributes:this.identity.pending.pending(this.identity.getAnonymousId()),deviceType:"web"})),signal:r.signal});if(!o.ok)return null===(s=(e=this.runtime).noteStatus)||void 0===s||s.call(e,o.status,null),null;const h=await o.json();return n!==this.generation?null:(null==h?void 0:h.eligible)&&h.campaign?h.campaign:null}catch(t){return null}finally{clearTimeout(o)}}canPromptForPush(){try{return"undefined"!=typeof Notification&&"default"===Notification.permission}catch(t){return!1}}async displayCampaign(t){const i=t.id;if(this.claimed.has(i)||this.displayedMessages.has(i)||this.pendingDelays.has(i))return void this.logger.debug(`Campaign ${i} already displayed, scheduled or being prepared`);this.claimed.add(i);const e=this.generation;try{if(t.reevaluateBeforeDisplay){const i=await this.resolveForDisplay(t);if(!i)return void this.logger.info(`Campaign ${t.id} not displayed: re-check said no`);t=i}if(this.displayedMessages.has(t.id)||this.pendingDelays.has(t.id))return void this.logger.debug(`Campaign ${t.id} already displayed or scheduled`);if(!this.checkFrequencyCap(t))return void this.logger.debug(`Campaign ${t.id} blocked by frequency cap`);const i=await this.renderTemplate(t);if(e!==this.generation||!this.runtime.canSend())return void this.logger.debug(`Campaign ${t.id} not displayed: the visitor or consent changed meanwhile`);const s=this.undisplayableReason(t,i);if(s)return void this.logger.warn(`Campaign ${t.id} not displayed (${s}). No impression recorded and no frequency cap consumed, so it stays eligible.`);if(i.includes("requestPushPermission")&&!this.canPromptForPush())return void this.logger.debug(`Campaign ${t.id} is a push primer but the browser can't be prompted (permission not 'default'); suppressing.`);const n={campaign:t,renderedHtml:i,displayedAt:new Date},r=()=>{this.boundedMapSet(this.displayedMessages,t.id,n,500);const i=this.impressionTimestamps.get(t.id)||[];i.push(Date.now()),this.boundedMapSet(this.impressionTimestamps,t.id,i,500),this.persistImpressionTimestamps(),this.display(n)},o=1e3*Math.max(0,+t.delay||0);if(o>0){const i=setTimeout(()=>{this.pendingDelays.delete(t.id),e===this.generation&&this.runtime.canSend()?!this.displayedMessages.has(t.id)&&this.checkFrequencyCap(t)&&(r(),this.trackImpression(t.id,"displayed").catch(()=>{})):this.logger.debug(`Campaign ${t.id} not displayed after its delay: the visitor or consent changed`)},o);return void this.pendingDelays.set(t.id,i)}r(),await this.trackImpression(t.id,"displayed")}finally{this.claimed.delete(i)}}async renderTemplate(t){const i=t.content;return i&&"html"===i.kind?i.html:""}undisplayableReason(t,i){var e;const s=null===(e=t.content)||void 0===e?void 0:e.kind;return t.content?"native"===s?null:"html"===s?i.trim()?this.allowHtmlJsInAppMessages?null:"it is an HTML message and allowHtmlJsInAppMessages is false":"its `content.html` is empty":`this SDK cannot render content kind '${s+""}'`:"the payload carries no `content`"}display(t){var i,e,s,n,r,o,h;const{campaign:a,renderedHtml:u}=t,d=document.createElement("div");d.id="joryio-inapp-"+a.id;const l=it.has(a.type)?null:["top","center","bottom"].find(t=>t===this.displayOptions.defaultPosition)||"center",c=["fade","slide","none"].find(t=>t===this.displayOptions.defaultAnimation)||"fade";d.className="joryio-inapp joryio-inapp-"+a.type+(l?" joryio-inapp-pos-"+l:"")+("none"!==c?" joryio-inapp-anim-"+c:"");const p=document.createElement("style");p.id="joryio-style-"+a.id;const f=Number.isFinite(this.displayOptions.zIndex)?+this.displayOptions.zIndex:999999,y=et(this.displayOptions.backdropColor)||"rgba(0, 0, 0, 0.5)",m=et(this.displayOptions.closeButtonColor)||"inherit";p.textContent=`\n .joryio-inapp {\n position: fixed;\n z-index: ${f};\n }\n\n /* displayOptions.defaultPosition - only for types with no placement of their own. */\n .joryio-inapp-pos-top {\n top: 20px;\n left: 50%;\n transform: translateX(-50%);\n max-width: 90%;\n }\n .joryio-inapp-pos-center {\n top: 50%;\n left: 50%;\n transform: translate(-50%, -50%);\n max-width: 90%;\n max-height: 90%;\n }\n .joryio-inapp-pos-bottom {\n bottom: 20px;\n left: 50%;\n transform: translateX(-50%);\n max-width: 90%;\n }\n\n /* displayOptions.defaultAnimation. The individual \`translate\` property\n composes with the positioning \`transform\` above instead of\n replacing it. Motion is skipped for visitors who asked for less. */\n @keyframes joryio-inapp-fade-in { from { opacity: 0; } to { opacity: 1; } }\n @keyframes joryio-inapp-slide-in { from { opacity: 0; translate: 0 16px; } to { opacity: 1; translate: 0 0; } }\n .joryio-inapp-anim-fade { animation: joryio-inapp-fade-in 200ms ease-out both; }\n .joryio-inapp-anim-slide { animation: joryio-inapp-slide-in 240ms ease-out both; }\n @media (prefers-reduced-motion: reduce) {\n .joryio-inapp-anim-fade, .joryio-inapp-anim-slide { animation: none; }\n }\n\n /* The message content lives in a sandboxed iframe; its own CSS stays\n inside it (no leak to/from the host page). Only SDK chrome is here. */\n .joryio-inapp > iframe {\n border: 0;\n width: 100%;\n display: block;\n background: transparent;\n color-scheme: normal;\n }\n\n .joryio-inapp-modal {\n top: 50%;\n left: 50%;\n transform: translate(-50%, -50%);\n max-width: 90%;\n max-height: 90%;\n }\n\n .joryio-inapp-banner {\n top: 0;\n left: 0;\n right: 0;\n }\n\n .joryio-inapp-slideup {\n bottom: 20px;\n right: 20px;\n max-width: 400px;\n }\n\n .joryio-inapp-fullscreen {\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n }\n\n /* Native card. Deliberately minimal and system-font: the host page's\n typography is the closest thing the web has to "the app's look", and\n a shipped palette would clash with every site.\n\n Every author-settable value comes through a CUSTOM PROPERTY with the\n system default as its fallback. That is what lets the campaign's own\n CSS override the colour pickers: inline styles beat a stylesheet, so\n setting the pickers inline would have made "advanced" strictly weaker\n than "basic" - the opposite of what an escape hatch is for. */\n .joryio-inapp-native {\n /* Positioning context for the close button, which sits in the card's\n top trailing corner rather than in the content flow. */\n position: relative;\n background: var(--joryio-inapp-bg, Canvas);\n color: var(--joryio-inapp-fg, CanvasText);\n color-scheme: light dark;\n border-radius: var(--joryio-inapp-radius, 14px);\n padding: 20px;\n box-shadow: 0 10px 40px rgba(0,0,0,0.18);\n font: menu;\n font-family: var(--joryio-inapp-font, system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif);\n /* Direction-relative, so a Hebrew or Arabic message reads from the\n right without the campaign having to know which way it runs. The\n card carries dir=auto, so 'start' resolves per message. */\n text-align: var(--joryio-inapp-align, start);\n max-width: 420px;\n }\n .joryio-inapp-fullscreen .joryio-inapp-native {\n border-radius: 0;\n max-width: none;\n height: 100%;\n }\n .joryio-inapp-native img {\n width: 100%;\n height: 140px;\n object-fit: cover;\n border-radius: 8px;\n display: block;\n margin-bottom: 14px;\n }\n .joryio-inapp-native h2 {\n margin: 0 0 8px;\n /* Room for the close button in the trailing corner. Logical, so in a\n Hebrew message the gap is on the left, where the button is. */\n padding-inline-end: 28px;\n /* Derived from the body size so one control keeps the hierarchy. */\n font-size: calc(var(--joryio-inapp-size, 14.5px) * 1.3);\n font-weight: var(--joryio-inapp-title-weight, 700);\n line-height: 1.3;\n }\n .joryio-inapp-native p {\n margin: 0 0 16px;\n font-size: var(--joryio-inapp-size, 14.5px);\n line-height: 1.5;\n opacity: 0.85;\n }\n .joryio-inapp-buttons {\n display: flex;\n gap: 8px;\n }\n .joryio-inapp-buttons.stacked {\n flex-direction: column;\n }\n .joryio-inapp-native button {\n flex: 1;\n min-height: 44px;\n border-radius: 8px;\n font: inherit;\n font-size: 14px;\n cursor: pointer;\n border: 1px solid transparent;\n }\n .joryio-inapp-native button.primary {\n background: var(--joryio-inapp-primary, AccentColor);\n color: var(--joryio-inapp-primary-fg, AccentColorText);\n }\n .joryio-inapp-native button.secondary {\n background: transparent;\n color: inherit;\n border-color: rgba(128,128,128,0.4);\n }\n /*\n * Native messages used to override the shared close button into a\n * full-width "Close" text row under the buttons, while HTML messages in\n * this same SDK drew an ✕ in the corner. One SDK, two dismiss designs -\n * and the text row also hardcoded the English word "Close", which is\n * wrong in a Hebrew or Arabic app. The ✕ needs no translation, so native\n * now uses the shared button and this override is gone.\n */\n\n .joryio-inapp-backdrop {\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: ${y};\n z-index: ${f-1};\n }\n\n .joryio-inapp-close {\n position: absolute;\n top: 6px;\n /* inset-inline-end, not right: the card carries dir=auto, so a Hebrew\n or Arabic message puts the ✕ in ITS trailing corner - the left one -\n without the campaign having to know which way the text runs. */\n inset-inline-end: 6px;\n display: flex;\n align-items: center;\n justify-content: center;\n /* 32px is the tap target; the glyph inside is smaller. Anything less\n is hard to hit on a phone, and it is the only way out of a\n full-screen message. */\n width: 32px;\n height: 32px;\n padding: 0;\n cursor: pointer;\n background: transparent;\n border: none;\n border-radius: 50%;\n font: inherit;\n font-size: 22px;\n line-height: 1;\n opacity: 0.55;\n color: ${m};\n }\n .joryio-inapp-close:hover,\n .joryio-inapp-close:focus-visible {\n opacity: 1;\n }\n `;const v=document.createElement("iframe");let b;if(v.id="joryio-iframe-"+a.id,"native"===(null===(i=a.content)||void 0===i?void 0:i.kind)){const i=a.content,s=document.createElement("div");s.className="joryio-inapp-native",s.dir="auto";const n=i.style;if("string"==typeof(null==n?void 0:n.customCss)&&(b=n.customCss),n){const t=(t,i,e="")=>{"string"==typeof i&&i.trim()?s.style.setProperty(t,i.trim()+e):"number"==typeof i&&Number.isFinite(i)&&s.style.setProperty(t,i+""+e)};t("--joryio-inapp-bg",n.backgroundColor),t("--joryio-inapp-fg",n.textColor),t("--joryio-inapp-font",n.fontFamily),t("--joryio-inapp-radius",n.cornerRadius,"px"),t("--joryio-inapp-size",n.fontSize,"px"),"string"==typeof n.titleWeight&&t("--joryio-inapp-title-weight",{regular:"400",medium:"500",semibold:"600",bold:"700"}[n.titleWeight]),"string"==typeof n.textAlign&&"auto"!==n.textAlign&&t("--joryio-inapp-align",n.textAlign),t("--joryio-inapp-primary",n.primaryButtonColor),t("--joryio-inapp-primary-fg","string"==typeof n.primaryButtonTextColor&&n.primaryButtonTextColor.trim()?n.primaryButtonTextColor:function(t){if("string"!=typeof t)return;const i=t.trim().replace(/^#/,""),e=3===i.length?i.replace(/(.)/g,"$1$1"):i;if(!/^[0-9a-f]{6}$/i.test(e))return;const[s,n,r]=[0,2,4].map(t=>parseInt(e.slice(t,t+2),16));return.2126*s+.7152*n+.0722*r>150?"#0A1240":"#FFFFFF"}(n.primaryButtonColor))}if(i.imageUrl&&/^https:\/\//i.test(i.imageUrl)){const t=document.createElement("img");t.src=i.imageUrl,t.alt="",t.onerror=()=>t.remove(),s.appendChild(t)}if(i.title){const t=document.createElement("h2");t.textContent=i.title,s.appendChild(t)}const r=document.createElement("p");if(r.textContent=i.body,s.appendChild(r),null===(e=i.buttons)||void 0===e?void 0:e.length){const e=document.createElement("div");e.className=i.buttons.length>2?"joryio-inapp-buttons stacked":"joryio-inapp-buttons",i.buttons.forEach((i,s)=>{const n=document.createElement("button");n.type="button",n.textContent=i.text,n.className=0===s?"primary":"secondary",n.addEventListener("click",()=>{var e;const s=tt(i.id);this.trackImpression(a.id,"clicked",Object.assign(Object.assign({},i.url&&/^https?:\/\//i.test(i.url)?{clickedUrl:i.url}:{}),s?{elementId:s}:{})).catch(()=>{}),this.callHost("onMessageClick",()=>{var e,s;return null===(s=(e=this.displayOptions).onClick)||void 0===s?void 0:s.call(e,t,i.id||i.action||"button")}),"request_push_permission"===i.action?this.canPromptForPush()&&(null===(e=this.bridge)||void 0===e||e.requestPushPermission()):("url"===i.action||"deep_link"===i.action)&&i.url&&/^https?:\/\//i.test(i.url)&&window.open(i.url,"_blank","noopener"),this.dismiss(a.id,"button").catch(()=>{})}),e.appendChild(n)}),s.appendChild(e)}if(!1!==i.closeButton){const t=document.createElement("button");t.type="button",t.className="joryio-inapp-close",t.innerHTML="×",t.setAttribute("aria-label","Close"),t.addEventListener("click",()=>{this.dismiss(a.id,"close_button").catch(()=>{})}),s.appendChild(t)}d.appendChild(s)}let g=!1;if("native"!==(null===(s=a.content)||void 0===s?void 0:s.kind)){if(!this.allowHtmlJsInAppMessages)return void this.logger.warn(`Campaign ${a.id} is an HTML in-app message, but allowHtmlJsInAppMessages is false - not displaying it.`);v.setAttribute("sandbox","allow-scripts allow-same-origin allow-popups");let t=0;v.addEventListener("load",()=>{var i,e;t++;let s=!0;try{const t=null===(e=null===(i=v.contentWindow)||void 0===i?void 0:i.location)||void 0===e?void 0:e.href;s=void 0===t||"about:srcdoc"===t}catch(t){s=!1}1>=t&&s||(this.logger.warn(`In-app message ${a.id} tried to navigate its frame; it has been closed`),this.dismiss(a.id,"navigation_blocked").catch(()=>{}))}),v.setAttribute("title",a.name||"Message"),v.style.height="0","banner"!==a.type&&"fullscreen"!==a.type||(v.style.width="100%");const i=function(t){var i;if("modal"!==t.type&&"slideup"!==t.type)return null;if("html"!==(null===(i=t.content)||void 0===i?void 0:i.kind))return null;const e=t.content.maxWidth;return"number"==typeof e&&Number.isFinite(e)&&e>0?Math.floor(e):V[t.type]}(a);if(null!==i&&(d.style.maxWidth="none",this.frameMaxWidths.set(a.id,i),v.style.width=Q(i,this.hostViewportWidth())+"px",this.watchViewport()),v.srcdoc=this.buildSrcdoc(a.id,u,"html"===(null===(n=a.content)||void 0===n?void 0:n.kind)?a.content.css:"",a.type),d.appendChild(v),this.iframes.set(a.id,v),u.includes("requestPushPermission")&&(null===(o=null===(r=this.bridge)||void 0===r?void 0:r.preparePushPermission)||void 0===o||o.call(r)),!1!==this.displayOptions.closeButton){const t=document.createElement("button");t.className="joryio-inapp-close",t.innerHTML="×",t.setAttribute("aria-label","Close"),t.onclick=async()=>{g||(g=!0,await this.dismiss(a.id,"close_button").catch(()=>{}))},d.appendChild(t)}}let w=null;if("modal"===a.type||"fullscreen"===a.type){w=document.createElement("div"),w.className="joryio-inapp-backdrop",w.id="joryio-backdrop-"+a.id;const t="native"!==(null===(h=a.content)||void 0===h?void 0:h.kind)||!1!==a.content.backdropDismissible;!1!==this.displayOptions.backdropClose&&t&&(w.onclick=async()=>{g||(g=!0,await this.dismiss(a.id,"backdrop").catch(()=>{}))})}const k=this.displayOptions.container||document.documentElement;if(w&&k.appendChild(w),k.appendChild(p),"string"==typeof b&&b.trim()){const t=this.scopeCss(b,"#joryio-inapp-"+a.id);if(t){const i=document.createElement("style");i.id="joryio-css-"+a.id,i.textContent=t,k.appendChild(i)}}k.appendChild(d),this.callHost("onMessageDisplay",()=>{var i,e;return null===(e=(i=this.displayOptions).onDisplay)||void 0===e?void 0:e.call(i,t)}),this.logger.info(`Displayed campaign: ${a.name} (${a.id})`)}hostViewportWidth(){const t="undefined"!=typeof document?document.documentElement:null,i=t&&"number"==typeof t.clientWidth?t.clientWidth:0;return i>0?i:"undefined"!=typeof window&&"number"==typeof window.innerWidth?window.innerWidth:0}sizeContentFrame(t){const i=this.iframes.get(t),e=this.frameMaxWidths.get(t);i&&void 0!==e&&(i.style.width=Q(e,this.hostViewportWidth())+"px")}watchViewport(){this.viewportListener||"undefined"==typeof window||"function"!=typeof window.addEventListener||(this.viewportListener=()=>{this.viewportTimer&&clearTimeout(this.viewportTimer),this.viewportTimer=setTimeout(()=>{this.viewportTimer=void 0;for(const t of this.frameMaxWidths.keys())this.sizeContentFrame(t)},100)},window.addEventListener("resize",this.viewportListener))}unwatchViewportIfIdle(){0>=this.frameMaxWidths.size&&this.viewportListener&&("undefined"!=typeof window&&"function"==typeof window.removeEventListener&&window.removeEventListener("resize",this.viewportListener),this.viewportListener=void 0,this.viewportTimer&&(clearTimeout(this.viewportTimer),this.viewportTimer=void 0))}buildSrcdoc(t,i,e,s){const n="modal"===s||"slideup"===s,r=n?"body{display:flow-root;}":"",o=`(function(){\n var CID=${JSON.stringify(t)},KEY=${JSON.stringify(G)},SIZED=${n?"true":"false"};\n // Per-device visibility: tag the root with the REAL device class from the\n // HOST page viewport (the iframe is message-sized, so its own innerWidth is\n // useless here). The jr-vp-* → jr-hide-* rules in <style> then hide elements\n // the dashboard marked "Mobile only" / "Desktop only". <=480 = mobile.\n try{var __vp=0;try{__vp=window.parent.innerWidth||0;}catch(e){}if(!__vp)__vp=window.innerWidth||0;document.documentElement.className+=(__vp<=480?' jr-vp-mobile':' jr-vp-desktop');}catch(e){}\n function host(){try{return window.parent[KEY]||null;}catch(e){return null;}}\n function call(m,args){var b=host();if(b&&typeof b[m]==='function'){try{return b[m].apply(b,[CID].concat(args||[]));}catch(e){}}}\n window.joryioBridge={\n logCustomEvent:function(name,props){call('logCustomEvent',[name,props]);},\n setCustomUserAttribute:function(k,v){call('setCustomUserAttribute',[k,v]);},\n changeUser:function(uid){call('changeUser',[uid]);},\n requestPushPermission:function(){call('requestPushPermission',[]);},\n logConversion:function(ev){call('logConversion',[ev||'in_app_conversion']);},\n submitForm:function(values){return call('submitForm',[values]);},\n logClick:function(action){call('logClick',[action]);},\n navigate:function(url,target){call('navigate',[url,target]);},\n closeMessage:function(){call('closeMessage',[]);}\n };\n document.addEventListener('click',function(e){\n var el=e.target;\n while(el&&el!==document.body&&el!==document.documentElement){\n var action=el.getAttribute&&el.getAttribute('data-joryio-action');\n if(action&&typeof window.joryioBridge[action]==='function'){e.preventDefault();window.joryioBridge[action](el.getAttribute('data-joryio-event')||undefined);return;}\n var tag=el.tagName;\n if(tag==='A'||tag==='BUTTON'){\n var da=el.getAttribute('data-action');\n var href=tag==='A'?el.getAttribute('href'):null;\n window.joryioBridge.logClick(da||(href?'link_click':'cta_click'));\n // Route only http(s)/root-relative links through the host (top-nav,\n // since the sandbox can't navigate the top page itself). Leave\n // #anchors, mailto:, tel:, sms: to the browser. Any other link\n // would navigate THIS frame away from the message: cancelled (rule 57).\n if(href&&/^(https?:\\/\\/|\\/(?!\\/))/i.test(href)){e.preventDefault();window.joryioBridge.navigate(href,el.getAttribute('target'));}\n else if(href&&!/^(#|mailto:|tel:|sms:)/i.test(href)){e.preventDefault();}\n return;\n }\n el=el.parentNode;\n }\n },true);\n // Forms (data-jry-form): serialize, hand the values to the host, show the\n // answer in place. A redirect goes through navigate (the sandbox cannot).\n document.addEventListener('submit',function(ev){var f=ev.target;if(!(f&&f.tagName==='FORM'&&f.hasAttribute('data-jry-form')))return;ev.preventDefault();if(f.getAttribute('data-jry-busy'))return;\n var d={},els=f.querySelectorAll('input,select,textarea');for(var i=0;i<els.length;i++){var el=els[i],n=el.name;if(!n||el.disabled)continue;if(el.type==='checkbox'){if(!el.checked)continue;if(d[n]===undefined)d[n]=[];d[n].push(el.value||'on')}else if(el.type==='radio'){if(el.checked)d[n]=el.value}else d[n]=el.value}\n function msg(text,ok){var b=f.querySelector('[data-jry-message]');if(!b){b=document.createElement('div');b.setAttribute('data-jry-message','');b.setAttribute('role','status');f.appendChild(b)}b.textContent=text;b.className=ok?'jry-form-success':'jry-form-error';reportSize()}\n f.setAttribute('data-jry-busy','1');var btn=f.querySelector('button[type="submit"],input[type="submit"]');if(btn)btn.disabled=true;\n var p=window.joryioBridge.submitForm(d);if(!p||typeof p.then!=='function'){msg('This form cannot be sent here.',false);f.removeAttribute('data-jry-busy');if(btn)btn.disabled=false;return}\n p.then(function(r){if(r&&r.ok){if(r.redirect){window.joryioBridge.navigate(r.redirect,'_top');return}var els2=f.querySelectorAll('input,select,textarea,button');for(var j=0;j<els2.length;j++){els2[j].disabled=true}msg(r.message||'Thank you.',true)}else{msg((r&&(r.message||(r.errors&&r.errors[0])))||'Something went wrong. Please try again.',false);f.removeAttribute('data-jry-busy');if(btn)btn.disabled=false}}).catch(function(){msg('Something went wrong. Please try again.',false);f.removeAttribute('data-jry-busy');if(btn)btn.disabled=false});\n },true);\n function reportSize(){try{var b=document.body,de=document.documentElement;var w=Math.max(b?b.scrollWidth:0,de.scrollWidth);var h=SIZED&&b?Math.ceil(Math.max(b.scrollHeight,b.getBoundingClientRect?b.getBoundingClientRect().height:0)):Math.max(b?b.scrollHeight:0,de.scrollHeight);call('setSize',[w,h]);}catch(e){}}\n if(document.readyState!=='loading')reportSize();else document.addEventListener('DOMContentLoaded',reportSize);\n window.addEventListener('load',reportSize);\n try{if(window.ResizeObserver&&document.body){new ResizeObserver(reportSize).observe(document.body);}}catch(e){}\n })();`,h=function(){const t=new Uint8Array(16),i=globalThis.crypto;if(i&&"function"==typeof i.getRandomValues)i.getRandomValues(t);else for(let i=0;i<t.length;i++)t[i]=Math.floor(256*Math.random());return Array.from(t,t=>t.toString(16).padStart(2,"0")).join("")}();return`<!doctype html><html><head><meta charset="utf-8"><meta http-equiv="Content-Security-Policy" content="${["default-src 'none'",`script-src 'nonce-${h}'`,"style-src 'unsafe-inline'; img-src https: data:; media-src https: data:; font-src https: data:; connect-src 'none'; form-action 'none'; base-uri 'none'; upgrade-insecure-requests"].join("; ")}"><meta name="viewport" content="width=device-width, initial-scale=1"><style>html,body{margin:0;padding:0;}img,video{max-width:100%;height:auto;}${r}.jr-vp-mobile .jr-hide-mobile{display:none!important}.jr-vp-desktop .jr-hide-desktop{display:none!important}${e=function(t){return"string"==typeof t?t.replace(/<\//g,"<\\/"):""}(e)}</style></head><body>${i}<script nonce="${h}">${o}<\/script></body></html>`}scopeCss(t,i){let e=null;try{e=document.createElement("style"),e.media="not all",e.textContent=t,document.head.appendChild(e);const s=e.sheet;if(!s)return this.logger.warn("Custom CSS could not be parsed; ignoring it"),"";const n=Y(s.cssRules,i);return n||this.logger.warn("Custom CSS contained no rules that can be scoped; ignoring it"),n}catch(t){return this.logger.warn("Custom CSS could not be parsed; ignoring it",t),""}finally{null==e||e.remove()}}async dismiss(t,i="dismiss"){const e=this.pendingDelays.get(t);e&&(clearTimeout(e),this.pendingDelays.delete(t));const s=document.getElementById("joryio-inapp-"+t),n=document.getElementById("joryio-backdrop-"+t),r=document.getElementById("joryio-style-"+t),o=document.getElementById("joryio-css-"+t);s&&s.remove(),this.iframes.delete(t),this.frameMaxWidths.delete(t),this.unwatchViewportIfIdle(),n&&n.remove(),r&&r.remove(),o&&o.remove();const h=this.displayedMessages.get(t);h&&(await this.trackImpression(t,"dismissed").catch(()=>{}),this.callHost("onMessageDismiss",()=>{var t,e;return null===(e=(t=this.displayOptions).onDismiss)||void 0===e?void 0:e.call(t,h,i)}),this.displayedMessages.delete(t)),this.logger.info("Dismissed campaign: "+t)}async trackConversion(t,i){await this.trackImpression(t,"converted",{conversionEvent:i});const e=this.displayedMessages.get(t);e&&this.callHost("onConversion",()=>{var t,s;return null===(s=(t=this.displayOptions).onConversion)||void 0===s?void 0:s.call(t,e,i)})}async submitForm(t,i){var e,s;const n=this.displayedMessages.get(t);if(!this.runtime.canSend())return{ok:!1,message:"This form cannot be sent right now."};const r=new AbortController,o=setTimeout(()=>r.abort(),this.runtime.requestTimeoutMs),h=this.identity.getUserId();try{const o=await fetch(this.apiEndpoint+"/v1/in-app/form-submit",{method:"POST",headers:Object.assign({"Content-Type":"application/json","X-SDK-Key":this.sdkKey},(null===(e=this.auth)||void 0===e?void 0:e.getSdkAuthHeaders(h))||{}),body:JSON.stringify({campaignId:t,variantId:null===(s=null==n?void 0:n.campaign)||void 0===s?void 0:s.variantId,userId:this.identity.getUserId()||void 0,anonymousId:this.identity.getAnonymousId(),values:i}),signal:r.signal});await this.maybeHandleSdkAuthError(o,this.apiEndpoint+"/v1/in-app/form-submit",h);const a=await o.json().catch(()=>null);return a&&"object"==typeof a?a:{ok:!1,message:"Something went wrong. Please try again."}}catch(t){return{ok:!1,message:"Something went wrong. Please try again."}}finally{clearTimeout(o)}}async trackImpression(t,i,e){var s,n,r,o;const h=this.campaigns.get(t)||(null===(s=this.displayedMessages.get(t))||void 0===s?void 0:s.campaign);if(!h)return;if(!this.runtime.canSend())return;const a=this.session.getSessionId(),u=Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({campaignId:t,variantId:h.variantId},this.subject()),{sessionId:a,deviceType:"web",locale:navigator.language,userAgent:navigator.userAgent}),h.pendingId?{pendingId:h.pendingId}:{}),h.deliveryToken?{deliveryToken:h.deliveryToken}:{}),e);"displayed"===i?u.displayedAt=(new Date).toISOString():"clicked"===i?(u.clicked=!0,u.clickedAt=(new Date).toISOString(),u.action="clicked"):"dismissed"===i?(u.dismissedAt=(new Date).toISOString(),u.action="dismissed"):"converted"===i&&(u.converted=!0,u.convertedAt=(new Date).toISOString());const d=new AbortController,l=setTimeout(()=>d.abort(),this.runtime.requestTimeoutMs),c="string"==typeof u.userId&&u.userId?u.userId:null;try{const e=await fetch(this.apiEndpoint+"/v1/in-app/track",{method:"POST",headers:Object.assign({"Content-Type":"application/json","X-SDK-Key":this.sdkKey},(null===(n=this.auth)||void 0===n?void 0:n.getSdkAuthHeaders(c))||{}),body:JSON.stringify(u),signal:d.signal});e.ok||null===(o=(r=this.runtime).noteStatus)||void 0===o||o.call(r,e.status,null),await this.maybeHandleSdkAuthError(e,this.apiEndpoint+"/v1/in-app/track",c),this.logger.debug(`Tracked ${i} for campaign ${t}`)}catch(e){"AbortError"===(null==e?void 0:e.name)?this.logger.error(`Impression tracking timed out after ${this.runtime.requestTimeoutMs}ms for campaign ${t}`):this.logger.error(`Failed to track ${i}:`,e)}finally{clearTimeout(l)}}checkFrequencyCap(t){if(!t.frequencyCap)return!0;const{maxImpressions:i,timeWindow:e,minDelayBetweenImpressions:s}=t.frequencyCap;if(!i||!e)return!0;const n=this.impressionTimestamps.get(t.id)||[],r=Date.now();let o=0;if("once"===e||"lifetime"===e)return 0===n.length;if("session"===e)o=this.session.getSessionInfo().sessionStart;else{const t=[["min",6e4],["mo",2592e6],["h",36e5],["d",864e5],["w",6048e5],["m",2592e6]];let i=864e5;for(const[s,n]of t){if(!e.endsWith(s))continue;const t=parseInt(e.slice(0,-s.length),10);!Number.isNaN(t)&&t>0&&(i=t*n);break}o=r-i}return n.filter(t=>t>=o).length<i&&!(s&&n.length>0&&1e3*s>r-n[n.length-1])}startAttributeWatching(){if(this.syncInterval&&(clearInterval(this.syncInterval),this.syncInterval=void 0),0===this.watchedAttributes.size)return;this.logger.debug(`Watching ${this.watchedAttributes.size} attributes for changes`);const t={};this.watchedAttributes.forEach(i=>{t[i]=this.identity.getAttribute(i)}),this.syncInterval=window.setInterval(()=>{if("undefined"!=typeof document&&document.hidden)return;const i={};let e=!1;if(this.watchedAttributes.forEach(s=>{const n=this.identity.getAttribute(s);n!==t[s]&&(i[s]=n,t[s]=n,e=!0)}),e){if(this.checkAttributeThresholds(Object.keys(i)),"session-start-only"===this.runtime.evaluationMode||!this.runtime.canSend())return;this.logger.info("Attribute changes detected, re-syncing campaigns"),this.sync(i).catch(t=>{this.logger.error("Failed to re-sync on attribute change:",t)})}},5e3)}checkAttributeThresholds(t){if(!t.length)return;const i=this.identity.getAttributes()||{};for(const e of this.campaigns.values())if((e.triggers||[]).some(e=>"attribute_threshold"===e.type&&!!e.attribute&&t.includes(e.attribute)&&this.triggerFilterMatches(e,i)))return void this.displayCampaign(e).catch(t=>this.logger.error("In-app display failed:",t))}getCampaigns(){return Array.from(this.campaigns.values())}getCampaign(t){return this.campaigns.get(t)}clearAll(){this.logger.info("Clearing in-app messaging state"),this.invalidate(),this.stop();for(const t of this.displayedMessages.keys())this.dismiss(t,"clear").catch(t=>this.logger.error("In-app dismiss failed:",t));this.campaigns.clear(),this.displayedMessages.clear(),this.watchedAttributes.clear(),this.iframes.clear(),this.frameMaxWidths.clear(),this.unwatchViewportIfIdle(),this.logger.info("In-app messaging state cleared")}forgetImpressions(){var t;this.impressionTimestamps.clear();try{null===(t=this.storage)||void 0===t||t.remove(X)}catch(t){}}boundedMapSet(t,i,e,s){if(t.set(i,e),t.size>s){const i=t.keys().next().value;void 0!==i&&t.delete(i)}}boundedSetAdd(t,i,e){if(t.add(i),t.size>e){const i=t.values().next().value;void 0!==i&&t.delete(i)}}destroy(){this.logger.info("Destroying in-app messaging"),this.stop();for(const t of this.displayedMessages.keys())this.dismiss(t,"destroy").catch(t=>this.logger.error("In-app dismiss failed:",t));this.campaigns.clear(),this.displayedMessages.clear(),this.impressionTimestamps.clear(),this.watchedAttributes.clear(),this.iframes.clear(),this.frameMaxWidths.clear(),this.unwatchViewportIfIdle(),"undefined"!=typeof window&&delete window[G]}}var nt;t.SubscriptionStatus=void 0,(nt=t.SubscriptionStatus||(t.SubscriptionStatus={})).OPTED_IN="optedIn",nt.SUBSCRIBED="subscribed",nt.UNSUBSCRIBED="unsubscribed";const rt=["email","sms","whatsapp","push","viber"];class ot{constructor(t,i,e,s,n){this.logger=t,this.network=i,this.identity=e,this.apiEndpoint=s,this.runWrite=n||((t,i)=>{this.sendOnce(i).then(i=>{i.ok||this.logger.error(`${t} failed (HTTP ${i.status||"no response"})`)},i=>this.logger.error(t+" failed:",i))})}sendOnce(t){return"subscription"===t.kind?this.network.sendSubscriptionUpdate(this.apiEndpoint,t.payload):"group"===t.kind?this.network.sendSubscriptionGroupUpdate(this.apiEndpoint,t.payload):Promise.resolve({ok:!1,status:0})}ids(){const t=this.identity.getUserId();return Object.assign(Object.assign({},t?{userId:t}:{}),{anonymousId:this.identity.getAnonymousId()})}setSubscription(i,e){if(!rt.includes(i))return void this.logger.error(`Invalid channel: ${i}. Must be one of: ${rt.join(", ")}`);const s=Object.values(t.SubscriptionStatus);if(!s.includes(e))return void this.logger.error(`Invalid status: ${e}. Must be one of: ${s.join(", ")}`);this.logger.debug(`Setting ${i} subscription status to ${e}`);const n=Object.assign({channel:i,status:e},this.ids());this.runWrite(`Update ${i} subscription`,{kind:"subscription",payload:n})}setSubscriptions(t){if(t&&"object"==typeof t)for(const[i,e]of Object.entries(t))void 0!==e&&this.setSubscription(i,e);else this.logger.error("setSubscriptions requires an object, e.g. { email: SubscriptionStatus.OPTED_IN }")}addToSubscriptionGroup(t,i="email"){this.updateGroup(t,i,"subscribe")}removeFromSubscriptionGroup(t,i="email"){this.updateGroup(t,i,"unsubscribe")}updateGroup(t,i,e){if("string"!=typeof t||!t)return void this.logger.error(`Cannot ${e} subscription group: groupId is required`);if(!rt.includes(i))return void this.logger.error(`Invalid channel: ${i}. Must be one of: ${rt.join(", ")}`);this.logger.debug(`${e} subscription group ${t} for channel ${i}`);const s=Object.assign({groupId:t,channel:i,action:e},this.ids());this.runWrite(`Subscription group ${t} ${e}`,{kind:"group",payload:s})}}const ht={error:0,warn:1,info:2,debug:3};class at{constructor(t,i="error"){this.enabled=t,this.level=i}shouldLog(t){return this.enabled&&ht[t]<=ht[this.level]}error(...t){this.shouldLog("error")&&console.error("[Joryio SDK]",...t)}warn(...t){this.shouldLog("warn")&&console.warn("[Joryio SDK]",...t)}info(...t){this.shouldLog("info")&&console.info("[Joryio SDK]",...t)}debug(...t){this.shouldLog("debug")&&console.debug("[Joryio SDK]",...t)}setEnabled(t){this.enabled=t}setLevel(t){this.level=t}}const ut=t=>t.includes("Edg/")?"Edge":t.includes("OPR/")?"Opera":t.includes("Chrome/")?"Chrome":t.includes("Safari/")&&!t.includes("Chrome/")?"Safari":t.includes("Firefox/")?"Firefox":t.includes("MSIE")||t.includes("Trident/")?"IE":"Unknown",dt=t=>"string"==typeof t&&t.trim().length>0,lt=t=>"number"==typeof t&&Number.isFinite(t),ct=t=>lt(t)?t:void 0;class pt{constructor(t,i,e){this.sdk=t,this.config={currency:i&&"string"==typeof i.currency&&i.currency||"USD"},this.logger=e||new at(!1)}guard(t,i,e){if(i)this.logger.warn(`ecommerce.${t}() not tracked: ${i}`);else try{e()}catch(i){this.logger.error(`ecommerce.${t}() failed:`,i)}}productProblem(t,i="product"){return t&&"object"==typeof t?dt(t.productId)?lt(t.price)?null:i+".price must be a finite number":i+".productId is required":`a ${i} object is required`}itemsProblem(t){if(!Array.isArray(t))return"an items array is required";for(const i of t){if(null==i)continue;const t=this.productProblem(i,"item");if(t)return t}return null}cartProblem(t,i){var e;return null!==(e=this.itemsProblem(t))&&void 0!==e?e:lt(i)?null:"cartValue must be a finite number"}textProblem(t){for(const[i,e]of Object.entries(t))if(!dt(e))return`a ${i} is required`;return null}amountsProblem(t){for(const[i,e]of Object.entries(t))if(null!=e&&!lt(e))return i+" must be a finite number";return null}validItems(t){return t.filter(t=>t&&"object"==typeof t)}itemCount(t){return t.reduce((t,i)=>t+(lt(i.quantity)?i.quantity:0),0)}viewProduct(t){this.guard("viewProduct",this.productProblem(t),()=>this.sdk.track("Product Viewed",{product_id:t.productId,name:t.name,price:t.price,category:t.category,brand:t.brand,variant:t.variant,variant_id:t.variantId,sku:t.sku,image_url:t.imageUrl,url:t.url,currency:this.config.currency}))}viewCategory(t,i,e){this.guard("viewCategory",this.textProblem({categoryId:t,categoryName:i}),()=>this.sdk.track("Product List Viewed",Object.assign({category_id:t,category_name:i},e&&"object"==typeof e?e:{})))}search(t,i,e){this.guard("search",this.textProblem({query:t}),()=>this.sdk.track("Products Searched",Object.assign({query:t,result_count:ct(i)},e&&"object"==typeof e?e:{})))}addToCart(t,i){var e;const s=null!==(e=this.productProblem(t,"item"))&&void 0!==e?e:this.amountsProblem({cartValue:i});this.guard("addToCart",s,()=>this.sdk.track("Product Added",{product_id:t.productId,name:t.name,price:t.price,quantity:t.quantity,category:t.category,brand:t.brand,variant:t.variant,variant_id:t.variantId,sku:t.sku,image_url:t.imageUrl,url:t.url,item_total:ct(t.price*t.quantity),cart_value:ct(i),currency:this.config.currency}))}removeFromCart(t,i=1){this.guard("removeFromCart",this.productProblem(t,"item"),()=>this.sdk.track("Product Removed",{product_id:t.productId,name:t.name,price:t.price,quantity:lt(i)?i:1,variant_id:t.variantId,sku:t.sku,currency:this.config.currency}))}cartViewed(t,i){this.guard("cartViewed",this.cartProblem(t,i),()=>{const e=this.validItems(t);this.sdk.track("Cart Viewed",{items:e.map(t=>({product_id:t.productId,name:t.name,price:t.price,quantity:t.quantity,variant_id:t.variantId,sku:t.sku})),item_count:this.itemCount(e),cart_value:ct(i),currency:this.config.currency})})}updateCart(t,i){this.guard("updateCart",this.cartProblem(t,i),()=>{const e=this.validItems(t);this.sdk.track("Cart Updated",{items:e.map(t=>({product_id:t.productId,name:t.name,price:t.price,quantity:t.quantity,variant_id:t.variantId,sku:t.sku})),item_count:this.itemCount(e),cart_value:ct(i),currency:this.config.currency})})}startCheckout(t,i,e){this.guard("startCheckout",this.cartProblem(t,i),()=>{const s=this.validItems(t);this.sdk.track("Checkout Started",Object.assign({items:s.map(t=>({product_id:t.productId,name:t.name,price:t.price,quantity:t.quantity,variant_id:t.variantId,sku:t.sku})),item_count:this.itemCount(s),value:ct(i),currency:this.config.currency},e&&"object"==typeof e?e:{}))})}addPaymentInfo(t,i){this.guard("addPaymentInfo",this.textProblem({paymentMethod:t}),()=>this.sdk.track("Payment Info Entered",Object.assign({payment_method:t},i&&"object"==typeof i?i:{})))}purchase(t){var i;const e=t&&"object"==typeof t?dt(t.orderId)?lt(t.value)?null!==(i=this.itemsProblem(t.items))&&void 0!==i?i:this.amountsProblem({shipping:t.shipping,tax:t.tax,discount:t.discount}):"order.value must be a finite number":"order.orderId is required":"an order object is required";this.guard("purchase",e,()=>{const i=this.validItems(t.items);this.sdk.track("Order Completed",{orderId:t.orderId,items:i.map(t=>({product_id:t.productId,name:t.name,price:t.price,quantity:t.quantity,category:t.category,brand:t.brand,variant_id:t.variantId,sku:t.sku})),item_count:this.itemCount(i),total:t.value,currency:t.currency||this.config.currency,shipping:ct(t.shipping),tax:ct(t.tax),discount:ct(t.discount),coupon:t.coupon})})}orderFulfilled(t,i,e){this.guard("orderFulfilled",dt(t)?null:"an orderId is required",()=>this.sdk.track("Order Fulfilled",{order_id:t,tracking_number:i,carrier:e}))}orderDelivered(t){this.guard("orderDelivered",dt(t)?null:"an orderId is required",()=>this.sdk.track("Order Delivered",{order_id:t}))}orderCancelled(t,i){this.guard("orderCancelled",dt(t)?null:"an orderId is required",()=>this.sdk.track("Order Cancelled",{order_id:t,reason:i}))}orderRefunded(t,i,e){var s;const n=null!==(s=this.textProblem({orderId:t}))&&void 0!==s?s:this.amountsProblem({refundAmount:i});this.guard("orderRefunded",n,()=>this.sdk.track("Order Refunded",{order_id:t,refund_amount:ct(i),reason:e}))}addToWishlist(t){this.guard("addToWishlist",this.productProblem(t),()=>this.sdk.track("Product Added to Wishlist",{product_id:t.productId,name:t.name,price:t.price,category:t.category,brand:t.brand,currency:this.config.currency}))}removeFromWishlist(t){this.guard("removeFromWishlist",this.productProblem(t),()=>this.sdk.track("Product Removed from Wishlist",{product_id:t.productId,name:t.name}))}shareProduct(t,i){var e;this.guard("shareProduct",null!==(e=this.productProblem(t))&&void 0!==e?e:this.textProblem({shareMethod:i}),()=>this.sdk.track("Product Shared",{product_id:t.productId,name:t.name,share_method:i}))}applyCoupon(t,i,e){var s;const n=null!==(s=this.textProblem({couponCode:t}))&&void 0!==s?s:this.amountsProblem({discountAmount:i});this.guard("applyCoupon",n,()=>this.sdk.track("Coupon Applied",{coupon_code:t,discount_amount:ct(i),discount_type:e}))}removeCoupon(t){this.guard("removeCoupon",dt(t)?null:"a couponCode is required",()=>this.sdk.track("Coupon Removed",{coupon_code:t}))}submitReview(t,i,e){const s=dt(t)?lt(i)?null:"rating must be a finite number":"a productId is required";this.guard("submitReview",s,()=>this.sdk.track("Product Reviewed",{product_id:t,rating:i,review_text:e}))}}function ft(t,i,e){return new pt(t,i,e)}function yt(t,i){var e={};for(var s in t)Object.prototype.hasOwnProperty.call(t,s)&&0>i.indexOf(s)&&(e[s]=t[s]);if(null!=t&&"function"==typeof Object.getOwnPropertySymbols){var n=0;for(s=Object.getOwnPropertySymbols(t);n<s.length;n++)0>i.indexOf(s[n])&&Object.prototype.propertyIsEnumerable.call(t,s[n])&&(e[s[n]]=t[s[n]])}return e}function mt(t){switch(t.kind){case"subscription":return"unsubscribed"===t.payload.status;case"group":return"unsubscribe"===t.payload.action;case"marker":return!0===t.payload.value;default:return!1}}"function"==typeof SuppressedError&&SuppressedError;const vt=[2e3,5e3,15e3,3e4,6e4,6e4,6e4,6e4,6e4],bt=3e5;function gt(t,i){const e=vt[Math.min(Math.max(t,1),vt.length)-1];return Math.min(Math.max(t>vt.length?Math.min(e*Math.pow(2,t-vt.length),bt):e,null!=i?i:0),bt)}function wt(t,i){if(t.ok)return{action:"done"};if(t.softFailure)return{action:"retry",counts:!0};const e=t.status;return 0!==e&&408!==e&&429!==e&&500>e?404===e?{action:"retry",counts:!0,notFound:!0}:401===e?i.isSdkAuthError?i.ownerIsCurrentUser?{action:"retry",counts:!0}:{action:"drop",reason:"SDK authentication refused a write of a user who is no longer signed in (401)"}:{action:"hold",reason:"the SDK key was refused (401)"}:402===e?{action:"retry",counts:!1,retryAfterMs:t.retryAfterMs}:{action:"drop",reason:`refused by the server (HTTP ${e})`}:{action:"retry",counts:!1,retryAfterMs:t.retryAfterMs}}function kt(t,i){return t>=10||i>=5}const St="push_registration",jt="push_unregistered",At="push_pending_unregister",It="joryio-sdk-state";class Ot{constructor(t,i,e,s,n={}){this.logger=t,this.network=i,this.identity=e,this.apiEndpoint=s,this.vapidKeyCache=null,this.prepared=null,this.lastPrepareError=null,this.unregisterInFlight=!1,this.unregisterTimer=null,this.canSend=n.canSend||(()=>!0),this.canWithdraw=n.canWithdraw||(()=>!0),this.withdrawalUserId=n.withdrawalUserId||(()=>this.identity.getUserId()),this.storage=n.storage||null,this.getDeviceId=n.getDeviceId||(()=>{}),this.onSubscribeSettled=n.onSubscribeSettled||null}isSupported(){return"undefined"!=typeof window&&"serviceWorker"in navigator&&"PushManager"in window&&"Notification"in window}getPermissionState(){if(!this.isSupported())return"unavailable";const t=Notification.permission;return"granted"===t||"denied"===t?t:"notDetermined"}async getExistingSubscription(t){if(!this.isSupported())return null;try{const i=await navigator.serviceWorker.getRegistration((null==t?void 0:t.scope)||"/");return i?await i.pushManager.getSubscription():null}catch(t){return this.logger.warn("Could not read the push subscription:",t),null}}async syncExistingSubscription(t=!1,i){var e,s;try{if(await this.sendPendingUnregister(),!this.canSend())return;if(!0===(null===(e=this.storage)||void 0===e?void 0:e.get(jt)))return;if(!this.isSupported()||"granted"!==Notification.permission)return;const n=await navigator.serviceWorker.getRegistration((null==i?void 0:i.scope)||"/");if(!n)return;let r=await n.pushManager.getSubscription();const o=null===(s=this.storage)||void 0===s?void 0:s.get(St),h=this.identity.getUserId(),a=this.identity.getAnonymousId(),u=!o||Date.now()-(o.at||0)>864e5,d=!r||!o||o.endpoint!==r.endpoint||o.userId!==h||o.anonymousId!==a;if(!t&&!u&&!d)return;const l=await this.fetchVapidPublicKey();if(!l)return;r&&!this.subscriptionKeyMatches(r,l)&&(this.logger.info("VAPID key changed - re-subscribing this browser"),await r.unsubscribe().catch(()=>!1),r=null),r||(r=await n.pushManager.subscribe({userVisibleOnly:!0,applicationServerKey:$t(l)})),await this.registerWithBackend(r)}catch(t){this.logger.warn("Could not refresh the push subscription:",t)}}async setTrackingOptedOut(t){try{if("undefined"==typeof caches)return;if(t){const t=await caches.open(It);await t.put("/__joryio/tracking-opted-out",new Response("1"))}else await caches.delete(It)}catch(t){this.logger.debug("Could not record the opt-out for the service worker:",t)}}async prepare(t){if(t=t||{},!this.isSupported())return this.lastPrepareError="unsupported",!1;if(this.prepared)return this.lastPrepareError=null,!0;const i=await this.fetchVapidPublicKey();if(!i)return this.lastPrepareError="no-key",this.logger.error("Web push is not enabled for this workspace"),!1;try{const e=await navigator.serviceWorker.register(t.swPath||"/joryio-sw.js",{scope:t.scope||"/"});return await navigator.serviceWorker.ready,this.prepared={registration:e,publicKey:i},this.lastPrepareError=null,!0}catch(t){return this.lastPrepareError="sw-failed",this.logger.error("Service worker registration failed:",t),!1}}async subscribe(t){var i;try{return await this.subscribeOnce(t)}finally{try{null===(i=this.onSubscribeSettled)||void 0===i||i.call(this)}catch(t){this.logger.warn("Push permission report failed:",t)}}}async subscribeOnce(t){var i;if(t=t||{},!this.isSupported())return console.warn("[Joryio SDK] Push not enabled: this browser/context does not support web push (needs HTTPS, a service worker, and PushManager - Safari < 16.4 and insecure origins are excluded)."),null;this.prepared||await this.prepare(t);const e=this.prepared;if(!e){this.logger.error("Web push is not enabled for this workspace");const i=t.swPath||"/joryio-sw.js";return"no-key"===this.lastPrepareError?console.warn("[Joryio SDK] Push not enabled: the server returned no VAPID key - web push is not configured for this app. Enable web push for THIS app (the one your SDK key belongs to) in the dashboard."):"sw-failed"===this.lastPrepareError?console.warn(`[Joryio SDK] Push not enabled: the service worker failed to register. The VAPID key was fetched OK, so the problem is ${i}: make sure it is hosted on your origin AND its importScripts() points at https://sdk.joryio.com/web/1/joryio-sw.js (a dead URL makes the worker's install throw and registration fail).`):console.warn("[Joryio SDK] Push not enabled: could not prepare web push."),null}null===(i=this.storage)||void 0===i||i.remove(jt);try{const t=await e.registration.pushManager.getSubscription();if(t&&this.subscriptionKeyMatches(t,e.publicKey))return await this.registerWithBackend(t).catch(t=>this.logRegisterFailure(t)),t;t&&(this.logger.info("VAPID key changed - re-subscribing this browser"),await t.unsubscribe().catch(()=>{}));const i=await e.registration.pushManager.subscribe({userVisibleOnly:!0,applicationServerKey:$t(e.publicKey)});return await this.sendPendingUnregister(),await this.registerWithBackend(i).catch(t=>this.logRegisterFailure(t)),this.logger.info("Web push subscribed"),i}catch(t){return"NotAllowedError"===(null==t?void 0:t.name)?(this.logger.info("User denied push permission"),console.warn("[Joryio SDK] Push not enabled: notification permission is denied. The browser will not re-prompt - the user must re-allow notifications for this site in browser settings.")):(this.logger.error("pushManager.subscribe failed:",t),console.warn("[Joryio SDK] Push not enabled: pushManager.subscribe failed:",t)),null}}async unsubscribe(t){var i,e;const s={userId:this.withdrawalUserId()||void 0,anonymousId:this.identity.getAnonymousId()};try{if(null===(i=this.storage)||void 0===i||i.set(jt,!0),null===(e=this.storage)||void 0===e||e.remove(St),!this.isSupported())return!1;const n=await navigator.serviceWorker.getRegistration((null==t?void 0:t.scope)||"/");if(!n)return!1;const r=await n.pushManager.getSubscription();if(!r)return!0;const o=r.endpoint,h=await r.unsubscribe().catch(()=>!1),a=this.pendingUnregisters().filter(t=>t.endpoint!==o);return a.push(Object.assign({endpoint:o},s)),this.storePendingUnregisters(a),await this.sendPendingUnregister(),h}catch(t){return this.logger.warn("Push unsubscribe failed:",t),!1}}async forget(){await this.unsubscribe(),this.prepared=null}pendingUnregisterUsers(){return this.pendingUnregisters().map(t=>t.userId).filter(t=>"string"==typeof t&&!!t)}pendingUnregisters(){var t;const i=null===(t=this.storage)||void 0===t?void 0:t.get(At);return(Array.isArray(i)?i:i?[i]:[]).filter(t=>t&&"string"==typeof t.endpoint&&t.endpoint&&"string"==typeof t.anonymousId)}storePendingUnregisters(t){var i,e;t.length?null===(i=this.storage)||void 0===i||i.set(At,t.slice(-20)):null===(e=this.storage)||void 0===e||e.remove(At)}retryPendingUnregister(){this.sendPendingUnregister().catch(()=>{})}async sendPendingUnregister(){if(!this.unregisterInFlight&&this.canWithdraw()&&("undefined"==typeof navigator||!1!==navigator.onLine)){null!==this.unregisterTimer&&(clearTimeout(this.unregisterTimer),this.unregisterTimer=null),this.unregisterInFlight=!0;try{for(;;){const[t]=this.pendingUnregisters();if(!t)return;const{attempts:i=0,notFoundAttempts:e=0,failures:s=0}=t,n=yt(t,["attempts","notFoundAttempts","failures"]),r=await this.network.request({url:this.apiEndpoint+"/v1/push/unregister",method:"POST",body:Object.assign({platform:"web"},n),subjectUserId:n.userId||null}),o=wt(r,{isSdkAuthError:this.network.isSdkAuthError(r.status,r.data),ownerIsCurrentUser:(n.userId||null)===this.withdrawalUserId()}),h=this.pendingUnregisters().filter(i=>i.endpoint!==t.endpoint);if("done"===o.action||"drop"===o.action){"drop"===o.action&&this.logger.error("Push unregister dropped: "+o.reason),this.storePendingUnregisters(h);continue}if("hold"===o.action)return;const a=Object.assign(Object.assign({},t),{failures:s+1,attempts:i+(o.counts&&!o.notFound?1:0),notFoundAttempts:e+(o.counts&&o.notFound?1:0)});if(!kt(a.attempts,a.notFoundAttempts))return this.storePendingUnregisters([a,...h]),void(this.unregisterTimer=setTimeout(()=>{this.unregisterTimer=null,this.sendPendingUnregister().catch(()=>{})},gt(a.failures,o.retryAfterMs)));this.logger.error("Push unregister failed too many times; dropping it"),this.storePendingUnregisters(h)}}catch(t){this.logger.warn("Failed to notify backend about unsubscribe:",t)}finally{this.unregisterInFlight=!1}}}destroy(){null!==this.unregisterTimer&&clearTimeout(this.unregisterTimer),this.unregisterTimer=null}logRegisterFailure(t){this.logger.warn("This browser is subscribed, but registering it with Joryio failed; it is retried on the next page load:",t)}subscriptionKeyMatches(t,i){var e;try{const s=null===(e=t.options)||void 0===e?void 0:e.applicationServerKey;if(!s)return!0;const n=new Uint8Array(s),r=$t(i);if(n.byteLength!==r.byteLength)return!1;for(let t=0;t<n.byteLength;t++)if(n[t]!==r[t])return!1;return!0}catch(t){return!0}}async fetchVapidPublicKey(){var t,i;if(this.vapidKeyCache)return this.vapidKeyCache;try{const e=await this.network.request({url:this.apiEndpoint+"/v1/push/vapid-public-key",method:"GET"});return e.ok&&(null===(t=e.data)||void 0===t?void 0:t.enabled)&&(null===(i=e.data)||void 0===i?void 0:i.publicKey)?(this.vapidKeyCache=e.data.publicKey,this.vapidKeyCache):null}catch(t){return this.logger.error("Failed to fetch VAPID public key:",t),null}}async registerWithBackend(t){var i,e,s,n;if(!this.canSend())return void this.logger.debug("Push subscription not registered: tracking is off or consent is pending");const r=t.toJSON(),o=this.getDeviceId(),h=Object.assign({platform:"web",subscription:{endpoint:t.endpoint,keys:{p256dh:(null===(i=r.keys)||void 0===i?void 0:i.p256dh)||"",auth:(null===(e=r.keys)||void 0===e?void 0:e.auth)||""}},userId:this.identity.getUserId()||void 0,anonymousId:this.identity.getAnonymousId()},o?{deviceId:o}:{}),a=this.pendingUnregisters();a.some(i=>i.endpoint===t.endpoint)&&this.storePendingUnregisters(a.filter(i=>i.endpoint!==t.endpoint));const u=await this.network.request({url:this.apiEndpoint+"/v1/push/register",method:"POST",body:h,subjectUserId:h.userId||null});if(!u.ok)throw Error("Failed to register subscription: "+(u.error||u.status));null===(s=this.storage)||void 0===s||s.set(St,{endpoint:t.endpoint,userId:null!==(n=h.userId)&&void 0!==n?n:null,anonymousId:h.anonymousId,at:Date.now()})}}function $t(t){const i=(t+"=".repeat((4-t.length%4)%4)).replace(/-/g,"+").replace(/_/g,"/"),e=atob(i),s=new Uint8Array(e.length);for(let t=0;t<e.length;t++)s[t]=e.charCodeAt(t);return s}const Dt="write_outbox",_t="deferred_writes",Tt="write_outbox_removed";function Ct(t){const i=t.payload;return Object.assign({anonymousId:i.anonymousId},i.userId?{userId:i.userId}:{})}function Mt(t){switch(t.kind){case"subscription":return"subscription:"+t.payload.channel;case"group":return`group:${t.payload.groupId}:${t.payload.channel}`;case"marker":return"marker";default:return null}}function xt(t){switch(t.kind){case"alias":return"addAlias";case"subscription":return`Update ${t.payload.channel} subscription`;case"group":return`Subscription group ${t.payload.groupId} ${t.payload.action}`;case"marker":return"The tracking_opted_out marker"}}function Pt(){return"undefined"!=typeof navigator&&!1===navigator.onLine}function Kt(t){return!(!t||"object"!=typeof t||"alias"!==t.kind&&"subscription"!==t.kind&&"group"!==t.kind&&"marker"!==t.kind||!t.payload||"object"!=typeof t.payload||"string"!=typeof t.payload.anonymousId)}function Ft(t){if(!t||!Kt(t.record))return null;const i=t=>Number.isInteger(t)&&t>=0?t:0;return{id:"string"==typeof t.id?t.id:o(),record:t.record,withdrawal:mt(t.record),attempts:i(t.attempts),notFoundAttempts:i(t.notFoundAttempts),failures:i(t.failures),notBefore:0,createdAt:"number"==typeof t.createdAt&&Number.isFinite(t.createdAt)?t.createdAt:0}}class Et{constructor(t){this.deps=t,this.entries=[],this.inFlight=null,this.timer=null,this.stopped=!1,this.handedOffAt=new Map,this.destroyed=!1,this.knownIds=new Set,this.load()}enqueue(t){if(this.destroyed)return;const i={id:o(),record:t,withdrawal:mt(t),attempts:0,notFoundAttempts:0,failures:0,notBefore:0,createdAt:Date.now()};this.knownIds.add(i.id);const e=Mt(t);e&&(this.entries=this.entries.filter(i=>i===this.inFlight||Mt(i.record)!==e||!this.sameOwner(i.record,t))),this.entries.push(i),this.trim(),this.persist(),this.kick()}discardNonWithdrawals(){this.entries=this.entries.filter(t=>t.withdrawal),this.persist({discardNonWithdrawals:!0})}persistNow(){this.persist()}find(t){return this.entries.find(t)}findLast(t){for(let i=this.entries.length-1;i>=0;i--)if(t(this.entries[i]))return this.entries[i]}cancel(t){const i=this.entries.length;this.entries=this.entries.filter(i=>i===this.inFlight||!t(i)),this.entries.length!==i&&this.persist()}pinOwner(t,i){let e=!1;for(const s of this.entries){const n=s.record.payload;n.anonymousId!==t||n.userId||(s.record=Object.assign(Object.assign({},s.record),{payload:Object.assign(Object.assign({},n),{userId:i})}),e=!0)}e&&this.persist()}isInFlight(t){return this.inFlight===t}size(){return this.entries.length}records(){return this.entries.map(t=>t.record)}kick(){if(this.destroyed||this.stopped||this.inFlight)return;if(null!==this.timer&&(clearTimeout(this.timer),this.timer=null),Pt())return;const t=Date.now(),i=new Set;let e=1/0,s=null;for(const n of[...this.entries]){const r=this.blockKey(n);if(i.has(r))continue;const o=this.safeGate(n);if("drop"!==o)if("hold"!==o){if(n.notBefore<=t){s=n;break}i.add(r),e=Math.min(e,n.notBefore)}else i.add(r);else this.remove(n)}s?this.run(s):1/0>e&&(this.timer=setTimeout(()=>{this.timer=null,this.kick()},Math.max(0,e-t)))}handOffAtUnload(t){let i=0;if(!this.deps.keepalive||this.destroyed||this.stopped||Pt())return i;this.persist();const e=Date.now(),s=new Set;this.inFlight&&s.add(this.blockKey(this.inFlight));for(const n of[...this.entries]){const r=this.blockKey(n);if(s.has(r))continue;if(n!==this.inFlight&&this.removedElsewhere(n)){this.deps.logger.debug(xt(n.record)+" not handed off: another tab settled or replaced it");const t=this.entries.indexOf(n);0>t||this.entries.splice(t,1);continue}if(s.add(r),n===this.inFlight||"send"!==this.safeGate(n))continue;const o=this.handedOffAt.get(n.id);if(void 0===o||e-o>=1e4)try{const s=this.deps.keepalive(n,this.deps.resolveOwner(Ct(n.record)));if(null===s)break;if(this.handedOffAt.set(n.id,e),i+=s,i>=t)break}catch(t){break}}return this.persist(),i}destroy(){this.destroyed=!0,null!==this.timer&&clearTimeout(this.timer),this.timer=null}async run(t){this.inFlight=t;const i=xt(t.record);try{if(await this.deps.beforeSend(t).catch(()=>{}),!this.entries.includes(t))return;const e=this.safeGate(t);if("drop"===e)return void this.remove(t);if("hold"===e)return;if(this.removedElsewhere(t))return this.deps.logger.debug(i+" not sent: another tab settled or replaced it"),void this.remove(t);const s=this.deps.resolveOwner(Ct(t.record)),n=await this.deps.send(t,s);if(!this.entries.includes(t))return;const r=wt(n,{isSdkAuthError:this.deps.isSdkAuthError(n.status,n.data),ownerIsCurrentUser:this.deps.ownerIsCurrentUser(s)});switch(r.action){case"done":return void this.settle(t,"done");case"drop":return this.deps.logger.error(`${i} dropped: ${r.reason}`),void this.settle(t,"drop");case"hold":return this.deps.logger.error(`${i} not sent: ${r.reason}; kept for the next page view`),void(this.stopped=!0);case"retry":return this.hasNewerOfSameSubject(t)?void this.remove(t):(t.failures++,r.counts&&(r.notFound?t.notFoundAttempts++:t.attempts++),kt(t.attempts,t.notFoundAttempts)?(this.deps.logger.error(`${i} failed (HTTP ${n.status||"no response"}) too many times; dropping it`),void this.settle(t,"drop")):(t.notBefore=Date.now()+gt(t.failures,r.retryAfterMs),void this.deps.logger.debug(`${i} failed with HTTP ${n.status||"no response"}; retrying`)))}}catch(e){this.deps.logger.error(i+" failed:",e),t.failures++,t.notBefore=Date.now()+gt(t.failures)}finally{this.inFlight===t&&(this.inFlight=null),this.persist(),this.kick()}}safeGate(t){try{return this.deps.gate(t)}catch(t){return"hold"}}settle(t,i){var e,s;this.remove(t);try{null===(s=(e=this.deps).onSettled)||void 0===s||s.call(e,t,i)}catch(t){this.deps.logger.error("Outbox bookkeeping failed:",t)}}remove(t){const i=this.entries.indexOf(t);0>i||(this.entries.splice(i,1),this.persist())}hasNewerOfSameSubject(t){const i=Mt(t.record);if(!i)return!1;const e=this.entries.indexOf(t);return this.entries.slice(e+1).some(e=>Mt(e.record)===i&&this.sameOwner(e.record,t.record))}effectiveUser(t){if(t.userId)return t.userId;const i=this.deps.currentIdentity();return t.anonymousId===i.anonymousId?i.userId:null}sameOwner(t,i){const e=Ct(t),s=Ct(i);return e.anonymousId===s.anonymousId&&this.effectiveUser(e)===this.effectiveUser(s)}blockKey(t){var i;const e=Ct(t.record);return`${null!==(i=Mt(t.record))&&void 0!==i?i:`${t.record.kind}:${t.id}`}|${e.anonymousId}`}trim(){for(;this.entries.length>200;){let t=this.entries.findIndex(t=>!t.withdrawal&&t!==this.inFlight);if(0>t&&(t=this.entries.findIndex(t=>t!==this.inFlight)),0>t)break;const[i]=this.entries.splice(t,1);this.deps.logger.warn(`Too many profile writes waiting; dropped the oldest (${xt(i.record)})`)}}persist(t={}){try{const i=this.deps.storage.get(Dt),e=Array.isArray(i)?i.filter(t=>t&&"string"==typeof t.id).map(t=>t.id):[],s=this.readRemoved();this.entries=this.entries.filter(t=>t===this.inFlight||!s.has(t.id));let n=this.foreignStoredEntries(i).filter(t=>!s.has(t.id));t.discardNonWithdrawals&&(n=n.filter(t=>t.withdrawal));let r=this.entries;if(n.length){const t=[...this.entries,...n].sort((t,i)=>t.createdAt-i.createdAt),i=(i,e)=>{const s=Mt(i.record);return!!s&&i!==this.inFlight&&t.slice(e+1).some(t=>Mt(t.record)===s&&this.sameOwner(t.record,i.record))};for(r=t.filter((t,e)=>!i(t,e));r.length>200;){let t=r.findIndex(t=>!t.withdrawal&&t!==this.inFlight);if(0>t&&(t=r.findIndex(t=>t!==this.inFlight)),0>t)break;this.deps.logger.warn(`Too many profile writes waiting; dropped the oldest (${xt(r[t].record)})`),r=r.filter((i,e)=>e!==t)}this.entries=this.entries.filter(t=>t===this.inFlight||r.includes(t))}const o=r.filter(t=>!s.has(t.id));this.write(o);const h=new Set(o.map(t=>t.id)),a=e.filter(t=>!h.has(t)&&!s.has(t));a.length&&this.writeRemoved(s,a)}catch(t){this.deps.logger.error("Failed to store pending profile writes:",t)}}removedElsewhere(t){try{if(this.readRemoved().has(t.id))return!0;const i=Mt(t.record);if(!i)return!1;const e=this.deps.storage.get(Dt);return!!Array.isArray(e)&&e.some(e=>e&&e.id!==t.id&&Kt(e.record)&&"number"==typeof e.createdAt&&e.createdAt>t.createdAt&&Mt(e.record)===i&&this.sameOwner(e.record,t.record))}catch(t){return!1}}readRemoved(){const t=new Map,i=this.deps.storage.get(Tt);if(!Array.isArray(i))return t;const e=Date.now();for(const s of i)Array.isArray(s)&&"string"==typeof s[0]&&"number"==typeof s[1]&&(e-s[1]>2592e6||t.set(s[0],s[1]));return t}writeRemoved(t,i){const e=Date.now(),s=[...t.entries(),...i.map(t=>[t,e])];this.deps.storage.set(Tt,s.slice(-500))}write(t){t.length?this.deps.storage.set(Dt,t.map(t=>({id:t.id,record:t.record,attempts:t.attempts,notFoundAttempts:t.notFoundAttempts,failures:t.failures,createdAt:t.createdAt}))):this.deps.storage.remove(Dt)}foreignStoredEntries(t){if(!Array.isArray(t))return[];const i=[];for(const e of t){if(!e||"string"!=typeof e.id||this.knownIds.has(e.id)||!Kt(e.record))continue;const t=Ft(e);t&&i.push(t)}return i}load(){const t=this.deps.storage.get(Dt);if(Array.isArray(t))for(const i of t){const t=Ft(i);t&&(this.entries.push(t),this.knownIds.add(t.id))}const i=this.deps.storage.get(_t);if(Array.isArray(i)){for(const t of i){if(!Kt(t))continue;const i={id:o(),record:t,withdrawal:mt(t),attempts:0,notFoundAttempts:0,failures:0,notBefore:0,createdAt:0};this.entries.push(i),this.knownIds.add(i.id)}this.deps.storage.remove(_t),this.trim(),this.persist()}else this.entries.length>200&&(this.trim(),this.persist())}}function Nt(t){const i=[],e=(t,s)=>{switch(typeof t){case"number":return Number.isFinite(t)?null:"a non-finite number (NaN or Infinity)";case"bigint":return"a BigInt";case"function":return"a function";case"symbol":return"a symbol";case"object":if(null===t)return null;if(s>100)return"a value nested deeper than 100 levels";if("function"==typeof t.toJSON)try{return JSON.stringify(t),null}catch(t){return"a value that cannot be serialized"}if(i.includes(t))return"a circular reference";i.push(t);try{const i=Array.isArray(t)?t:Object.values(t);for(const t of i){const i=e(t,s+1);if(i)return i}}finally{i.pop()}return null;default:return null}};try{return e(t,1)}catch(t){return"a value that cannot be serialized"}}function qt(t,i){const e={};for(const s of Object.keys(t)){const n=Nt(t[s]);n?i(s,n):e[s]=t[s]}return e}const Ut="tracking_opted_out",zt="tracking_consent",Rt="tracking_consent_granted_at",Jt="tracking_consent_denied_at",Ht="tracking_opted_out_at",Wt="tracking_opt_in_at",Lt="reported_tracking_opted_out",Bt="tracking_opted_out_marker_given_up",Vt="session_start_sent",Qt="withdrawal_user_id",Gt="retired_sdk_auth_tokens",Xt=[K,F,E,Dt,At,"held_attribute_writes"];function Yt(t,i,e=0){if(t&&"object"==typeof t&&6>=e)if(Array.isArray(t))for(const s of t)Yt(s,i,e+1);else for(const[s,n]of Object.entries(t))"userId"===s&&"string"==typeof n&&n?i.add(n):Yt(n,i,e+1)}const Zt=new WeakMap;function ti(t,i,e){const s=t,n=s.dataGate;s.dataGate=new Set([...n,...i]);try{e()}finally{s.dataGate=n}}const ii="anonymous_id",ei="user_id",si=["jry_sdk_ios_","jry_sdk_android_"],ni="tracking_opted_out",ri="held_attribute_writes",oi="joryio_reported_push_permission",hi="push_permission";class ai{constructor(t,n){if(this.attributeFlushTimer=null,this.attributeFlushInFlight=!1,this.attributeFlushAgain=!1,this.attributeGeneration=0,this.attributeFailures=0,this.t=null,this.isInitialized=!1,this.isOptedOut=!1,this.disabled=!1,this.consentPending=!1,this.userOptedOut=!1,this.dntEnabled=!1,this.trackingConsent="granted",this.lastTrackedUrl=null,this.boundHandlePageUnload=null,this.boundHandleOnline=null,this.boundHandleStorage=null,this.withdrawalUserId=null,this.optedOutAt=0,this.consentDeniedAt=0,this.lastDecisionStamp=0,this.awaitingSessionOf=null,this.pruneTimer=null,this.dataGate=new Set,this.inflightSessionStartAtClear=null,ai.instance)return console.warn("[Joryio] SDK already initialized. Returning existing instance."),ai.instance;const o=t&&"object"==typeof t&&"string"==typeof t.sdkKey&&t.sdkKey?t.sdkKey.startsWith("jry_sdk_")?si.some(i=>t.sdkKey.startsWith(i))?"this is a mobile app key - use the web SDK key (jry_sdk_web_...) from Settings -> Apps":null:"invalid SDK key format, expected jry_sdk_*":"sdkKey is required";o&&(console.error(`[Joryio] SDK not started: ${o}. Calls on this instance are ignored.`),this.disabled=!0),this.config=function(t){var i,n,r,o,h,a,u,d,l,c,p,f,y,m,v,b,g;!function(t){const i=t;for(const[t,e]of Object.entries(s))void 0!==i[t]&&console.warn(`[Joryio] \`${t}\` must be nested under \`${e}\`, not passed at the top level - as written it is IGNORED. Use: { ${e}: { ${t}: ${JSON.stringify(i[t])} } }`);void 0!==i.disablePlugins&&console.warn("[Joryio] `disablePlugins` was removed in 1.3.0 and is ignored - leave a plugin out of `plugins` instead.")}(t);const w={enabled:!1!==(null===(i=t.inApp)||void 0===i?void 0:i.enabled),evaluationMode:"session-start-only"===(null===(n=t.inApp)||void 0===n?void 0:n.evaluationMode)?"session-start-only":"differential-sync",syncInterval:(null===(r=t.inApp)||void 0===r?void 0:r.syncInterval)&&t.inApp.syncInterval>0?Math.max(3e4,t.inApp.syncInterval):0,displayOptions:{defaultPosition:(null===(h=null===(o=t.inApp)||void 0===o?void 0:o.displayOptions)||void 0===h?void 0:h.defaultPosition)||"center",defaultAnimation:(null===(u=null===(a=t.inApp)||void 0===a?void 0:a.displayOptions)||void 0===u?void 0:u.defaultAnimation)||"fade",backdropColor:(null===(l=null===(d=t.inApp)||void 0===d?void 0:d.displayOptions)||void 0===l?void 0:l.backdropColor)||"rgba(0, 0, 0, 0.5)",closeButtonColor:(null===(p=null===(c=t.inApp)||void 0===c?void 0:c.displayOptions)||void 0===p?void 0:p.closeButtonColor)||void 0,zIndex:(null===(y=null===(f=t.inApp)||void 0===f?void 0:f.displayOptions)||void 0===y?void 0:y.zIndex)||999999},allowHtmlJsInAppMessages:!0===(null===(m=t.inApp)||void 0===m?void 0:m.allowHtmlJsInAppMessages),onMessageDisplay:(null===(v=t.inApp)||void 0===v?void 0:v.onMessageDisplay)||(()=>{}),onMessageClick:(null===(b=t.inApp)||void 0===b?void 0:b.onMessageClick)||(()=>{}),onMessageDismiss:(null===(g=t.inApp)||void 0===g?void 0:g.onMessageDismiss)||(()=>{})};return{sdkKey:t.sdkKey,apiEndpoint:e(t.apiEndpoint),userId:t.userId,anonymousId:t.anonymousId||"",batchSize:t.batchSize||50,batchFlushInterval:"number"==typeof t.batchFlushInterval&&t.batchFlushInterval>0?Math.max(1e3,t.batchFlushInterval):5e3,sendImmediately:t.sendImmediately||!1,maxQueueSize:t.maxQueueSize||1e3,sessionTimeout:t.sessionTimeout||18e5,trackSessionStart:!1!==t.trackSessionStart,trackPageViews:!0===t.trackPageViews,captureUTM:!1!==t.captureUTM,resetSessionOnNewCampaign:t.resetSessionOnNewCampaign||!1,trackPageProperties:!1!==t.trackPageProperties,trackDeviceProperties:!1!==t.trackDeviceProperties,inApp:w,persistQueue:!1!==t.persistQueue,maxRetries:"number"!=typeof t.maxRetries||0>t.maxRetries?3:Math.floor(t.maxRetries),retryBackoffMs:t.retryBackoffMs||1e3,requestTimeout:t.requestTimeout&&t.requestTimeout>0?t.requestTimeout:1e4,respectDoNotTrack:!1!==t.respectDoNotTrack,optOut:!0===t.optOut,trackingConsent:"granted"===t.trackingConsent||"denied"===t.trackingConsent||"pending"===t.trackingConsent?t.trackingConsent:void 0,enableSdkAuthentication:!0===t.enableSdkAuthentication,sdkAuthenticationToken:t.sdkAuthenticationToken,enableDebug:t.enableDebug||!1,logLevel:t.logLevel||(t.enableDebug?"debug":"error"),loggingEnabled:!0===t.enableDebug||!!t.logLevel,plugins:t.plugins||[]}}(o?Object.assign(Object.assign({},t&&"object"==typeof t?t:{}),{sdkKey:"jry_sdk_invalid",optOut:!1}):t),this.logger=new at(this.config.loggingEnabled,this.config.logLevel),this.logger.info("Initializing Joryio SDK v"+i),this.storage=new r(this.config.sdkKey,this.logger),this.dntEnabled=this.config.respectDoNotTrack&&this.isDoNotTrackEnabled(),this.dntEnabled&&this.logger.warn("Do Not Track is enabled, SDK will not track events"),this.config.optOut&&this.writeOptOut(),this.userOptedOut=this.config.optOut||this.storedOptOut(),this.userOptedOut&&(this.optedOutAt=this.storedStamp(Ht)),this.trackingConsent=this.initialConsent(this.config.trackingConsent),this.utm=new B(this.storage,this.logger,this.config.resetSessionOnNewCampaign);const h=this.config.resetSessionOnNewCampaign&&this.config.captureUTM&&this.utm.hasNewCampaign();this.session=new c(this.storage,this.logger,this.config.sessionTimeout),h&&(this.logger.info("New campaign detected, resetting session"),this.session.resetSession()),this.identity=new S(this.storage,this.logger,this.config.userId,this.config.anonymousId),this.deviceId=this.getOrCreateDeviceId(),this.queue=new z(this.storage,this.logger,this.config.batchSize,this.config.batchFlushInterval,this.config.persistQueue,this.config.maxQueueSize,this.config.retryBackoffMs),this.network=new P(this.config.sdkKey,this.logger,{maxRetries:this.config.maxRetries,backoffMs:this.config.retryBackoffMs,timeoutMs:this.config.requestTimeout}),this.network.setRetiredTokenStore({load:()=>this.storage.get(Gt),update:t=>{const i=this.storage.get(Gt),e=t(i&&"object"==typeof i&&!Array.isArray(i)?i:{});Object.keys(e).length?this.storage.set(Gt,e):this.storage.remove(Gt)}});const a=this.storage.get(Qt),u="string"==typeof this.config.userId&&this.config.userId?this.config.userId:null;this.withdrawalUserId="string"==typeof a&&a&&a!==this.identity.getUserId()&&!u?a:null,!this.withdrawalUserId&&a&&this.storage.remove(Qt),this.network.setCurrentUserId(this.withdrawalUserId||this.identity.getUserId()),this.config.enableSdkAuthentication&&(this.network.setSdkAuthenticationEnabled(!0),this.config.sdkAuthenticationToken&&this.network.setSdkAuthenticationToken(this.config.sdkAuthenticationToken)),this.outbox=this.createOutbox(),this.inapp=new st(this.config.apiEndpoint,this.config.sdkKey,this.identity,this.session,this.logger,this.storage,Object.assign(Object.assign({closeButton:!0,backdropClose:!0},this.config.inApp.displayOptions),{onDisplay:this.config.inApp.onMessageDisplay,onClick:this.config.inApp.onMessageClick,onDismiss:this.config.inApp.onMessageDismiss}),{logCustomEvent:(t,i)=>this.track(t,i),setCustomUserAttribute:(t,i)=>this.setAttribute(t,i),changeUser:t=>this.identify(t),requestPushPermission:()=>{this.i.subscribe().catch(t=>{this.logger.warn("Push subscribe failed:",t)})},preparePushPermission:()=>{this.i.prepare().catch(t=>{this.logger.warn("Push prepare failed:",t)})}},this.network,{canSend:()=>this.canSend(),requestTimeoutMs:this.config.requestTimeout,syncIntervalMs:this.config.inApp.syncInterval,evaluationMode:this.config.inApp.evaluationMode,noteStatus:(t,i)=>{this.network.noteSuspended(t,i)}}),this.inapp.setAllowHtmlJsInAppMessages(this.config.inApp.allowHtmlJsInAppMessages),this.o=new ot(this.logger,this.network,this.identity,this.config.apiEndpoint,(t,i)=>this.runWrite(t,i)),this.i=new Ot(this.logger,this.network,this.identity,this.config.apiEndpoint,{canSend:()=>this.canSend(),canWithdraw:()=>this.isInitialized&&!this.disabled,withdrawalUserId:()=>this.effectiveUserId(),storage:this.storage,getDeviceId:()=>this.deviceId,onSubscribeSettled:()=>this.reportPushPermissionIfChanged()}),this.queue.setClearedInflightCallback(t=>{const i=this.inflightSessionStartAtClear;i&&(this.inflightSessionStartAtClear=null,t.some(t=>"Session Start"===t.type&&t.sessionId===i)||this.storage.get(Vt)!==i||this.storage.set(Vt,""))}),this.queue.setFlushCallback(async(t,i)=>{try{return await this.flushEvents(t,i)}finally{this.scheduleRetiredTokenPrune()}}),Zt.set(this,{optedOut:this.userOptedOut,consent:this.trackingConsent});for(const t of n||[])this.applyPreInitDecision(t);this.recomputePrivacy(),this.isOptedOut&&this.logger.warn("Tracking is off (opt-out, Do Not Track or consent denied)"),this.queue.setPaused(this.consentPending),this.isOptedOut&&this.queue.clear(),this.restoreAttributeWrites(),this.disabled||"undefined"==typeof window||"function"!=typeof window.addEventListener||(this.boundHandlePageUnload=this.handlePageUnload.bind(this),window.addEventListener("pagehide",this.boundHandlePageUnload),window.addEventListener("beforeunload",this.boundHandlePageUnload),this.boundHandleOnline=()=>{this.queue.resetBackoff(),this.canSend()&&this.queue.flush().catch(t=>this.logger.error("Flush failed:",t)),this.outbox.kick(),this.i.retryPendingUnregister(),!this.identity.pending.isEmpty()&&this.canSend()&&(this.attributeFailures=0,null!==this.attributeFlushTimer&&(clearTimeout(this.attributeFlushTimer),this.attributeFlushTimer=null),this.scheduleAttributeFlush(0))},window.addEventListener("online",this.boundHandleOnline),this.boundHandleStorage=t=>this.handleStorageEvent(t),window.addEventListener("storage",this.boundHandleStorage)),this.disabled||this.loadPlugins().catch(t=>this.logger.error("Plugin load failed:",t)),this.isInitialized=!0,this.disabled||(ai.instance=this),this.logger.info("SDK initialized successfully"),this.reportPushPermissionIfChanged();let d=!1;if(this.session.ensureSession(),this.config.trackSessionStart&&!this.isOptedOut){const t=this.session.getSessionInfo(),i=this.storage.get(Vt),e=null!==i&&i!==t.sessionId;(t.isNewSession||h||e)&&(this.trackSessionStart(),d=!0)}!this.config.trackPageViews||this.isOptedOut||d||(this.trackPageView(),"undefined"!=typeof document&&"loading"===document.readyState&&document.addEventListener("DOMContentLoaded",()=>{this.trackPageView()},{once:!0})),this.session.onNewSession(()=>{this.isOptedOut||(this.config.trackSessionStart&&(this.logger.debug("New session created (mid-visit), tracking session start"),this.trackSessionStart()),this.resyncInApp())}),this.canSend()&&(this.queue.start(),this.config.inApp.enabled&&this.inapp.initialize().catch(t=>{this.logger.error("Failed to initialize in-app messaging:",t)}),this.i.syncExistingSubscription().catch(()=>{}),this.releaseHeldWrites()),this.syncWorkerReporting(),this.isOptedOut||this.releaseDeferredIdentify(),this.syncOptOutMarker(),this.scheduleRetiredTokenPrune(),this.outbox.kick(),this.i.retryPendingUnregister()}createOutbox(){return new Et({storage:this.storage,logger:this.logger,gate:t=>!this.isInitialized||this.disabled?"hold":t.withdrawal?"send":this.network.isSuspended()?"hold":this.isOptedOut?"drop":this.consentPending?"hold":"send",resolveOwner:t=>this.resolveOwner(t),ownerIsCurrentUser:t=>(t.userId||null)===this.effectiveUserId(),currentIdentity:()=>({anonymousId:this.identity.getAnonymousId(),userId:this.effectiveUserId()}),send:(t,i)=>this.sendWrite(t.record,i),beforeSend:()=>this.flushQueueForWrite(),isSdkAuthError:(t,i)=>this.network.isSdkAuthError(t,i),onSettled:(t,i)=>{this.onWriteSettled(t,i),this.scheduleRetiredTokenPrune()},keepalive:(t,i)=>{const e=this.writeRequest(t.record,i),s=JSON.stringify(e.body);return this.network.postKeepalive(e.url,e.body)?I(s)+256:null}})}currentOwner(){const t=this.effectiveUserId();return Object.assign({anonymousId:this.identity.getAnonymousId()},t?{userId:t}:{})}effectiveUserId(){return this.withdrawalUserId||this.identity.getUserId()}deferIdentify(t){t!==this.effectiveUserId()&&(this.network.switchUser(t),this.withdrawalUserId=t===this.identity.getUserId()?null:t,this.withdrawalUserId?this.storage.set(Qt,this.withdrawalUserId):this.storage.remove(Qt),this.logger.debug("Tracking is off: identify kept on this device for withdrawals only, not sent"))}releaseDeferredIdentify(){const t=this.withdrawalUserId;t&&(this.forgetDeferredIdentify(),this.identify(t))}forgetDeferredIdentify(){this.withdrawalUserId=null,this.storage.remove(Qt)}scheduleRetiredTokenPrune(t=0){null!==this.pruneTimer||this.disabled||(this.pruneTimer=setTimeout(()=>{this.pruneTimer=null,this.pruneRetiredTokens()},t))}pruneRetiredTokens(){var t;try{if(!this.network.retiredSdkAuthUsers().length)return;const i=new Set,e=this.network.getCurrentUserId();e&&i.add(e),this.withdrawalUserId&&i.add(this.withdrawalUserId);for(const t of this.queue.getQueuedEvents())t.userId&&i.add(t.userId);for(const t of this.queue.getPendingIdentifies())i.add(t.userId);for(const t of this.outbox.records()){const e=t.payload.userId;"string"==typeof e&&e&&i.add(e)}for(const e of this.identity.pending.serialize())(null===(t=e.owner)||void 0===t?void 0:t.userId)&&i.add(e.owner.userId);for(const t of this.i.pendingUnregisterUsers())i.add(t);for(const t of Xt)Yt(this.storage.get(t),i);const s=this.network.forgetRetiredSdkAuthTokensExcept(i);null!==s&&this.scheduleRetiredTokenPrune(s+50)}catch(t){this.logger.warn("Could not prune stored SDK authentication tokens:",t)}}handleStorageEvent(t){var i;try{if(!this.isInitialized||this.disabled||!t)return;const e=null!==(i=t.key)&&void 0!==i?i:null,s=t=>null===e||e===this.storage.storageKeyFor(t);if(null===e)this.repersistPrivacyDecisions(),this.outbox.persistNow();else if(s(Ut)||s(Ht)||s(Wt)||s(zt)||s(Jt)||s(Rt)){const t=this.storedOptOut(),i=this.storedDenial();t&&(this.optedOutAt=this.storedStamp(Ht)),i&&(this.consentDeniedAt=this.storedStamp(Jt)),this.noteDecisionStamps();let e=!1;t!==this.userOptedOut&&(this.userOptedOut=t,e=!0),i&&"denied"!==this.trackingConsent?(this.trackingConsent="denied",e=!0):i||"denied"!==this.trackingConsent?!i&&"pending"===this.trackingConsent&&s(Rt)&&null!==this.storage.get(Rt)&&(this.trackingConsent="granted",e=!0):(this.trackingConsent="granted",e=!0),e&&this.applyPrivacyState()}if(null!==e&&s(Qt)){const t=this.storage.get(Qt),i="string"==typeof t&&t&&t!==this.identity.getUserId()?t:null;i!==this.withdrawalUserId&&(this.network.switchUser(i||this.identity.getUserId()),this.withdrawalUserId=i)}if(null!==e&&s(a)&&this.awaitingSessionOf&&(this.awaitingSessionOf===this.identity.getAnonymousId()&&this.storage.get(a)&&this.session.followStoredSession(),this.awaitingSessionOf=null),s(ii)||s(ei)){const t=this.storage.get(ii),i=this.storage.get(ei)||null;if(!t)return;if(t===this.identity.getAnonymousId()&&i===this.identity.getUserId())return;this.logger.info("Another tab changed the visitor identity; following it");const e=t!==this.identity.getAnonymousId();this.config.inApp.enabled?this.inapp.clearAll():this.inapp.invalidate(),this.pinAnonymousWrites(),this.network.switchUser(i),this.identity.adopt(t,i),this.withdrawalUserId=null,e&&(this.utm.reset(),this.session.followStoredSession(),this.awaitingSessionOf=t),this.resyncInApp(!0)}}catch(t){this.logger.error("Could not follow a change made in another tab:",t)}}repersistPrivacyDecisions(){this.userOptedOut&&!0!==this.storage.get(Ut)&&this.writeOptOut(this.optedOutAt),"denied"===this.trackingConsent&&"denied"!==this.storage.get(zt)&&this.writeDenial(this.consentDeniedAt),this.withdrawalUserId&&this.storage.get(Qt)!==this.withdrawalUserId&&this.storage.set(Qt,this.withdrawalUserId)}storedStamp(t){const i=this.storage.get(t);return"number"==typeof i&&Number.isFinite(i)?i:0}noteDecisionStamps(){for(const t of[Ht,Wt,Jt,Rt])this.lastDecisionStamp=Math.max(this.lastDecisionStamp,this.storedStamp(t))}nextDecisionStamp(){return this.noteDecisionStamps(),this.lastDecisionStamp=Math.max(Date.now(),this.lastDecisionStamp+1,this.optedOutAt+1,this.consentDeniedAt+1),this.lastDecisionStamp}storedOptOut(){return!0===this.storage.get(Ut)&&!(this.storedStamp(Wt)>this.storedStamp(Ht))}storedDenial(){return"denied"===this.storage.get(zt)&&!(this.storedStamp(Rt)>this.storedStamp(Jt))}writeOptOut(t){const i=void 0===t?this.nextDecisionStamp():t;this.optedOutAt=i,this.storage.set(Ut,!0),this.storage.set(Ht,i)}writeOptIn(){const t=this.nextDecisionStamp();this.optedOutAt=0,this.storage.remove(Ut),this.storage.remove(Ht),this.storage.set(Wt,t)}writeDenial(t){const i=void 0===t?this.nextDecisionStamp():t;this.consentDeniedAt=i,this.storage.set(zt,"denied"),this.storage.set(Jt,i)}writeGrant(){const t=this.nextDecisionStamp();this.consentDeniedAt=0,this.storage.remove(zt),this.storage.remove(Jt),this.storage.set(Rt,t)}resolveOwner(t){if(t.userId)return t;const i=this.effectiveUserId();return i&&t.anonymousId===this.identity.getAnonymousId()?this.queue.getPendingIdentifies().some(i=>i.anonymousId===t.anonymousId)?t:{anonymousId:t.anonymousId,userId:i}:t}pinAnonymousWrites(){const t=this.identity.getUserId();if(!t)return;const i=this.identity.getAnonymousId();this.identity.pending.pinOwner(i,t),this.persistAttributeWrites(),this.outbox.pinOwner(i,t)}writeRequest(t,i){const e=this.config.apiEndpoint,s=Object.assign(Object.assign({},i.userId?{userId:i.userId}:{}),{anonymousId:i.anonymousId});switch(t.kind){case"alias":return{url:e+"/v1/alias/add",body:Object.assign(Object.assign({},t.payload),s)};case"subscription":return{url:e+"/v1/subscriptions/channel",body:Object.assign(Object.assign({},t.payload),s)};case"group":return{url:e+"/v1/subscriptions/group",body:Object.assign(Object.assign({},t.payload),s)};default:return{url:e+"/v1/attributes",body:Object.assign(Object.assign({},i.userId?{userId:i.userId}:{anonymousId:i.anonymousId}),this.markerOps(t))}}}markerOps(t){const i=t.payload.value;return{attributes:{[ni]:i}}}sendWrite(t,i){const e=this.config.apiEndpoint,s=Object.assign(Object.assign({},i.userId?{userId:i.userId}:{}),{anonymousId:i.anonymousId});switch(t.kind){case"alias":return this.network.sendAddAlias(e,Object.assign(Object.assign({},t.payload),s));case"subscription":return this.network.sendSubscriptionUpdate(e,Object.assign(Object.assign({},t.payload),s));case"group":return this.network.sendSubscriptionGroupUpdate(e,Object.assign(Object.assign({},t.payload),s));default:return this.network.sendSetAttributes(e,this.markerOps(t),i.userId,i.anonymousId)}}onWriteSettled(t,i){if("marker"!==t.record.kind)return;const e=t.record.payload.value;"done"===i?(e?this.storage.set(Lt,!0):this.storage.remove(Lt),this.storage.remove(Bt)):this.storage.set(Bt,e),this.syncOptOutMarker()}syncWorkerReporting(){this.disabled||this.i.setTrackingOptedOut(this.isOptedOut||this.consentPending).catch(()=>{})}initialConsent(t){const i=this.storedDenial();return"granted"===t?(this.storage.remove(zt),this.storage.remove(Jt),"granted"):"denied"===t?(this.writeDenial(),"denied"):i?(this.consentDeniedAt=this.storedStamp(Jt),"denied"):"pending"===t?"pending":"granted"}storeConsent(t){return"granted"===t?(this.writeGrant(),"granted"):"denied"===t?(this.writeDenial(),"denied"):this.storedDenial()?(this.logger.info("updateConsent('pending') ignored: consent was denied, and only 'granted' lifts that"),"denied"):"pending"}applyPreInitDecision(t){try{switch(t.method){case"optOut":this.userOptedOut=!0,this.writeOptOut();break;case"optIn":this.userOptedOut=!1,this.writeOptIn();break;case"updateConsent":"granted"!==t.consent&&"denied"!==t.consent&&"pending"!==t.consent||(this.trackingConsent=this.storeConsent(t.consent));break;case"wipeData":this.i.forget().catch(()=>{}),this.wipeLocalState(),this.config.userId&&(this.identity.identify(this.config.userId),this.network.setCurrentUserId(this.config.userId)),this.config.enableSdkAuthentication&&this.config.sdkAuthenticationToken&&this.network.setSdkAuthenticationToken(this.config.sdkAuthenticationToken)}}catch(i){this.logger.error(`Applying ${t.method} from before init failed:`,i)}}getTrackingConsent(){return this.trackingConsent}isUserOptedOut(){return this.userOptedOut}syncOptOutMarker(){if(this.disabled||!this.isInitialized)return;const t=this.userOptedOut,i=!0===this.storage.get(Lt),e=this.identity.getAnonymousId(),s=this.outbox.findLast(t=>"marker"===t.record.kind&&t.record.payload.anonymousId===e);if(s){if("marker"===s.record.kind&&s.record.payload.value===t)return;if(t===i&&!this.outbox.isInFlight(s))return void this.outbox.cancel(t=>"marker"===t.record.kind&&t.record.payload.anonymousId===e)}else{if(t===i)return;if(this.storage.get(Bt)===t)return}this.outbox.enqueue({kind:"marker",payload:Object.assign({value:t},this.currentOwner())})}recomputePrivacy(){this.isOptedOut=this.disabled||this.userOptedOut||this.dntEnabled||"denied"===this.trackingConsent,this.consentPending=!this.isOptedOut&&"pending"===this.trackingConsent}canSend(){return this.isInitialized&&!this.isOptedOut&&!this.consentPending&&!this.network.isSuspended()}applyPrivacyState(){const t=this.isOptedOut,i=this.consentPending;if(this.recomputePrivacy(),this.syncWorkerReporting(),t===this.isOptedOut&&i===this.consentPending||this.inapp.invalidate(),this.isOptedOut){const t=this.session.getSessionId(),i=i=>"Session Start"===i.type&&i.sessionId===t;return this.queue.getWaitingEvents().some(i)?this.storage.set(Vt,""):t&&this.queue.getInflightEvents().some(i)&&(this.inflightSessionStartAtClear=t),this.queue.stop(),this.queue.clear(),this.queue.setPaused(!1),this.clearPendingAttributeWrites(),this.outbox.discardNonWithdrawals(),this.outbox.kick(),void(this.config.inApp.enabled&&this.inapp.stop())}if(t&&this.releaseDeferredIdentify(),t&&this.trackSessionStartIfMissing(),this.consentPending)return this.queue.stop(),this.queue.setPaused(!0),void(this.config.inApp.enabled&&this.inapp.stop());this.queue.setPaused(!1),this.queue.isStarted()||this.queue.start(),this.queue.flush().catch(t=>this.logger.error("Flush failed:",t)),this.releaseHeldWrites(),this.config.inApp.enabled&&this.inapp.initialize().catch(t=>{this.logger.error("Failed to initialize in-app messaging:",t)}),this.i.syncExistingSubscription().catch(()=>{})}releaseHeldWrites(){this.identity.pending.isEmpty()||this.scheduleAttributeFlush(0),this.outbox.kick()}runWrite(t,i){this.isInitialized&&!this.disabled?!this.isOptedOut&&0>=this.dataGate.size||mt(i)?(this.withdrawalUserId&&mt(i)&&i.payload.anonymousId===this.identity.getAnonymousId()&&(i=Object.assign(Object.assign({},i),{payload:Object.assign(Object.assign({},i.payload),{userId:this.withdrawalUserId})})),this.outbox.enqueue(i)):this.logger.debug(t+" not sent: tracking is off"):this.logger.error(t+": SDK not initialized")}restoreAttributeWrites(){const t=this.storage.get(ri);if(this.isOptedOut)return this.storage.remove(ri),void this.outbox.discardNonWithdrawals();t&&"object"==typeof t&&(Array.isArray(t.entries)?this.identity.pending.restore(t.entries):(t.ops&&"object"==typeof t.ops&&this.identity.pending.mark(t.ops),t.increment&&"object"==typeof t.increment&&this.identity.pending.mark({increment:t.increment})))}persistAttributeWrites(){this.identity.pending.isEmpty()?this.storage.remove(ri):this.storage.set(ri,{entries:this.identity.pending.serialize()})}async flushQueueForWrite(){this.canSend()&&(this.queue.getPendingIdentify()||this.queue.getQueueSize()>0)&&await this.queue.flush().catch(()=>{})}trackSessionStart(){this.logger.debug("Tracking session start");const t={};this.config.trackDeviceProperties&&(Object.assign(t,(()=>{var t,i;if("undefined"==typeof window||"undefined"==typeof navigator)return{};const e=navigator.userAgent||"",s=navigator.language||"",n=Array.isArray(navigator.languages)?navigator.languages:void 0;return{$user_agent:e,$timezone:Intl.DateTimeFormat().resolvedOptions().timeZone,$screen_width:null===(t=window.screen)||void 0===t?void 0:t.width,$screen_height:null===(i=window.screen)||void 0===i?void 0:i.height,$viewport_width:window.innerWidth,$viewport_height:window.innerHeight,$language:s,$languages:n,$platform:navigator.platform,$browser:ut(e)}})()),t.$device_id=this.deviceId),"undefined"!=typeof window&&window.location&&(t.landing_page=window.location.href,t.landing_path=window.location.pathname,t.landing_search=window.location.search,t.landing_title="undefined"!=typeof document?document.title:"",t.landing_referrer="undefined"!=typeof document&&document.referrer||null),this.track("Session Start",t),this.storage.set(Vt,this.session.getSessionId())}trackSessionStartIfMissing(){this.config.trackSessionStart&&!this.isOptedOut&&(this.session.ensureSession(),this.storage.get(Vt)!==this.session.getSessionId()&&this.trackSessionStart())}getOrCreateDeviceId(){const t="device_id",i=this.storage.get(t);if(i)return i;const e=o();return this.storage.set(t,e),e}trackPageView(){if("undefined"==typeof window||!window.location)return;const t=window.location.href;if(this.lastTrackedUrl===t)return;const i={url:t,path:window.location.pathname,search:window.location.search,title:"undefined"!=typeof document?document.title:""};this.config.trackPageProperties&&"undefined"!=typeof document&&(i.referrer=document.referrer||null,i.landing_page=this.utm.getSessionLandingPage()||null),this.lastTrackedUrl=t,this.track("Page Viewed",i)}track(t,i){var e;if(this.isInitialized){if(!this.isDroppingDataCalls("track"))if(this.isOptedOut)this.logger.debug("Tracking disabled, event not tracked:",t);else if("string"!=typeof t||1>t.length||t.length>255)this.logger.error("track() needs an event name of 1-255 characters; event dropped");else try{"Session Start"!==t&&this.session.refreshIfExpired(),this.session.ensureSession(),this.session.updateActivity();const s=i&&"object"==typeof i&&!Array.isArray(i)?Object.assign({},i):{};this.config.captureUTM&&Object.assign(s,this.utm.getUTMProperties()),this.deviceId&&!s.$device_id&&(s.$device_id=this.deviceId);let n={eventId:o(),type:t,properties:s,timestamp:(new Date).toISOString(),userId:this.identity.getUserId(),anonymousId:this.identity.getAnonymousId(),sessionId:this.session.getSessionId()};for(const t of this.config.plugins)if(t.beforeTrack){try{n=t.beforeTrack(n)}catch(i){this.logger.error(`Plugin ${t.name} beforeTrack threw; event kept unchanged:`,i)}if(null===n)return void this.logger.debug("Event blocked by plugin: "+t.name)}n&&n.properties&&"object"==typeof n.properties&&(n=Object.assign(Object.assign({},n),{properties:qt(n.properties,(i,e)=>this.logger.warn(`Event "${t}": property "${i}" dropped - ${e}`))}));const r=n&&n.properties&&"object"==typeof n.properties?function(t){const i=Object.keys(t).length;if(i>200)return i+" property keys (the limit is 200)";const e=(t,i)=>i>5||null!==t&&"object"==typeof t&&(Array.isArray(t)?t:Object.values(t)).some(t=>null!==t&&"object"==typeof t&&e(t,i+1));if(e(t,1))return"properties nested deeper than 5 levels";let s;try{s=JSON.stringify(t)}catch(t){return"properties that cannot be serialized (a circular reference?)"}return s.length>51200?s.length+" characters of properties (the limit is 51200)":null}(n.properties):null;if(r)return void this.logger.error(`Event "${t}" dropped: ${r}`);if(this.queue.enqueue(n),this.canSend())try{null===(e=this.inapp)||void 0===e||e.onEventTracked(t,s)}catch(t){this.logger.error("In-app trigger evaluation failed:",t)}for(const t of this.config.plugins)if(t.afterTrack)try{t.afterTrack(n)}catch(i){this.logger.error(`Plugin ${t.name} afterTrack threw:`,i)}this.config.sendImmediately&&this.canSend()&&this.flush().catch(t=>this.logger.error("Immediate flush failed:",t))}catch(t){this.logger.error("track() failed:",t)}}else this.logger.error("SDK not initialized")}identify(t){if(!this.isInitialized)return void this.logger.error("SDK not initialized");if("string"!=typeof t||!t.trim()||t.length>255)return void this.logger.error("identify() needs a userId of 1-255 characters");if(this.isOptedOut)return void(this.disabled||this.deferIdentify(t));this.withdrawalUserId&&this.forgetDeferredIdentify();const i=this.identity.getUserId(),e=this.identity.getAnonymousId();this.queue.setPendingIdentify({userId:t,anonymousId:e,attributes:{}});const s=!!i&&i!==t;s&&(this.pinAnonymousWrites(),this.config.inApp.enabled&&this.inapp.clearAll()),this.identity.identify(t),this.network.switchUser(t),i!==t&&this.inapp.invalidate(),this.canSend()&&this.queue.flush(!1,!0).catch(t=>{this.logger.error("Failed to flush with identify:",t)}).then(()=>{i!==t&&this.resyncInApp(s)})}addAlias(t,i){if(!this.isInitialized)return void this.logger.error("SDK not initialized");if(this.isDroppingDataCalls("addAlias"))return;if("string"!=typeof t||!t.trim()||"string"!=typeof i||!i.trim())return void this.logger.error("addAlias(aliasLabel, aliasName) needs two non-empty strings");const e=this.identity.getUserId(),s=Object.assign(Object.assign({anonymousId:this.identity.getAnonymousId()},e?{userId:e}:{}),{aliasLabel:t,aliasName:i});this.runWrite("addAlias",{kind:"alias",payload:s})}setAttributes(t){if(!this.isInitialized)return void this.logger.error("SDK not initialized");if(this.isDroppingDataCalls("setAttributes"))return;if(!t||"object"!=typeof t||Array.isArray(t))return void this.logger.error('setAttributes requires a plain object, e.g. setAttributes({ email: "user@example.com" })');const i={},e=[];for(const[s,n]of Object.entries(t)){if(!s)continue;if(null==n){e.push(s);continue}const t=Nt(n);t?this.logger.warn(`Attribute "${s}" not set: its value is ${t}`):i[s]=n}this.identity.setAttributes(i);for(const t of e)this.identity.unsetAttribute(t);this.isOptedOut||!Object.keys(i).length&&!e.length||this.sendAttributesAfterPendingIdentify(Object.assign(Object.assign({},Object.keys(i).length?{attributes:i}:{}),e.length?{unset:e}:{}))}sendAttributesAfterPendingIdentify(t){this.identity.pending.mark(t,this.currentOwner()),this.persistAttributeWrites(),this.scheduleAttributeFlush(ai.ATTRIBUTE_FLUSH_DEBOUNCE_MS)}scheduleAttributeFlush(t){null===this.attributeFlushTimer&&(this.attributeFlushTimer=setTimeout(()=>{this.attributeFlushTimer=null,this.canSend()&&this.flushAttributeOps()},t))}clearPendingAttributeWrites(){null!==this.attributeFlushTimer&&(clearTimeout(this.attributeFlushTimer),this.attributeFlushTimer=null),this.identity.pending.clear(),this.attributeGeneration++,this.attributeFlushInFlight=!1,this.attributeFlushAgain=!1,this.attributeFailures=0,this.storage.remove(ri)}flushAttributeOps(){(this.queue.getPendingIdentify()?this.queue.flush(!1,!0).catch(()=>{}):Promise.resolve()).then(()=>{var t;if(!this.canSend())return;if(this.queue.getPendingIdentify())return void this.scheduleAttributeFlush(this.attributeRetryDelay());if(this.attributeFlushInFlight)return void(this.attributeFlushAgain=!0);const i=this.identity.pending.nextRequest(t=>this.resolveOwner(null!=t?t:this.currentOwner()));if(!i)return;this.attributeFlushInFlight=!0;const e=this.attributeGeneration,{ops:s,entries:n}=i,r=this.resolveOwner(null!==(t=i.owner)&&void 0!==t?t:this.currentOwner());this.network.sendSetAttributes(this.config.apiEndpoint,s,r.userId,r.anonymousId).then(t=>{var i,o;if(e!==this.attributeGeneration)return;const h=wt(t,{isSdkAuthError:this.network.isSdkAuthError(t.status,t.data),ownerIsCurrentUser:(r.userId||null)===this.identity.getUserId()});if("done"===h.action){this.attributeFailures=0,this.identity.pending.acknowledge(n),this.persistAttributeWrites();const t=null===(i=s.attributes)||void 0===i?void 0:i[hi];return"string"==typeof t&&this.storage.set(oi,t),this.identity.pending.hasUnsent()&&(this.attributeFlushAgain=!0),void this.scheduleRetiredTokenPrune()}if("drop"===h.action)return this.logger.error("Attributes dropped: "+h.reason,t.error),this.identity.pending.drop(n),this.persistAttributeWrites(),this.identity.pending.hasUnsent()&&(this.attributeFlushAgain=!0),void this.scheduleRetiredTokenPrune();const a=!(t.softFailure||0!==t.status&&500>t.status),u=this.identity.pending.release(n,a);if(u>0&&this.logger.error(`Failed to send attributes (HTTP ${t.status||"no response"}); ${u} increment(s) are LOST (an $inc cannot be safely retried).`),"hold"===h.action)return this.persistAttributeWrites(),void this.logger.error(`Attributes not sent: ${h.reason}; they are kept for the next page view.`);if(h.counts){const i=n.filter(t=>(t.attempts=(t.attempts||0)+1,t.attempts>=10));i.length&&(this.logger.error(`Attributes failed (HTTP ${t.status}) too many times; dropping them`),this.identity.pending.drop(i))}this.persistAttributeWrites(),this.logger.warn(`Failed to send attributes (HTTP ${t.status||"no response"}); will retry`),this.attributeFailures++,this.scheduleAttributeFlush(Math.max(this.attributeRetryDelay(),Math.min(null!==(o=h.retryAfterMs)&&void 0!==o?o:0,3e5)))}).then(()=>{e===this.attributeGeneration&&(this.attributeFlushInFlight=!1,this.attributeFlushAgain&&(this.attributeFlushAgain=!1,this.flushAttributeOps()))}).catch(t=>{e===this.attributeGeneration&&(this.attributeFlushInFlight=!1),this.logger.error("Attribute flush bookkeeping failed:",t)})})}attributeRetryDelay(){const t=Math.max(1,this.attributeFailures);return Math.min(5e3*Math.pow(2,t-1),3e5)}reportPushPermissionIfChanged(){if(this.isInitialized&&!this.isOptedOut)try{const t=this.i.getPermissionState(),i="notDetermined"===t?"not_determined":t;if(this.storage.get(oi)===i)return;this.logger.debug(`Push permission changed to ${i}; reporting`),this.setAttribute(hi,i)}catch(t){this.logger.warn("Could not report push permission:",t)}}setAttribute(t,i){"string"==typeof t&&t?this.setAttributes({[t]:i}):this.logger.error("setAttribute(key, value) needs a non-empty key")}incrementAttribute(t,i=1){this.isInitialized?this.isDroppingDataCalls("incrementAttribute")||("string"==typeof t&&t&&"number"==typeof i&&Number.isFinite(i)?(this.identity.incrementAttribute(t,i),this.isOptedOut||this.sendAttributesAfterPendingIdentify({increment:{[t]:i}})):this.logger.error("incrementAttribute(key, value) needs a key and a finite number")):this.logger.error("SDK not initialized")}unsetAttribute(t){this.isInitialized?this.isDroppingDataCalls("unsetAttribute")||("string"==typeof t&&t?(this.identity.unsetAttribute(t),this.isOptedOut||this.sendAttributesAfterPendingIdentify({unset:[t]})):this.logger.error("unsetAttribute() needs a non-empty attribute key")):this.logger.error("SDK not initialized")}addToArray(t,i){if(!this.isInitialized)return void this.logger.error("SDK not initialized");if(this.isDroppingDataCalls("addToArray"))return;if("string"!=typeof t||!t)return void this.logger.error("addToArray() needs a non-empty attribute key");const e=Nt(i);e?this.logger.warn(`addToArray("${t}") ignored: the value is ${e}`):(this.identity.addToArray(t,i),this.isOptedOut||this.sendAttributesAfterPendingIdentify({append:{[t]:i}}))}removeFromArray(t,i){if(!this.isInitialized)return void this.logger.error("SDK not initialized");if(this.isDroppingDataCalls("removeFromArray"))return;if("string"!=typeof t||!t)return void this.logger.error("removeFromArray() needs a non-empty attribute key");const e=Nt(i);e?this.logger.warn(`removeFromArray("${t}") ignored: the value is ${e}`):(this.identity.removeFromArray(t,i),this.isOptedOut||this.sendAttributesAfterPendingIdentify({remove:{[t]:i}}))}async reset(){this.isInitialized?(this.logger.info("Resetting user identity"),this.config.inApp.enabled&&this.inapp.clearAll(),this.network.retireSdkAuthToken(),this.forgetDeferredIdentify(),this.pinAnonymousWrites(),this.identity.reset(),this.network.setCurrentUserId(this.identity.getUserId()),this.utm.reset(),this.session.resetSession(),await this.flush().catch(()=>{}),this.canSend()&&(this.resyncInApp(!0),this.i.syncExistingSubscription(!0).catch(()=>{})),this.outbox.kick(),this.logger.info("User identity reset")):this.logger.error("SDK not initialized")}async wipeData(){if(!this.isInitialized)return void this.logger.error("SDK not initialized");this.logger.info("Wiping local SDK data");const t=this.i.forget().catch(()=>{});this.wipeLocalState(),this.session.ensureSession(),this.trackSessionStartIfMissing(),await t,this.canSend()&&this.resyncInApp(!0),this.logger.info("Local SDK data wiped")}wipeLocalState(){this.clearPendingAttributeWrites(),this.outbox.discardNonWithdrawals(),this.storage.remove(oi),this.storage.set(Vt,""),this.queue.clear(),this.config.inApp.enabled?this.inapp.clearAll():this.inapp.invalidate(),this.inapp.forgetImpressions();const t=new Set;for(const i of[this.effectiveUserId(),this.identity.getUserId(),this.network.getCurrentUserId()])i&&t.add(i);for(const i of this.outbox.records()){const e=i.payload.userId;"string"==typeof e&&e&&t.add(e)}for(const i of this.i.pendingUnregisterUsers())t.add(i);for(const i of[Dt,At])Yt(this.storage.get(i),t);this.network.retireSdkAuthToken(),this.network.dropStandbySdkAuthTokens(t),this.forgetDeferredIdentify(),this.pinAnonymousWrites(),this.identity.reset(),this.network.setCurrentUserId(null),this.utm.reset(),this.session.clear(),this.lastTrackedUrl=null,this.storage.remove("device_id"),this.deviceId=this.getOrCreateDeviceId()}resyncInApp(t=!1){this.config.inApp.enabled&&this.canSend()&&(t?this.inapp.initialize():this.inapp.sync().then(()=>{})).catch(t=>this.logger.debug("In-app re-sync failed:",t))}async flush(){this.isInitialized?await this.queue.flush(!1,!0):this.logger.error("SDK not initialized")}async flushEvents(t,i){var e,s,n,r;if(!this.canSend())return{status:"retry"};this.logger.debug(`Sending ${t.length} events${i?" + identify":""} to backend`);const o=await this.network.sendEvents(this.config.apiEndpoint,t,i);if(o.ok||o.softFailure){const h=Array.isArray(null===(e=o.data)||void 0===e?void 0:e.rejectedIndices)?o.data.rejectedIndices:void 0;let a=!1,u=!1,d=!0;if(i&&!(null===(s=o.data)||void 0===s?void 0:s.identified)&&o.softFailure)a=!0;else if(i&&!(null===(n=o.data)||void 0===n?void 0:n.identified)){this.logger.debug("Backend did not confirm atomic identify, falling back to standalone");const t=await this.network.sendIdentify(this.config.apiEndpoint,i.userId,i.attributes||{},i.anonymousId);if(!t.ok){const e=!(t.softFailure||0!==t.status&&408!==t.status&&429!==t.status&&500>t.status);!0===t.softFailure||e||401===t.status&&this.network.isSdkAuthError(t.status,t.data)&&i.userId===this.identity.getUserId()||402===t.status?(this.logger.error("Standalone identify fallback failed; it is kept and retried:",t.error),a=!0,d=!e&&402!==t.status):(this.logger.error(`Standalone identify fallback refused (HTTP ${t.status}); dropping it:`,t.error),u=!0)}}return o.softFailure?{status:"ok",failedIndices:Array.isArray(null===(r=o.data)||void 0===r?void 0:r.failedIndices)?o.data.failedIndices:t.map((t,i)=>i),rejectedIndices:h,identifyFailed:a,identifyAttemptCounts:d,identifyDropped:u}:(this.logger.debug("Events sent successfully"),{status:"ok",rejectedIndices:h,identifyFailed:a,identifyAttemptCounts:d,identifyDropped:u})}return this.classifyFailure(o,t,i)}classifyFailure(t,i=[],e){var s,n;const r=t.status;if(400===r||413===r||422===r)return{status:"rejected",httpStatus:r};if(401===r){if(this.network.isSdkAuthError(r,t.data)){const r=null===(s=t.data)||void 0===s?void 0:s.reason,o=(null==e?void 0:e.userId)||(null===(n=i.find(t=>t.userId))||void 0===n?void 0:n.userId)||null;return o&&o!==this.identity.getUserId()?{status:"dropped",reason:"401 "+(r||"sdk_authentication_error")}:{status:"retry",counts:!0}}return{status:"suspended",reason:"the SDK key was refused (401)"}}return 402===r?{status:"suspended",reason:"event ingestion is paused for this workspace (402)"}:403===r?{status:"suspended",reason:"the request was forbidden (403)"}:0!==r&&408!==r&&429!==r&&500>r?{status:"suspended",reason:"the API answered HTTP "+r}:{status:"retry",retryAfterMs:t.retryAfterMs}}handlePageUnload(){if(this.isInitialized)if("undefined"==typeof navigator||!1!==navigator.onLine){try{this.outbox.handOffAtUnload(8192)}catch(t){this.logger.error("Page-unload write hand-off failed:",t)}if(!this.canSend()||this.queue.isSuspended()||this.queue.isBackingOff())this.queue.persistNow();else try{this.sendAttributesAtUnload();const t=Math.max(0,this.network.keepaliveBudget()-256),i=this.queue.getQueuedEvents(),e=this.queue.getPendingIdentify();if(0===i.length&&!e)return;if(!this.network.supportsKeepalive())return void this.queue.persistNow();const s=i[0],n=!e||s&&(s.anonymousId!==e.anonymousId||s.userId&&s.userId!==e.userId)?null:e;let r=64+(n?I(JSON.stringify(n)):0);const o=[];let h=null;for(const e of i){if(s&&e.anonymousId!==s.anonymousId)break;if(e.userId&&h&&e.userId!==h)break;if(n&&(e.anonymousId!==n.anonymousId||e.userId&&e.userId!==n.userId))break;const i=I(JSON.stringify(e))+1;if(r+i>t)break;o.push(e),e.userId&&(h=e.userId),r+=i}if(0===o.length&&!n)return void this.queue.persistNow();this.logger.debug(`Page unload: handing ${o.length} of ${i.length} events${n?" + identify":""} to keepalive`);const a=this.network.sendEventsKeepalive(this.config.apiEndpoint,o,n||void 0);if(!a)return void this.queue.persistNow();this.queue.markHandedOff(o,n),a.then(t=>{t.ok||!t.softFailure&&0!==t.status&&429!==t.status&&500>t.status||this.queue.takeBack(o,n)}).catch(()=>{})}catch(t){this.logger.error("Page-unload send failed:",t),this.queue.persistNow()}}else this.queue.persistNow()}sendAttributesAtUnload(){var t;if(this.queue.getPendingIdentify())return 0;const i=this.identity.pending.peekRequest(t=>this.resolveOwner(null!=t?t:this.currentOwner()));if(!i||!this.network.supportsKeepalive())return 0;try{const e=this.resolveOwner(null!==(t=i.owner)&&void 0!==t?t:this.currentOwner()),s=Object.assign({userId:e.userId||void 0,anonymousId:e.userId?void 0:e.anonymousId},i.ops),n=this.network.postKeepalive(this.config.apiEndpoint+"/v1/attributes",s);return n?(n.catch(()=>{}),this.identity.pending.dropIncrements(i.entries),this.persistAttributeWrites(),I(JSON.stringify(s))+256):0}catch(t){return 0}}optOut(){this.isInitialized?(this.logger.info("User opted out of tracking"),this.userOptedOut=!0,this.writeOptOut(),this.storage.remove(Bt),this.syncOptOutMarker(),this.applyPrivacyState()):this.logger.error("SDK not initialized")}optIn(){this.isInitialized?(this.logger.info("User opted in to tracking"),this.userOptedOut=!1,this.liftDataGate("optedOut"),this.writeOptIn(),this.applyPrivacyState(),this.storage.remove(Bt),this.syncOptOutMarker()):this.logger.error("SDK not initialized")}updateConsent(t){this.isInitialized?"granted"===t||"denied"===t||"pending"===t?(this.trackingConsent=this.storeConsent(t),this.config.trackingConsent=this.trackingConsent,"granted"===t&&this.liftDataGate("denied"),this.applyPrivacyState(),this.syncOptOutMarker()):this.logger.error("updateConsent expects 'granted', 'denied' or 'pending', got "+t):this.logger.error("SDK not initialized")}isDoNotTrackEnabled(){if("undefined"==typeof window||"undefined"==typeof navigator)return!1;const t=navigator.doNotTrack||window.doNotTrack||navigator.msDoNotTrack;return"1"===t||"yes"===t}async loadPlugins(){for(const t of this.config.plugins)try{this.logger.debug(`Loading plugin: ${t.name} v${t.version}`),await t.load(this),this.logger.info("Plugin loaded: "+t.name)}catch(i){this.logger.error(`Failed to load plugin ${t.name}:`,i)}}async unloadPlugins(){for(const t of this.config.plugins)try{this.logger.debug("Unloading plugin: "+t.name),await t.unload()}catch(i){this.logger.error(`Failed to unload plugin ${t.name}:`,i)}}get user(){var t;return this.isInitialized||null===(t=this.logger)||void 0===t||t.error("SDK not initialized"),this.o}get push(){var t;return this.isInitialized||null===(t=this.logger)||void 0===t||t.error("SDK not initialized"),this.i}ecommerce(t){var i;return this.isInitialized||null===(i=this.logger)||void 0===i||i.error("SDK not initialized"),this.t&&!t||(this.t=ft(this,t,this.logger)),this.t}setSdkAuthenticationToken(t){var i;this.isInitialized?this.config.enableSdkAuthentication?this.network.setSdkAuthenticationToken(t):this.logger.warn("setSdkAuthenticationToken called but enableSdkAuthentication is false - ignoring"):null===(i=this.logger)||void 0===i||i.error("SDK not initialized")}setSdkAuthenticationErrorCallback(t){var i;this.isInitialized?this.network.setSdkAuthenticationFailureCallback(t):null===(i=this.logger)||void 0===i||i.error("SDK not initialized")}getAnonymousId(){return this.identity?this.identity.getAnonymousId():""}getUserId(){return this.identity?this.identity.getUserId():null}liftDataGate(t){if(!this.dataGate.has(t))return;const i=new Set(this.dataGate);i.delete(t),this.dataGate=i}isDroppingDataCalls(t){return 0!==this.dataGate.size&&(this.logger.debug(t+"() in a ready() callback queued while tracking was off: dropped"),!0)}ready(t){if("function"==typeof t)try{t(this)}catch(t){this.logger.error("Error in ready() callback:",t)}else this.logger.error("ready(callback) requires a function")}getIdentity(){return this.identity.getIdentity()}getSessionInfo(){return this.session.getSessionInfo()}getUTMData(){return this.utm.getUTMData()}updateUTM(){this.isInitialized?(this.utm.updateUTM(),this.config.resetSessionOnNewCampaign&&this.utm.hasNewCampaign()&&(this.logger.info("New campaign detected, resetting session"),this.session.resetSession())):this.logger.error("SDK not initialized")}async syncInAppCampaigns(t){if(this.isInitialized)if(this.config.inApp.enabled)if(this.canSend())try{await this.inapp.sync(t)}catch(t){this.logger.error("In-app sync failed:",t)}else this.logger.debug("Tracking disabled or consent pending, not syncing in-app campaigns");else this.logger.warn("In-app messaging is not enabled");else this.logger.error("SDK not initialized")}getInAppCampaigns(){return this.isInitialized?this.config.inApp.enabled?this.inapp.getCampaigns():[]:(this.logger.error("SDK not initialized"),[])}async displayInAppCampaign(t){if(!this.isInitialized)return void this.logger.error("SDK not initialized");if(!this.config.inApp.enabled)return void this.logger.warn("In-app messaging is not enabled");if(!this.canSend())return void this.logger.debug("Tracking disabled or consent pending, not displaying in-app campaign");const i=this.inapp.getCampaigns().find(i=>i.id===t);if(i)try{await this.inapp.displayCampaign(i)}catch(t){this.logger.error("In-app display failed:",t)}else this.logger.error(`Campaign ${t} not found`)}dismissInAppMessage(t){this.isInitialized?this.config.inApp.enabled&&this.inapp.dismiss(t).catch(t=>this.logger.error("In-app dismiss failed:",t)):this.logger.error("SDK not initialized")}async trackInAppConversion(t,i){if(this.isInitialized){if(!this.isDroppingDataCalls("trackInAppConversion"))if(this.config.inApp.enabled)if(this.canSend())try{await this.inapp.trackConversion(t,i)}catch(t){this.logger.error("In-app conversion failed:",t)}else this.logger.debug("Tracking disabled or consent pending, not tracking in-app conversion");else this.logger.warn("In-app messaging is not enabled")}else this.logger.error("SDK not initialized")}async destroy(){this.isInitialized&&(this.logger.info("Destroying SDK instance"),null!==this.attributeFlushTimer&&(clearTimeout(this.attributeFlushTimer),this.attributeFlushTimer=null,this.canSend()&&this.flushAttributeOps()),this.outbox.destroy(),this.i.destroy(),"undefined"!=typeof window&&"function"==typeof window.removeEventListener&&(this.boundHandlePageUnload&&(window.removeEventListener("pagehide",this.boundHandlePageUnload),window.removeEventListener("beforeunload",this.boundHandlePageUnload)),this.boundHandleOnline&&window.removeEventListener("online",this.boundHandleOnline),this.boundHandleStorage&&window.removeEventListener("storage",this.boundHandleStorage)),this.boundHandlePageUnload=null,this.boundHandleOnline=null,this.boundHandleStorage=null,null!==this.pruneTimer&&(clearTimeout(this.pruneTimer),this.pruneTimer=null),await this.queue.flush().catch(()=>{}),this.queue.stop(),await this.unloadPlugins(),this.session.destroy(),this.inapp.clearAll(),this.inapp.destroy(),this.isInitialized=!1,ai.instance===this&&(ai.instance=null),this.logger.info("SDK destroyed"))}static getInstance(){return ai.instance}}ai.instance=null,ai.ATTRIBUTE_FLUSH_DEBOUNCE_MS=800;const ui=["init","optOut","optIn","updateConsent","wipeData"],di=["track","setAttributes","setAttribute","incrementAttribute","unsetAttribute","addToArray","removeFromArray","addAlias","trackInAppConversion"];function li(t){var i,e;try{const s=t&&t.joryio;if(!Array.isArray(s))return;const n=s.find(t=>Array.isArray(t)&&"init"===t[0]);if(!n){if(s.__joryioWaitingForInit)return;return s.__joryioWaitingForInit=!0,void(s.push=function(...i){for(let t=s.length+i.length-1e3;t>0;t--){const t=s.findIndex(t=>!(Array.isArray(t)&&ui.includes(t[0])));if(0>t)break;s.splice(t,1)}const e=Array.prototype.push.apply(s,i);return i.some(t=>Array.isArray(t)&&"init"===t[0])&&li(t),e})}const r=s.slice(),o=r.indexOf(n),h=[],a=new Set;r.forEach((t,i)=>{if(!Array.isArray(t))return;const[e,s]=t;if("optOut"===e||"optIn"===e)h.push({method:e});else if("updateConsent"===e)h.push({method:e,consent:s});else{if("wipeData"!==e||i>=o)return;h.push({method:e})}a.add(t)});let u=null;try{u=new ai(n[1],h)}catch(t){console.error("[Joryio] init failed:",t)}if(!u||ai.getInstance()!==u){const i=s.indexOf(n);return 0>i||s.splice(i,1),s.__joryioWaitingForInit=!1,void li(t)}const d=new Map,l=function(t,i,e=t.length,s=new Map){const n=new Set,r=(t,i)=>{n.add(t);const e=s.get(t)||new Set;e.add(i),s.set(t,e)};let o=!!(null==i?void 0:i.optedOut),h=(null==i?void 0:i.consent)||"granted";const a=[],u=(t=!1)=>{const i=a.filter(i=>t&&"ready"===i[0]);a.forEach(t=>{i.includes(t)||r(t,"purged")}),a.length=0,a.push(...i)};return t.forEach((t,i)=>{if(!Array.isArray(t))return;const[s,n]=t;"optOut"===s?(o=!0,u()):"optIn"===s?o=!1:"updateConsent"===s?("granted"===n||"denied"===n?h=n:"pending"===n&&"denied"!==h&&(h="pending"),"denied"===n&&u()):"wipeData"===s&&e>i?u(!0):(di.includes(s)||"ready"===s)&&(o&&r(t,"optedOut"),"denied"===h&&r(t,"denied"),o||"denied"===h||a.push(t))}),n}(r,Zt.get(u),o,d);t.joryio=u;for(const t of r){if(!Array.isArray(t)||a.has(t))continue;const[s,...n]=t;if("init"===s)continue;const r=l.has(t);if(r&&"ready"!==s){null===(e=null===(i=u.logger)||void 0===i?void 0:i.debug)||void 0===e||e.call(i,s+" queued before load dropped: tracking was off when it was called");continue}const o=u[s];if("function"==typeof o)try{let i;r?ti(u,d.get(t)||[],()=>i=o.apply(u,n)):i=o.apply(u,n),i&&"function"==typeof i.catch&&i.catch(t=>{console.error(`[Joryio] Error executing ${s+""}:`,t)})}catch(t){console.error(`[Joryio] Error executing ${s+""}:`,t)}else console.warn("[Joryio] Unknown method queued before load: "+s)}}catch(t){console.error("[Joryio] Could not process the snippet queue:",t)}}"undefined"!=typeof window&&(window.Joryio=ai,li(window)),t.EcommerceTracker=pt,t.JoryioSDK=ai,t.PushManager=Ot,t.SDK_VERSION=i,t.User=ot,t.createEcommerceTracker=ft,t.default=ai,t.installSnippetQueue=li,Object.defineProperty(t,"__esModule",{value:!0})});
|
|
7
7
|
//# sourceMappingURL=joryio.min.js.map
|