@gojek/clickstream-web
Version:
A Modern, Fast, and Lightweight Event Ingestion library for Web
2 lines (1 loc) • 25.8 kB
JavaScript
import*as e from"protobufjs/minimal.js";function t(e,t){return function(e,t){if(t.get)return t.get.call(e);return t.value}(e,i(e,t,"get"))}function n(e,t,n){return function(e,t,n){if(t.set)t.set.call(e,n);else{if(!t.writable)throw new TypeError("attempted to set read only private field");t.value=n}}(e,i(e,t,"set"),n),n}function i(e,t,n){if(!t.has(e))throw new TypeError("attempted to "+n+" private field on non-instance");return t.get(e)}function s(e,t,n){if(!t.has(e))throw new TypeError("attempted to get private field on non-instance");return n}function r(e,t){if(t.has(e))throw new TypeError("Cannot initialize the same private elements twice on an object")}function o(e,t,n){r(e,t),t.set(e,n)}function a(e,t){r(e,t),t.add(e)}const c={event:{classification:{instant:[]},group:""},batch:{maxTimeBetweenTwoBatches:10,maxBatchSize:5e4,dbName:"clickstream_db"},network:{url:"",headers:new Headers({}),maxRetries:5,timeBetweenTwoRetries:1e3,timeToResumeRetries:2e4},crypto:null},u="instant",h="realTime",l="batchCreated",d="batchFailed",p={CLICKSTREAM_ERROR:"clickstreamError",VALIDATION_ERROR:"validationError",DATABASE_ERROR:"databaseError",NETWORK_ERROR:"networkError",TRACKING_ERROR:"trackingError",CLEANUP_ERROR:"cleanupError"},w="Clickstream Error",f="Validation Error",v="Database Error",g="Network Error",m="Cleanup Error";class b extends Error{constructor(e,t){super(e,t),this.name=t?.name??w,this.code=t?.code??p.CLICKSTREAM_ERROR}}class y extends b{constructor(e,t){super(e,t),this.name=f,this.code=p.VALIDATION_ERROR}}class k extends b{constructor(e,t){super(e,t),this.name=v,this.code=p.DATABASE_ERROR}}class S extends b{constructor(e,t){super(e,t),this.name=g,this.code=p.NETWORK_ERROR}}let T;e.default&&(T=e.default);const R=T.Reader,E=T.Writer,O=T.util,B=T.roots.default||(T.roots.default={});B.EventService=(()=>{function e(e,t,n){T.rpc.Service.call(this,e,t,n)}return(e.prototype=Object.create(T.rpc.Service.prototype)).constructor=e,e.create=function(e,t,n){return new this(e,t,n)},Object.defineProperty(e.prototype.sendEvent=function e(t,n){return this.rpcCall(e,B.SendEventRequest,B.SendEventResponse,t,n)},"name",{value:"SendEvent"}),e})();const W=B.SendEventRequest=(()=>{function e(e){if(this.events=[],e)for(let t=Object.keys(e),n=0;n<t.length;++n)null!=e[t[n]]&&(this[t[n]]=e[t[n]])}return e.prototype.reqGuid="",e.prototype.sentTime=null,e.prototype.events=O.emptyArray,e.create=function(t){return new e(t)},e.encode=function(e,t){if(t||(t=E.create()),null!=e.reqGuid&&Object.hasOwnProperty.call(e,"reqGuid")&&t.uint32(10).string(e.reqGuid),null!=e.sentTime&&Object.hasOwnProperty.call(e,"sentTime")&&B.Timestamp.encode(e.sentTime,t.uint32(18).fork()).ldelim(),null!=e.events&&e.events.length)for(let n=0;n<e.events.length;++n)B.Event.encode(e.events[n],t.uint32(26).fork()).ldelim();return t},e.decode=function(e,t){e instanceof R||(e=R.create(e));let n=void 0===t?e.len:e.pos+t,i=new B.SendEventRequest;for(;e.pos<n;){let t=e.uint32();switch(t>>>3){case 1:i.reqGuid=e.string();break;case 2:i.sentTime=B.Timestamp.decode(e,e.uint32());break;case 3:i.events&&i.events.length||(i.events=[]),i.events.push(B.Event.decode(e,e.uint32()));break;default:e.skipType(7&t)}}return i},e.verify=function(e){if("object"!=typeof e||null===e)return"object expected";if(null!=e.reqGuid&&e.hasOwnProperty("reqGuid")&&!O.isString(e.reqGuid))return"reqGuid: string expected";if(null!=e.sentTime&&e.hasOwnProperty("sentTime")){let t=B.Timestamp.verify(e.sentTime);if(t)return"sentTime."+t}if(null!=e.events&&e.hasOwnProperty("events")){if(!Array.isArray(e.events))return"events: array expected";for(let t=0;t<e.events.length;++t){let n=B.Event.verify(e.events[t]);if(n)return"events."+n}}return null},e.getTypeUrl=function(e){return void 0===e&&(e="type.googleapis.com"),e+"/SendEventRequest"},e})();B.Timestamp=(()=>{function e(e){if(e)for(let t=Object.keys(e),n=0;n<t.length;++n)null!=e[t[n]]&&(this[t[n]]=e[t[n]])}return e.prototype.seconds=O.Long?O.Long.fromBits(0,0,!1):0,e.prototype.nanos=0,e.create=function(t){return new e(t)},e.encode=function(e,t){return t||(t=E.create()),null!=e.seconds&&Object.hasOwnProperty.call(e,"seconds")&&t.uint32(8).int64(e.seconds),null!=e.nanos&&Object.hasOwnProperty.call(e,"nanos")&&t.uint32(16).int32(e.nanos),t},e.decode=function(e,t){e instanceof R||(e=R.create(e));let n=void 0===t?e.len:e.pos+t,i=new B.Timestamp;for(;e.pos<n;){let t=e.uint32();switch(t>>>3){case 1:i.seconds=e.int64();break;case 2:i.nanos=e.int32();break;default:e.skipType(7&t)}}return i},e.verify=function(e){return"object"!=typeof e||null===e?"object expected":null!=e.seconds&&e.hasOwnProperty("seconds")&&!(O.isInteger(e.seconds)||e.seconds&&O.isInteger(e.seconds.low)&&O.isInteger(e.seconds.high))?"seconds: integer|Long expected":null!=e.nanos&&e.hasOwnProperty("nanos")&&!O.isInteger(e.nanos)?"nanos: integer expected":null},e.getTypeUrl=function(e){return void 0===e&&(e="type.googleapis.com"),e+"/Timestamp"},e})();const j=B.Event=(()=>{function e(e){if(e)for(let t=Object.keys(e),n=0;n<t.length;++n)null!=e[t[n]]&&(this[t[n]]=e[t[n]])}return e.prototype.eventBytes=O.newBuffer([]),e.prototype.type="",e.create=function(t){return new e(t)},e.encode=function(e,t){return t||(t=E.create()),null!=e.eventBytes&&Object.hasOwnProperty.call(e,"eventBytes")&&t.uint32(10).bytes(e.eventBytes),null!=e.type&&Object.hasOwnProperty.call(e,"type")&&t.uint32(18).string(e.type),t},e.decode=function(e,t){e instanceof R||(e=R.create(e));let n=void 0===t?e.len:e.pos+t,i=new B.Event;for(;e.pos<n;){let t=e.uint32();switch(t>>>3){case 1:i.eventBytes=e.bytes();break;case 2:i.type=e.string();break;default:e.skipType(7&t)}}return i},e.verify=function(e){return"object"!=typeof e||null===e?"object expected":null!=e.eventBytes&&e.hasOwnProperty("eventBytes")&&!(e.eventBytes&&"number"==typeof e.eventBytes.length||O.isString(e.eventBytes))?"eventBytes: buffer expected":null!=e.type&&e.hasOwnProperty("type")&&!O.isString(e.type)?"type: string expected":null},e.getTypeUrl=function(e){return void 0===e&&(e="type.googleapis.com"),e+"/Event"},e})(),P=B.SendEventResponse=(()=>{function e(e){if(this.data={},e)for(let t=Object.keys(e),n=0;n<t.length;++n)null!=e[t[n]]&&(this[t[n]]=e[t[n]])}return e.prototype.status=0,e.prototype.code=0,e.prototype.sentTime=O.Long?O.Long.fromBits(0,0,!1):0,e.prototype.reason="",e.prototype.data=O.emptyObject,e.create=function(t){return new e(t)},e.encode=function(e,t){if(t||(t=E.create()),null!=e.status&&Object.hasOwnProperty.call(e,"status")&&t.uint32(8).int32(e.status),null!=e.code&&Object.hasOwnProperty.call(e,"code")&&t.uint32(16).int32(e.code),null!=e.sentTime&&Object.hasOwnProperty.call(e,"sentTime")&&t.uint32(24).int64(e.sentTime),null!=e.reason&&Object.hasOwnProperty.call(e,"reason")&&t.uint32(34).string(e.reason),null!=e.data&&Object.hasOwnProperty.call(e,"data"))for(let n=Object.keys(e.data),i=0;i<n.length;++i)t.uint32(42).fork().uint32(10).string(n[i]).uint32(18).string(e.data[n[i]]).ldelim();return t},e.decode=function(e,t){e instanceof R||(e=R.create(e));let n,i,s=void 0===t?e.len:e.pos+t,r=new B.SendEventResponse;for(;e.pos<s;){let t=e.uint32();switch(t>>>3){case 1:r.status=e.int32();break;case 2:r.code=e.int32();break;case 3:r.sentTime=e.int64();break;case 4:r.reason=e.string();break;case 5:{r.data===O.emptyObject&&(r.data={});let t=e.uint32()+e.pos;for(n="",i="";e.pos<t;){let t=e.uint32();switch(t>>>3){case 1:n=e.string();break;case 2:i=e.string();break;default:e.skipType(7&t)}}r.data[n]=i;break}default:e.skipType(7&t)}}return r},e.verify=function(e){if("object"!=typeof e||null===e)return"object expected";if(null!=e.status&&e.hasOwnProperty("status"))switch(e.status){default:return"status: enum value expected";case 0:case 1:case 2:}if(null!=e.code&&e.hasOwnProperty("code"))switch(e.code){default:return"code: enum value expected";case 0:case 1:case 2:case 3:case 4:case 5:}if(null!=e.sentTime&&e.hasOwnProperty("sentTime")&&!(O.isInteger(e.sentTime)||e.sentTime&&O.isInteger(e.sentTime.low)&&O.isInteger(e.sentTime.high)))return"sentTime: integer|Long expected";if(null!=e.reason&&e.hasOwnProperty("reason")&&!O.isString(e.reason))return"reason: string expected";if(null!=e.data&&e.hasOwnProperty("data")){if(!O.isObject(e.data))return"data: object expected";let t=Object.keys(e.data);for(let n=0;n<t.length;++n)if(!O.isString(e.data[t[n]]))return"data: string{k:string} expected"}return null},e.getTypeUrl=function(e){return void 0===e&&(e="type.googleapis.com"),e+"/SendEventResponse"},e})();B.Status=(()=>{const e={},t=Object.create(e);return t[e[0]="STATUS_UNSPECIFIED"]=0,t[e[1]="STATUS_SUCCESS"]=1,t[e[2]="STATUS_ERROR"]=2,t})(),B.Code=(()=>{const e={},t=Object.create(e);return t[e[0]="CODE_UNSPECIFIED"]=0,t[e[1]="CODE_OK"]=1,t[e[2]="CODE_BAD_REQUEST"]=2,t[e[3]="CODE_INTERNAL_ERROR"]=3,t[e[4]="CODE_MAX_CONNECTION_LIMIT_REACHED"]=4,t[e[5]="CODE_MAX_USER_LIMIT_REACHED"]=5,t})();let x=!1;function A(e,t){return e?[e,...t]:t}const M={info:function(e="",...t){x&&console.log(...A(e,t))},debug:function(e="",...t){x&&console.debug(...A(e,t))},warn:function(e="",...t){x&&console.warn(...A(e,t))},error:function(e="",...t){console.error(...A(e,t))},get logging(){return x},set logging(e){x=Boolean(e)}};var G=new WeakMap,N=new WeakMap,q=new WeakMap,C=new WeakMap,_=new WeakMap,I=new WeakMap,D=new WeakSet,L=new WeakSet,z=new WeakSet;class U{constructor({config:e,eventBus:t,store:i,id:s}){a(this,z),a(this,L),a(this,D),o(this,G,{writable:!0,value:void 0}),o(this,N,{writable:!0,value:void 0}),o(this,q,{writable:!0,value:void 0}),o(this,C,{writable:!0,value:void 0}),o(this,_,{writable:!0,value:0}),o(this,I,{writable:!0,value:void 0}),n(this,G,e),n(this,q,t),n(this,N,i),n(this,_,0),n(this,I,void 0),n(this,C,s)}async send(e,{retry:t=!1}={}){const n=s(this,D,Q).call(this,e);s(this,z,H).call(this,n,{retry:t})}}function Q(e){const n=t(this,C).uuidv4(),{seconds:i}=(()=>{const e=new Date;return{seconds:Math.floor(e.getTime()/1e3)}})();M.info("Network:","generated reqGuid",n),M.info("Network:","generated timestamp(seconds)",i);const s=e.filter((e=>e.eventType===h));s.length&&t(this,N).isOpen&&(t(this,N).update(s,"reqGuid",n),M.info("Network:","updated reqGuid for all events in store"));const r=e.map((e=>{const{data:t,type:n}=e;return j.create({eventBytes:t,type:n})})),o=W.create({reqGuid:n,sentTime:{seconds:i},events:[...r]});return M.debug("Network:","network request",o),{reqGuid:n,body:W.encode(o).finish()}}function $(e){const{maxRetries:i,timeBetweenTwoRetries:r,timeToResumeRetries:o}=t(this,G);t(this,_)<i?(t(this,I)&&(window.clearTimeout(t(this,I)),n(this,I,void 0)),n(this,_,t(this,_)+1),M.debug("Network:","retry",t(this,_)),window.setTimeout((()=>{t(this,q).emit(d,{reqGuid:e.reqGuid})}),r)):t(this,_)===i&&void 0===t(this,I)&&(M.debug("Network:","waiting for",o),n(this,I,window.setTimeout((()=>{n(this,_,0),s(this,L,$).call(this,e)}),o)))}async function H(e,{retry:n}){const i=new Headers(t(this,G).headers);i.append("Content-Type","application/proto");try{const r=await fetch(t(this,G).url,{method:"POST",headers:i,body:e.body});if(!r.ok)return M.error("Network:",new S(`Network request to raccoon failed with status code ${r.status}`)),void(n&&s(this,L,$).call(this,e));if(M.info("Network:","received response from raccoon "),t(this,N).isOpen()){const e=await r.blob(),n=await(async e=>e.arrayBuffer?e.arrayBuffer():new Promise(((t,n)=>{const i=new FileReader;i.onloadend=()=>{2===i.readyState&&t(i.result)},i.onerror=e=>n(e),i.readAsArrayBuffer(e)})))(e),i=new Uint8Array(n),s=P.decode(i);M.debug("Network:","response data from Raccoon",s,JSON.stringify(s,void 0,2));const o=await t(this,N).readByReqGuid(s.data.req_guid);t(this,N).remove(o),M.debug("remove events from store with reqGuid",s.data.req_guid)}}catch(t){M.error("Network:",new S(t.message,{cause:t})),n&&s(this,L,$).call(this,e)}}var K=new WeakMap,F=new WeakMap,V=new WeakMap,X=new WeakMap,J=new WeakSet,Y=new WeakSet;class Z{constructor({config:e,store:t,id:i,isRealTimeEventsSupported:s}){a(this,Y),a(this,J),o(this,K,{writable:!0,value:void 0}),o(this,F,{writable:!0,value:void 0}),o(this,V,{writable:!0,value:void 0}),o(this,X,{writable:!0,value:void 0}),n(this,K,e),n(this,F,t),n(this,V,i),n(this,X,s)}process(e){const t=s(this,J,ee).call(this,e);return{type:t,event:s(this,Y,te).call(this,e,t)}}}function ee(e){return t(this,X)?t(this,F).isOpen()?t(this,K)?.classification?.instant?.includes(e.eventName)?(M.info("Processor:",`"${e.eventName}" event is classified as QoS0 as per configuration`),u):(M.info("Processor:",`"${e.eventName}" event is considered as QoS1 by default configuration`),h):(M.info("Processor:",`treating "${e.eventName}" event as QoS0 as indexedDB is not supported`),u):(M.info("Processor:",`treating "${e.eventName}" event as QoS0 as QoS1 events are not supported`),u)}function te(e,n){const i=e.constructor,s=i.encode(e).finish();try{if(i.decode){const e=i.decode(s);M.debug("Processor:","decoded event payload",e)}}catch(e){M.debug("Processor:","event decoding failed",e)}const r=i.getTypeUrl("").split("."),o=r[r.length-1].toLowerCase(),a=t(this,K).group?`${t(this,K).group}-${o}`:o;M.info("Processor:","topic name is set to",a);const c={data:s,eventType:n,type:a};return n===h&&(c.eventGuid=t(this,V).uuidv4(),c.reqGuid=""),M.info("Processor:","created a new event"),M.debug("Processor:","new event data",c),c}var ne=new WeakMap,ie=new WeakMap,se=new WeakMap,re=new WeakMap,oe=new WeakMap,ae=new WeakMap,ce=new WeakMap,ue=new WeakMap,he=new WeakSet,le=new WeakSet,de=new WeakSet,pe=new WeakSet,we=new WeakSet,fe=new WeakSet,ve=new WeakSet,ge=new WeakSet,me=new WeakSet,be=new WeakSet;class ye{constructor({config:e,eventBus:t,store:i}){a(this,be),a(this,me),a(this,ge),a(this,ve),a(this,fe),a(this,we),a(this,pe),a(this,de),a(this,le),a(this,he),o(this,ne,{writable:!0,value:void 0}),o(this,ie,{writable:!0,value:void 0}),o(this,se,{writable:!0,value:void 0}),o(this,re,{writable:!0,value:void 0}),o(this,oe,{writable:!0,value:void 0}),o(this,ae,{writable:!0,value:void 0}),o(this,ce,{writable:!0,value:void 0}),o(this,ue,{writable:!0,value:void 0}),n(this,re,e),n(this,oe,t),n(this,ae,i),n(this,ne,void 0),n(this,ie,0),n(this,se,!1),n(this,ce,[]),n(this,ue,[])}isRunning(){return t(this,se)}start(){n(this,se,!0),s(this,be,Pe).call(this),s(this,pe,Re).call(this)}stop(){s(this,le,Se).call(this),n(this,ie,0),n(this,se,!1)}pause(){n(this,se,!1)}resume(){n(this,se,!0)}async free(){try{this.stop(),M.info("Scheduler:","scheduler is stopped"),M.info("Scheduler:","flushing all events"),t(this,ae).isOpen()&&await s(this,he,ke).call(this),s(this,we,Ee).call(this)}catch(e){return Promise.reject(e)}}}async function ke(){let e=await t(this,ae).read();e=e.filter((e=>![...t(this,ce),...t(this,ue)].some((t=>t.eventGuid===e.eventGuid)))),M.debug("Scheduler:","flushed events",e),t(this,ce).push(...e),s(this,de,Te).call(this)}function Se(){void 0!==t(this,ne)&&(clearInterval(t(this,ne)),n(this,ne,void 0))}function Te(){t(this,ce).length&&t(this,oe).emit(l,{batch:t(this,ce)}),n(this,ie,0),n(this,ue,t(this,ce)),n(this,ce,[])}function Re(){t(this,oe)?.on(d,(async e=>{M.debug("Scheduler:","batch failed with reqGuid",e.detail.reqGuid);const n=await t(this,ae).readByReqGuid(e.detail.reqGuid);t(this,oe).emit(l,{batch:n})})),M.info("Scheduler:",'added "BATCH_FAILED" listener')}function Ee(){t(this,oe)?.remove(d),M.info("Scheduler:",'removed "BATCH_FAILED" listener')}function Oe(e){return e.reduce(((e,t)=>e+new Blob(t?.data).size),0)}function Be(e){const n=s(this,fe,Oe).call(this,[e[0]]),i=s(this,fe,Oe).call(this,t(this,ce)),r=t(this,re).maxBatchSize-i;return M.debug("Scheduler:","current batch size",i),M.debug("Scheduler:","max batch size",t(this,re).maxBatchSize),M.debug("Scheduler:","remaining batch size",r),e.splice(0,Math.ceil(r/n)+1)}async function We(){if(!t(this,ae).isOpen())return M.debug("Scheduler:","store is not open"),[];try{let e=await t(this,ae).read();if(e=e.filter((e=>![...t(this,ce),...t(this,ue)].some((t=>t.eventGuid===e.eventGuid)))),!e.length)return M.debug("no new QoS1 events are found"),[];const n=s(this,ve,Be).call(this,e);return M.debug("Scheduler:","events before splitting by size",e,e.length),M.debug("Scheduler:","events after splitting by size",n,n.length),n}catch(e){return M.error("Scheduler:",e),[]}}async function je(){const e=await s(this,ge,We).call(this);M.debug("Scheduler:","QoS1 events",e),e.length&&(t(this,ce).push(...e),M.debug("Scheduler:","QoS1 events pushed in batch",t(this,ce)))}function Pe(){s(this,le,Se).call(this),n(this,ne,setInterval((()=>{if(!t(this,se))return void M.debug("Scheduler:","batching is not running");n(this,ie,t(this,ie)+1),s(this,me,je).call(this);const e=s(this,fe,Oe).call(this,t(this,ce));e>=t(this,re).maxBatchSize?(s(this,de,Te).call(this),M.info("Scheduler:","this batch of size",e,"batch has reached max size threshold of",t(this,re).maxBatchSize)):t(this,ie)>=t(this,re).maxTimeBetweenTwoBatches&&(s(this,de,Te).call(this),M.info("Scheduler:","batch has waited max time of",t(this,re).maxTimeBetweenTwoBatches))}),1e3))}class xe{constructor(){this.eventTarget=new EventTarget}emit(e,t){const n=new CustomEvent(e,{detail:t});this.eventTarget.dispatchEvent(n)}on(e,t){this.eventTarget.addEventListener(e,t)}remove(e,t){this.eventTarget.removeEventListener(e,t)}}const Ae="events";var Me=new WeakMap,Ge=new WeakMap,Ne=new WeakMap,qe=new WeakMap;class Ce{constructor({name:e="clickstream_db",version:t=1}){o(this,Me,{writable:!0,value:void 0}),o(this,Ge,{writable:!0,value:void 0}),o(this,Ne,{writable:!0,value:void 0}),o(this,qe,{writable:!0,value:void 0}),n(this,Me,e),n(this,Ge,t),n(this,qe,!1)}isOpen(){return t(this,qe)}open(){return new Promise(((e,i)=>{const s=window.indexedDB.open(t(this,Me),t(this,Ge));s.onblocked=e=>{M.info("Store:","please close all other tabs with this site open"),i(e.target.error)},s.onerror=e=>{i(e.target.error)},s.onsuccess=i=>{n(this,Ne,i.target.result),n(this,qe,!0),e("success"),M.info("Store:","store is open with name",t(this,Me)),t(this,Ne).addEventListener("close",(()=>{M.info("Store:","database connection is closed")}))},s.onupgradeneeded=e=>{if(n(this,Ne,e.target.result),0===e.oldVersion){const e=t(this,Ne).createObjectStore(Ae,{keyPath:"eventGuid"});e.createIndex("reqGuid","reqGuid",{unique:!1}),e.createIndex("eventGuid","eventGuid",{unique:!0})}t(this,Ne).onversionchange=e=>{t(this,Ne).close(),n(this,qe,!1),M.info("Store:","a new version of this page is ready, please reload or close this tab"),i(e.target.error)}}}))}read(){return new Promise(((e,i)=>{try{const n=t(this,Ne).transaction(Ae).objectStore(Ae);n.getAll().onsuccess=t=>{e(t.target.result)},n.getAll().onerror=e=>{i(e.target.error)}}catch(e){n(this,qe,!1),M.error("Store:",new k(e.message,{cause:e}))}}))}readByReqGuid(e){return new Promise((i=>{const s=[];try{const n=t(this,Ne).transaction([Ae],"readwrite").objectStore(Ae);n.index("reqGuid").openCursor().onsuccess=t=>{try{const n=t.target.result;n?(n.value.reqGuid===e&&s.push(n.value),n.continue()):i(s)}catch(e){M.error("Store:",new k(e.message,{cause:e}))}}}catch(e){n(this,qe,!1),M.error("Store:",new k(e.message,{cause:e}))}}))}write(e){return new Promise(((i,s)=>{Array.isArray(e)||(e=[e]);try{const n=t(this,Ne).transaction([Ae],"readwrite"),r=n.objectStore(Ae);n.oncomplete=()=>{i("success")},n.onerror=e=>{s(e.target.error)};try{e.forEach((e=>{r.add(e)}))}catch(e){M.error("Store:",new k(e.message,{cause:e}))}}catch(e){n(this,qe,!1),M.error("Store:",new k(e.message,{cause:e}))}}))}update(e,i,s){try{const n=t(this,Ne).transaction([Ae],"readwrite").objectStore(Ae);try{e.forEach((e=>{e[i]=s,n.put(e)}))}catch(e){M.error("Store:",new k(e.message,{cause:e}))}}catch(e){n(this,qe,!1),M.error("Store:",new k(e.message,{cause:e}))}}remove(e){return new Promise(((i,s)=>{try{const n=t(this,Ne).transaction([Ae],"readwrite"),r=n.objectStore(Ae);n.oncomplete=()=>{i("success")},n.onerror=e=>{s(e.target.error)};try{e.forEach((e=>{r.delete(e.eventGuid)}))}catch(e){M.error("Store:",new k(e.message,{cause:e}))}}catch(e){n(this,qe,!1),M.error("Store:",new k(e.message,{cause:e}))}}))}delete(){return new Promise(((e,i)=>{let s=window.indexedDB.deleteDatabase(t(this,Me));s.onerror=e=>{i(e.target.error)},s.onsuccess=t=>{n(this,Ne,null),n(this,qe,!1),e(t.target.result)}}))}}var _e=new WeakMap;class Ie{constructor({crypto:e}){o(this,_e,{writable:!0,value:void 0}),n(this,_e,e||crypto)}uuidv4(){return"10000000-1000-4000-8000-100000000000".replace(/[018]/g,(e=>(e^t(this,_e).getRandomValues(new Uint8Array(1))[0]&15>>e/4).toString(16)))}}const De=e=>Number.isInteger(e)&&e>0,Le=e=>"string"==typeof e,ze=e=>void 0!==e;class Ue{validate(e,t,n,i){if(!n?.url)throw new y("provide url in network config");if(ze(n.url)&&!Le(n.url)&&!(n.url instanceof URL))throw new y("network url must be of type string or instance of URL");if(!n?.headers)throw new y('provide "Authorization" header in network config');if(ze(n.headers)&&!(n.headers instanceof Headers))throw new y("network headers must be instance of Headers");if(!n.headers.get("Authorization"))throw new y('provide "Authorization" header in network config');if(ze(n.timeBetweenTwoRetries)&&!De(n.timeBetweenTwoRetries))throw new y('"timeBetweenTwoRetries" must be a positive integer');if(ze(n.timeToResumeRetries)&&!De(n.timeToResumeRetries))throw new y('"timeToResumeRetries" must be a positive integer');if(ze(e?.classification?.instant)){if(e.classification.instant.some((e=>!Le(e))))throw new y('"instant" event names must be of type string')}if(ze(e?.group)&&!Le(e.group))throw new y('"group" name must be of type string');if(ze(t?.maxTimeBetweenTwoBatches)&&!De(t.maxTimeBetweenTwoBatches))throw new y("maxTimeBetweenTwoBatches must be a positive integer");if(ze(t?.maxBatchSize)&&!De(t.maxBatchSize))throw new y('"maxBatchSize" must be a positive integer');if(ze(t?.dbName)&&!Le(t.dbName))throw new y('"dbName" name must be of type string');if(ze(i)&&"object"!=typeof i)throw new y('"crypto" must be of type object')}}const Qe="Cickstream:",$e="browser",He="node",Ke="unknown",Fe=async()=>{const e="object"==typeof globalThis.process?He:void 0!==globalThis.window?$e:Ke;if(M.debug(Qe,"runtime detected:",e),e===$e){const{vendor:e,userAgent:t,platform:n}=globalThis.navigator;M.debug(Qe,"url:",document?.location.href??null),M.debug(Qe,"platform:",n),M.debug(Qe,"vendor:",e),M.debug(Qe,"userAgent:",t)}else e===He&&M.debug(Qe,`node version: ${globalThis.process.version}`)},Ve=()=>void 0!==globalThis.indexedDB&&void 0!==globalThis.EventTarget;var Xe=new WeakMap,Je=new WeakMap,Ye=new WeakMap,Ze=new WeakMap,et=new WeakMap,tt=new WeakMap,nt=new WeakMap,it=new WeakMap,st=new WeakMap,rt=new WeakMap,ot=new WeakMap,at=new WeakSet,ct=new WeakSet;class ut{constructor({event:e,batch:i,network:r,crypto:u,debug:h}){a(this,ct),a(this,at),o(this,Xe,{writable:!0,value:void 0}),o(this,Je,{writable:!0,value:void 0}),o(this,Ye,{writable:!0,value:void 0}),o(this,Ze,{writable:!0,value:void 0}),o(this,et,{writable:!0,value:void 0}),o(this,tt,{writable:!0,value:void 0}),o(this,nt,{writable:!0,value:void 0}),o(this,it,{writable:!0,value:void 0}),o(this,st,{writable:!0,value:void 0}),o(this,rt,{writable:!0,value:void 0}),o(this,ot,{writable:!0,value:void 0}),h&&(M.logging=h,M.info(Qe,"logging is set to",M.logging)),Fe(),M.info(Qe,"configuration received"),M.debug(Qe,"event configuration received",e),M.debug(Qe,"batch configuration received",i),M.debug(Qe,"network configuration received",r),M.debug(Qe,"crypto configuration received",u),(new Ue).validate(e,i,r,u),M.info(Qe,"configuration validation is successful"),n(this,ot,Ve()),M.info(Qe,`QoS1 events are ${t(this,ot)?"":"not"} supported`),n(this,it,Object.assign(c.event,e)),n(this,st,Object.assign(c.batch,i)),n(this,rt,Object.assign(c.network,r)),M.info(Qe,"configuration merged with default configuration"),M.debug(Qe,"event configuration",t(this,it)),M.debug(Qe,"batch configuration",t(this,st)),M.debug(Qe,"network configuration",t(this,rt)),M.debug(Qe,"crypto configuration",u),n(this,Xe,!0),n(this,et,new Ce({name:t(this,st).dbName})),t(this,ot)&&n(this,nt,new xe),n(this,tt,new Ie({crypto:u})),n(this,Je,new Z({config:t(this,it),store:t(this,et),id:t(this,tt),isRealTimeEventsSupported:Ve})),n(this,Ye,new ye({config:t(this,st),eventBus:t(this,nt),store:t(this,et)})),n(this,Ze,new U({config:t(this,rt),eventBus:t(this,nt),store:t(this,et),id:t(this,tt)})),s(this,at,ht).call(this)}async track(e){if(!t(this,Xe))return Promise.reject(new b("Tracking is paused, call .resume() method to resume tracking",{code:p.TRACKING_ERROR}));if(t(this,ot)&&!t(this,Ye).isRunning()&&(t(this,Ye).start(),M.info(Qe,"restarted scheduler")),t(this,ot)&&!t(this,et)?.isOpen())try{await t(this,et).open()}catch(e){return Promise.reject(new k(e.message,{cause:e}))}const{type:n,event:i}=t(this,Je).process(e);M.info(Qe,"event type is set to",n);try{n===h?(await t(this,et).write(i),M.info(Qe,"event is stored in the store with eventGuid",i.eventGuid)):n===u&&(M.info(Qe,"event is sent to transport layer"),t(this,Ze).send([i]))}catch(e){return Promise.reject(new b(e.message,{cause:e}))}}pause(){n(this,Xe,!1),M.info(Qe,"tracking is set to",t(this,Xe))}resume(){n(this,Xe,!0),M.info(Qe,"tracking is set to",t(this,Xe))}async free(){try{await t(this,Ye).free(),M.info(Qe,"scheduler resources are released"),t(this,et).isOpen()&&(await t(this,et).delete(),M.info(Qe,"store is deleted")),M.info(Qe,"cleanup is done")}catch(e){return Promise.reject(new b(e.message,{name:m,code:p.CLEANUP_ERROR}))}}}function ht(){t(this,ot)&&(s(this,ct,lt).call(this),t(this,Ye).start(),M.info(Qe,"scheduler is up and running"))}function lt(){t(this,nt)?.on(l,(e=>{M.info(Qe,"new batch created"),M.debug(Qe,"new batch data",e.detail.batch),t(this,Ze).send(e.detail.batch,{retry:!0})}))}export{ut as Clickstream,p as errorCodes};