@dashgram/javascript 1.0.2 → 1.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/dashgram.min.js +1 -1
- package/dist/dashgram.min.js.map +1 -1
- package/dist/index.d.ts +1 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +0 -2
- package/package.json +1 -1
package/dist/dashgram.min.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports):"function"==typeof define&&define.amd?define(["exports"],t):t((e="undefined"!=typeof globalThis?globalThis:e||self).DashgramMini={})}(this,function(e){"use strict";class t extends Error{constructor(e){super(e),this.name="DashgramError";const s=Error;"function"==typeof s.captureStackTrace&&s.captureStackTrace(this,t)}}class s extends t{constructor(e,t){super(`Dashgram API error (${e}): ${t}`),this.statusCode=e,this.details=t,this.name="DashgramAPIError";const i=Error;"function"==typeof i.captureStackTrace&&i.captureStackTrace(this,s)}}class i extends t{constructor(e){super(`Network error: ${e.message}`),this.originalError=e,this.name="NetworkError";const t=Error;"function"==typeof t.captureStackTrace&&t.captureStackTrace(this,i)}}class n extends t{constructor(e){super(e),this.name="DashgramConfigurationError";const t=Error;"function"==typeof t.captureStackTrace&&t.captureStackTrace(this,n)}}const r={trackLevel:1,apiUrl:"https://api.dashgram.io/v1",batchSize:10,flushInterval:5e3,debug:!1,disabled:!1};class o{constructor(e){this.config={...r,...e},this.validate()}validate(){if(!this.config.projectId)throw new n("projectId is required");if(![1,2,3].includes(this.config.trackLevel))throw new n("trackLevel must be 1, 2, or 3")}get(e){return this.config[e]}getOnError(){return this.config.onError}getTrackUrl(){return`${this.config.apiUrl.replace(/\/$/,"")}/${this.config.projectId}/webapp/track`}setTrackLevel(e){if(![1,2,3].includes(e))throw new n("trackLevel must be 1, 2, or 3");this.config.trackLevel=e}getTrackLevel(){return this.config.trackLevel}isDebug(){return this.config.debug}isDisabled(){return this.config.disabled}}function c(){if("undefined"==typeof window)return null;const e=window;return e.Telegram?.WebApp||null}function a(){const e=c();return e?.initData||""}function u(){const e=c();return e?.platform||"unknown"}function h(){const e=c();if(e?.colorScheme)return e.colorScheme;if(e?.themeParams?.bg_color){const t=e.themeParams.bg_color;try{const e=parseInt(t.slice(1),16);return.2126*(e>>16&255)+.7152*(e>>8&255)+.0722*(255&e)<128?"dark":"light"}catch{return}}}function d(e,t){const s=c();if(!s||!s.onEvent)return()=>{};try{const i=(s,i)=>{try{t(i)}catch(t){"undefined"!=typeof window&&window.__DASHGRAM_DEBUG__&&console.warn(`[Dashgram] Error in Telegram event callback for ${e}:`,t)}};return s.onEvent(e,i),()=>{try{s.offEvent&&s.offEvent(e,i)}catch{}}}catch{return()=>{}}}function l(){return"undefined"==typeof window?{platform:"unknown"}:{platform:u(),user_agent:navigator.userAgent,timezone:Intl.DateTimeFormat().resolvedOptions().timeZone||void 0,theme:h()}}class p{constructor(){this.telemetry=l()}getTelemetry(){return{...this.telemetry}}updateTelemetry(){this.telemetry=l()}}function g(e,t){let s=null,i=0;return function(...n){const r=Date.now(),o=t-(r-i);o<=0||o>t?(s&&(clearTimeout(s),s=null),i=r,e.apply(this,n)):s||(s=setTimeout(()=>{i=Date.now(),s=null,e.apply(this,n)},o))}}function f(e){try{return JSON.stringify(e)}catch(e){return"{}"}}function b(e){if(e.id)return`#${e.id}`;if(e.className&&"string"==typeof e.className){const t=e.className.trim().split(/\s+/).slice(0,2).join(".");if(t)return`${e.tagName.toLowerCase()}.${t}`}return e.tagName.toLowerCase()}function m(e,t=50){const s=e.textContent?.trim()||"";return s.length>t?s.substring(0,t)+"...":s}class v{constructor(e){this.isOnline=!0,this.pendingRequests=new Set,this.config=e,this.setupOnlineListener()}setupOnlineListener(){"undefined"!=typeof window&&(window.addEventListener("online",()=>{this.isOnline=!0,this.log("Connection restored")}),window.addEventListener("offline",()=>{this.isOnline=!1,this.log("Connection lost")}),this.isOnline=navigator.onLine)}buildPayload(e){return{origin:("undefined"==typeof window?"":window.location.origin)||void 0,updates:e}}async send(e){if(0===e.length)return;if(this.config.isDisabled())return void this.log("Tracking disabled, skipping send");if(!this.isOnline)return void this.log("Offline, skipping send");const t=this.sendRequest(e);this.pendingRequests.add(t);try{await t}catch(e){this.logError("Failed to send events:",e);const t=this.config.getOnError();if(t)try{e instanceof s||e instanceof i?t(e):e instanceof Error&&t(new i(e))}catch(e){this.logError("Error in onError callback:",e)}}finally{this.pendingRequests.delete(t)}}async sendRequest(e){const t=this.config.getTrackUrl(),n=this.buildPayload(e);try{const i=await fetch(t,{method:"POST",headers:{"Content-Type":"application/json"},body:f(n),keepalive:!0});if(!i.ok){let e=i.statusText;try{const t=await i.json();e=t.details||t.message||e}catch{}throw new s(i.status,e)}this.log(`Sent ${e.length} events successfully`)}catch(e){if(e instanceof s)throw e;if(e instanceof Error)throw new i(e);throw new i(new Error(String(e)))}}sendBeacon(e){if(0===e.length)return!0;if(this.config.isDisabled())return!0;if("undefined"==typeof navigator||!navigator.sendBeacon)return!1;const t=this.config.getTrackUrl(),s=this.buildPayload(e),i=new Blob([f(s)],{type:"application/json"}),n=navigator.sendBeacon(t,i);return this.log(`sendBeacon ${n?"succeeded":"failed"} for ${e.length} events`),n}async flush(){await Promise.all(Array.from(this.pendingRequests))}log(...e){this.config.isDebug()&&console.log("[Dashgram Transport]",...e)}logError(...e){this.config.isDebug()&&console.error("[Dashgram Transport]",...e)}}class _{constructor(e=100){this.queue=[],this.maxSize=e}enqueue(e){this.queue.push(e),this.queue.length>this.maxSize&&this.queue.shift()}flush(){const e=[...this.queue];return this.queue=[],e}peek(){return[...this.queue]}size(){return this.queue.length}isEmpty(){return 0===this.queue.length}clear(){this.queue=[]}}class k{constructor(e,t){this.flushTimer=null,this.isStarted=!1,this.config=e,this.transport=t,this.queue=new _(200)}start(){this.isStarted||(this.isStarted=!0,this.scheduleFlush(),this.setupPageUnloadHandler())}stop(){this.isStarted=!1,this.flushTimer&&(clearTimeout(this.flushTimer),this.flushTimer=null)}addEvent(e){this.queue.enqueue(e);const t=this.config.get("batchSize");this.queue.size()>=t&&this.flush()}scheduleFlush(){this.flushTimer&&clearTimeout(this.flushTimer);const e=this.config.get("flushInterval");this.flushTimer=setTimeout(()=>{this.flush(),this.isStarted&&this.scheduleFlush()},e)}flush(){const e=this.queue.flush();e.length>0&&this.transport.send(e)}async flushAsync(){const e=this.queue.flush();e.length>0&&await this.transport.send(e),await this.transport.flush()}setupPageUnloadHandler(){if("undefined"==typeof window)return;const e=()=>{const e=this.queue.flush();e.length>0&&this.transport.sendBeacon(e)};window.addEventListener("visibilitychange",()=>{"hidden"===document.visibilityState&&e()}),window.addEventListener("pagehide",e),window.addEventListener("beforeunload",e)}}class w{constructor(e,t,s){this.isActive=!1,this.config=e,this.trackCallback=t,this.level=s}start(){if(this.isActive)return;this.config.getTrackLevel()>=this.level&&(this.isActive=!0,this.setup(),this.log(`Started (level ${this.level})`))}stop(){this.isActive&&(this.isActive=!1,this.teardown(),this.log("Stopped"))}track(e,t={}){this.isActive&&this.trackCallback(e,t)}log(...e){this.config.isDebug()&&console.log(`[Dashgram ${this.constructor.name}]`,...e)}}class y extends w{constructor(e,t){super(e,t,1),this.unsubscribers=[],this.hasTrackedAppOpen=!1}setup(){"undefined"!=typeof window&&(this.trackAppOpen(),this.setupVisibilityTracking(),this.setupUnloadTracking())}teardown(){this.unsubscribers.forEach(e=>e()),this.unsubscribers=[]}trackAppOpen(){this.hasTrackedAppOpen||(this.track("app_open",{referrer:document.referrer||"direct"}),this.hasTrackedAppOpen=!0)}setupVisibilityTracking(){const e=()=>{"hidden"===document.visibilityState?this.track("app_close",{visibility_state:"hidden"}):"visible"===document.visibilityState&&this.track("app_open",{visibility_state:"visible"})};document.addEventListener("visibilitychange",e),this.unsubscribers.push(()=>{document.removeEventListener("visibilitychange",e)})}setupUnloadTracking(){const e=()=>{this.track("app_close",{reason:"unload"})};window.addEventListener("pagehide",e),this.unsubscribers.push(()=>{window.removeEventListener("pagehide",e)}),window.addEventListener("beforeunload",e),this.unsubscribers.push(()=>{window.removeEventListener("beforeunload",e)})}}class T extends w{constructor(e,t){super(e,t,2),this.unsubscribers=[],this.lastPath="",this.inputValues=new Map}setup(){"undefined"!=typeof window&&(this.trackScreenView(),this.setupHistoryTracking(),this.setupClickTracking(),this.setupFormTracking(),this.setupInputTracking(),this.setupClipboardTracking(),this.setupSelectionTracking(),this.setupErrorTracking())}teardown(){this.unsubscribers.forEach(e=>e()),this.unsubscribers=[]}trackScreenView(){const e="undefined"==typeof window?"":window.location.pathname;e!==this.lastPath&&(this.lastPath=e,this.track("screen_view",{path:e,url:"undefined"==typeof window?"":window.location.href,title:"undefined"==typeof document?"":document.title||"",referrer:document.referrer||"direct"}))}setupHistoryTracking(){const e=history.pushState,t=history.replaceState,s=()=>{this.trackScreenView()};history.pushState=function(...t){e.apply(history,t),s()},history.replaceState=function(...e){t.apply(history,e),s()},window.addEventListener("popstate",s),this.unsubscribers.push(()=>{history.pushState=e,history.replaceState=t,window.removeEventListener("popstate",s)})}setupClickTracking(){const e=e=>{const t=e.target;if(!t)return;const s=t.closest('button, [role="button"], a');if(s){if("a"===s.tagName.toLowerCase()){const e=s,t=e.href,i=!!t&&this.isExternalLink(t);this.track("link_click",{element:b(s),text:m(s),href:t||void 0,target:e.target||void 0,is_external:i,is_download:e.hasAttribute("download")})}else this.track("button_click",{element:b(s),text:m(s)})}};document.addEventListener("click",e,{capture:!0}),this.unsubscribers.push(()=>{document.removeEventListener("click",e,{capture:!0})})}isExternalLink(e){try{return new URL(e,window.location.href).origin!==window.location.origin}catch{return!1}}setupFormTracking(){const e=e=>{const t=e.target;t&&this.track("form_submit",{form_id:t.id||void 0,form_name:t.name||void 0,form_action:t.action||void 0,form_method:t.method||void 0})};document.addEventListener("submit",e,{capture:!0}),this.unsubscribers.push(()=>{document.removeEventListener("submit",e,{capture:!0})})}setupInputTracking(){const e=g(e=>{const t=e.target;if(!t)return;const s=t.tagName.toLowerCase();if(["input","textarea","select"].includes(s)){const e=t;this.inputValues.set(t,e.value||""),this.track("input_focus",{element:b(e),input_type:e.type||s,input_name:e.name||void 0,input_id:e.id||void 0})}},1e3),t=e=>{const t=e.target;if(!t)return;const s=t.tagName.toLowerCase();if(["input","textarea","select"].includes(s)){const e=t,i=this.inputValues.get(t),n=e.value||"";void 0!==i&&i!==n&&this.track("input_change",{element:b(e),input_type:e.type||s,input_name:e.name||void 0,input_id:e.id||void 0,had_value:i.length>0,has_value:n.length>0}),this.inputValues.delete(t)}};document.addEventListener("focus",e,{capture:!0}),document.addEventListener("blur",t,{capture:!0}),this.unsubscribers.push(()=>{document.removeEventListener("focus",e,{capture:!0}),document.removeEventListener("blur",t,{capture:!0}),this.inputValues.clear()})}setupClipboardTracking(){const e=e=>{const t=window.getSelection(),s=t?.toString()||"";this.track("copy",{text_length:s.length,has_selection:s.length>0})},t=e=>{const t=window.getSelection(),s=t?.toString()||"";this.track("cut",{text_length:s.length,has_selection:s.length>0})},s=e=>{const t=e.clipboardData?.getData("text")||"",s=e.target;this.track("paste",{text_length:t.length,target_element:s?b(s):void 0})};document.addEventListener("copy",e),document.addEventListener("cut",t),document.addEventListener("paste",s),this.unsubscribers.push(()=>{document.removeEventListener("copy",e),document.removeEventListener("cut",t),document.removeEventListener("paste",s)})}setupSelectionTracking(){let e;const t=()=>{clearTimeout(e),e=setTimeout(()=>{const e=window.getSelection(),t=e?.toString()||"";t.length>0&&this.track("text_select",{text_length:t.length})},500)};document.addEventListener("selectionchange",t),this.unsubscribers.push(()=>{document.removeEventListener("selectionchange",t),clearTimeout(e)})}setupErrorTracking(){const e=e=>{this.track("js_error",{message:e.message,filename:e.filename,lineno:e.lineno,colno:e.colno,stack:e.error?.stack})};window.addEventListener("error",e),this.unsubscribers.push(()=>{window.removeEventListener("error",e)});const t=e=>{this.track("unhandled_rejection",{reason:String(e.reason),promise:String(e.promise)})};window.addEventListener("unhandledrejection",t),this.unsubscribers.push(()=>{window.removeEventListener("unhandledrejection",t)})}}class E extends w{constructor(e,t){super(e,t,3),this.unsubscribers=[],this.observers=[],this.clickTracker=new Map,this.maxScrollDepth=0,this.trackedMedia=new WeakSet}setup(){"undefined"!=typeof window&&(this.setupScrollTracking(),this.setupVisibilityTracking(),this.setupRageClickTracking(),this.setupLongTaskTracking(),this.setupWebVitals(),this.setupNetworkTracking(),this.setupOrientationTracking(),this.setupMediaTracking(),this.setupTelegramTracking())}teardown(){this.unsubscribers.forEach(e=>e()),this.unsubscribers=[],this.observers.forEach(e=>e.disconnect()),this.observers=[],this.clickTracker.clear()}getScrollDepth(){const e=window.innerHeight,t=document.documentElement.scrollHeight,s=window.pageYOffset||document.documentElement.scrollTop;if(t<=e)return 100;const i=s/(t-e)*100;return Math.min(Math.round(i),100)}setupScrollTracking(){const e=g(()=>{const e=this.getScrollDepth();if(e>this.maxScrollDepth){this.maxScrollDepth=e;const t=[25,50,75,100].find(t=>e>=t&&this.maxScrollDepth-e<t);t&&this.track("scroll_depth",{depth:t,max_depth:this.maxScrollDepth})}},500);window.addEventListener("scroll",e,{passive:!0}),this.unsubscribers.push(()=>{window.removeEventListener("scroll",e)})}setupVisibilityTracking(){if(!("IntersectionObserver"in window))return;const e=new IntersectionObserver(t=>{t.forEach(t=>{if(t.isIntersecting){const s=t.target,i=s.getAttribute("data-track-visible");i&&(this.track("element_visible",{element:i,intersection_ratio:t.intersectionRatio}),e.unobserve(s))}})},{threshold:.5});document.querySelectorAll("[data-track-visible]").forEach(t=>{e.observe(t)}),this.observers.push(e);const t=new MutationObserver(t=>{t.forEach(t=>{t.addedNodes.forEach(t=>{t instanceof Element&&(t.hasAttribute("data-track-visible")&&e.observe(t),t.querySelectorAll("[data-track-visible]").forEach(t=>{e.observe(t)}))})})});t.observe(document.body,{childList:!0,subtree:!0}),this.unsubscribers.push(()=>{t.disconnect()})}setupRageClickTracking(){const e=e=>{const t=e.target;if(!t)return;const s=this.clickTracker.get(t);if(s)s.count++,clearTimeout(s.timer),s.count>=5?(this.track("rage_click",{element:t.tagName.toLowerCase(),click_count:s.count}),this.clickTracker.delete(t)):s.timer=setTimeout(()=>{this.clickTracker.delete(t)},2e3);else{const e=setTimeout(()=>{this.clickTracker.delete(t)},2e3);this.clickTracker.set(t,{count:1,timer:e})}};document.addEventListener("click",e),this.unsubscribers.push(()=>{document.removeEventListener("click",e)})}setupLongTaskTracking(){if("PerformanceObserver"in window)try{const e=new PerformanceObserver(e=>{for(const t of e.getEntries())t.duration>50&&this.track("long_task",{duration:Math.round(t.duration),start_time:Math.round(t.startTime)})});e.observe({entryTypes:["longtask"]}),this.observers.push(e)}catch(e){this.log("Long task tracking not supported")}}setupWebVitals(){if(!("PerformanceObserver"in window))return;try{const e=new PerformanceObserver(e=>{const t=e.getEntries(),s=t[t.length-1];this.track("web_vital_lcp",{value:Math.round(s.renderTime||s.loadTime),element:s.element?.tagName.toLowerCase()})});e.observe({entryTypes:["largest-contentful-paint"]}),this.observers.push(e)}catch(e){this.log("LCP tracking not supported")}try{const e=new PerformanceObserver(e=>{e.getEntries().forEach(e=>{this.track("web_vital_fid",{value:Math.round(e.processingStart-e.startTime),event_type:e.name})})});e.observe({entryTypes:["first-input"]}),this.observers.push(e)}catch(e){this.log("FID tracking not supported")}let e=0;try{const t=new PerformanceObserver(t=>{t.getEntries().forEach(t=>{t.hadRecentInput||(e+=t.value)})});t.observe({entryTypes:["layout-shift"]}),this.observers.push(t);const s=()=>{e>0&&this.track("web_vital_cls",{value:Math.round(1e3*e)/1e3})};window.addEventListener("visibilitychange",()=>{"hidden"===document.visibilityState&&s()}),this.unsubscribers.push(()=>{s()})}catch(e){this.log("CLS tracking not supported")}}setupNetworkTracking(){const e=()=>{this.track("network_status",{status:"online",effective_type:navigator.connection?.effectiveType,downlink:navigator.connection?.downlink,rtt:navigator.connection?.rtt})},t=()=>{this.track("network_status",{status:"offline"})};window.addEventListener("online",e),window.addEventListener("offline",t),this.unsubscribers.push(()=>{window.removeEventListener("online",e),window.removeEventListener("offline",t)});const s=navigator.connection;if(s){const e=()=>{this.track("network_change",{effective_type:s.effectiveType,downlink:s.downlink,rtt:s.rtt,save_data:s.saveData})};s.addEventListener("change",e),this.unsubscribers.push(()=>{s.removeEventListener("change",e)})}}setupOrientationTracking(){const e=()=>{const e=screen.orientation?.type||(window.innerWidth>window.innerHeight?"landscape":"portrait");this.track("orientation_change",{orientation:e,angle:screen.orientation?.angle,width:window.innerWidth,height:window.innerHeight})};screen.orientation?(screen.orientation.addEventListener("change",e),this.unsubscribers.push(()=>{screen.orientation.removeEventListener("change",e)})):(window.addEventListener("orientationchange",e),this.unsubscribers.push(()=>{window.removeEventListener("orientationchange",e)}))}setupMediaTracking(){const e=e=>{const t=e.target;if(!t||this.trackedMedia.has(t))return;const s=t.tagName.toLowerCase(),i=e.type,n={media_type:s,src:t.currentSrc||t.src,duration:isFinite(t.duration)?Math.round(t.duration):void 0,current_time:Math.round(t.currentTime),muted:t.muted,volume:Math.round(100*t.volume)};"play"===i?this.track("media_play",n):"pause"===i?this.track("media_pause",{...n,percent_played:t.duration?Math.round(t.currentTime/t.duration*100):0}):"ended"===i?this.track("media_ended",{...n,completed:!0}):"error"===i&&this.track("media_error",{media_type:s,src:t.currentSrc||t.src,error:t.error?.message||"unknown"})},t=t=>{this.trackedMedia.has(t)||(this.trackedMedia.add(t),t.addEventListener("play",e),t.addEventListener("pause",e),t.addEventListener("ended",e),t.addEventListener("error",e))};document.querySelectorAll("video, audio").forEach(e=>{t(e)});const s=new MutationObserver(e=>{e.forEach(e=>{e.addedNodes.forEach(e=>{e instanceof HTMLMediaElement&&t(e),e instanceof Element&&e.querySelectorAll("video, audio").forEach(e=>{t(e)})})})});s.observe(document.body,{childList:!0,subtree:!0}),this.observers.push(s)}setupTelegramTracking(){const e=window.Telegram?.WebApp,t=(e,t)=>{this.track(`telegram_${e}`,t||{})},s=d("themeChanged",()=>{t("theme_changed",{color_scheme:e?.colorScheme,theme_params:e?.themeParams})});this.unsubscribers.push(s);const i=d("viewportChanged",s=>{t("viewport_changed",{is_state_stable:s?.isStateStable,is_expanded:e?.isExpanded,viewport_height:e?.viewportHeight,viewport_stable_height:e?.viewportStableHeight})});this.unsubscribers.push(i);const n=d("safeAreaChanged",()=>{t("safe_area_changed",{safe_area:e?.safeAreaInset})});this.unsubscribers.push(n);const r=d("contentSafeAreaChanged",()=>{t("content_safe_area_changed",{content_safe_area:e?.contentSafeAreaInset})});this.unsubscribers.push(r);const o=d("backButtonClicked",()=>{t("back_button_clicked",{})});this.unsubscribers.push(o);const c=d("mainButtonClicked",()=>{t("main_button_clicked",{button_text:e?.MainButton?.text})});this.unsubscribers.push(c);const a=d("invoiceClosed",e=>{t("invoice_closed",{url:e?.url,status:e?.status})});this.unsubscribers.push(a);const u=d("popupClosed",e=>{t("popup_closed",{button_id:e?.button_id})});this.unsubscribers.push(u);const h=d("qrTextReceived",e=>{t("qr_text_received",{data:e?.data})});this.unsubscribers.push(h);const l=d("scanQrPopupClosed",()=>{t("scan_qr_popup_closed",{})});this.unsubscribers.push(l);const p=d("clipboardTextReceived",e=>{t("clipboard_text_received",{data:e?.data})});this.unsubscribers.push(p);const g=d("writeAccessRequested",e=>{t("write_access_requested",{status:e?.status})});this.unsubscribers.push(g);const f=d("fileDownloadRequested",e=>{t("file_download_requested",{status:e?.status})});this.unsubscribers.push(f);const b=d("customMethodInvoked",e=>{t("custom_method_invoked",{req_id:e?.req_id,result:e?.result,error:e?.error})});this.unsubscribers.push(b);const m=d("fullscreenChanged",e=>{t("fullscreen_changed",{is_fullscreen:e?.isFullscreen})});this.unsubscribers.push(m);const v=d("fullscreenFailed",e=>{t("fullscreen_failed",{error:e?.error})});this.unsubscribers.push(v);const _=d("homeScreenAdded",()=>{t("home_screen_added",{})});this.unsubscribers.push(_);const k=d("homeScreenChecked",e=>{t("home_screen_checked",{status:e?.status})});this.unsubscribers.push(k);const w=d("preparedMessageSent",()=>{t("prepared_message_sent",{})});this.unsubscribers.push(w);const y=d("preparedMessageFailed",e=>{t("prepared_message_failed",{error:e?.error})});this.unsubscribers.push(y);const T=d("emojiStatusSet",()=>{t("emoji_status_set",{})});this.unsubscribers.push(T);const E=d("emojiStatusFailed",e=>{t("emoji_status_failed",{error:e?.error})});this.unsubscribers.push(E);const L=d("emojiStatusAccessRequested",e=>{t("emoji_status_access_requested",{status:e?.status})});this.unsubscribers.push(L);const S=d("settingsButtonClicked",()=>{t("settings_button_clicked",{})});this.unsubscribers.push(S);const x=d("secondaryButtonClicked",()=>{t("secondary_button_clicked",{})});this.unsubscribers.push(x);const q=d("shareMessageSent",()=>{t("share_message_sent",{})});this.unsubscribers.push(q);const A=d("shareMessageFailed",e=>{t("share_message_failed",{error:e?.error})});this.unsubscribers.push(A);const D=d("locationManagerUpdated",()=>{const s=e?.LocationManager;t("location_manager_updated",{is_inited:s?.isInited,is_location_available:s?.isLocationAvailable,is_access_requested:s?.isAccessRequested,is_access_granted:s?.isAccessGranted})});this.unsubscribers.push(D);const I=d("locationRequested",e=>{t("location_requested",{available:!1!==e?.available,latitude:e?.latitude,longitude:e?.longitude,altitude:e?.altitude,course:e?.course,speed:e?.speed,horizontal_accuracy:e?.horizontal_accuracy,vertical_accuracy:e?.vertical_accuracy,course_accuracy:e?.course_accuracy,speed_accuracy:e?.speed_accuracy})});this.unsubscribers.push(I);const P=d("accelerometerStarted",()=>{t("accelerometer_started",{})});this.unsubscribers.push(P);const C=d("accelerometerStopped",()=>{t("accelerometer_stopped",{})});this.unsubscribers.push(C);const M=d("accelerometerChanged",()=>{const s=e?.Accelerometer;t("accelerometer_changed",{x:s?.x,y:s?.y,z:s?.z})});this.unsubscribers.push(M);const O=d("accelerometerFailed",e=>{t("accelerometer_failed",{error:e?.error})});this.unsubscribers.push(O);const z=d("deviceOrientationStarted",()=>{t("device_orientation_started",{})});this.unsubscribers.push(z);const R=d("deviceOrientationStopped",()=>{t("device_orientation_stopped",{})});this.unsubscribers.push(R);const j=d("deviceOrientationChanged",()=>{const s=e?.DeviceOrientation;t("device_orientation_changed",{absolute:s?.absolute,alpha:s?.alpha,beta:s?.beta,gamma:s?.gamma})});this.unsubscribers.push(j);const F=d("deviceOrientationFailed",e=>{t("device_orientation_failed",{error:e?.error})});this.unsubscribers.push(F);const N=d("gyroscopeStarted",()=>{t("gyroscope_started",{})});this.unsubscribers.push(N);const U=d("gyroscopeStopped",()=>{t("gyroscope_stopped",{})});this.unsubscribers.push(U);const B=d("gyroscopeChanged",()=>{const s=e?.Gyroscope;t("gyroscope_changed",{x:s?.x,y:s?.y,z:s?.z})});this.unsubscribers.push(B);const $=d("gyroscopeFailed",e=>{t("gyroscope_failed",{error:e?.error})});this.unsubscribers.push($);const V=d("contactRequested",e=>{t("contact_requested",{status:e?.status})});this.unsubscribers.push(V);const H=d("activated",()=>{t("activated",{})});this.unsubscribers.push(H);const W=d("deactivated",()=>{t("deactivated",{})});this.unsubscribers.push(W);const G=d("biometricManagerUpdated",()=>{const s=e?.BiometricManager;t("biometric_manager_updated",{is_inited:s?.isInited,is_biometric_available:s?.isBiometricAvailable,biometric_type:s?.biometricType,is_access_requested:s?.isAccessRequested,is_access_granted:s?.isAccessGranted,is_biometric_token_saved:s?.isBiometricTokenSaved,device_id:s?.deviceId})});this.unsubscribers.push(G);const Q=d("biometricAuthRequested",e=>{t("biometric_auth_requested",{is_authenticated:e?.isAuthenticated,biometric_token:e?.biometricToken})});this.unsubscribers.push(Q);const K=d("biometricTokenUpdated",e=>{t("biometric_token_updated",{is_updated:e?.isUpdated})});this.unsubscribers.push(K),this.patchWebAppMethods(e,t)}patchWebAppMethods(e,t){if(e&&!e.openLink?._dashgramPatched){if(e.openLink&&"function"==typeof e.openLink){const s=e.openLink.bind(e),i=(e,i)=>(t("open_link",{url:e,options:i}),s(e,i));i._dashgramPatched=!0,e.openLink=i}if(e.openTelegramLink&&"function"==typeof e.openTelegramLink){const s=e.openTelegramLink.bind(e),i=e=>(t("open_telegram_link",{url:e}),s(e));i._dashgramPatched=!0,e.openTelegramLink=i}if(e.switchInlineQuery&&"function"==typeof e.switchInlineQuery){const s=e.switchInlineQuery.bind(e),i=(e,i)=>(t("switch_inline_query",{query:e,choose_chat_types:i}),s(e,i));i._dashgramPatched=!0,e.switchInlineQuery=i}if(e.shareToStory&&"function"==typeof e.shareToStory){const s=e.shareToStory.bind(e),i=(e,i)=>(t("share_story",{media_url:e,params:i}),s(e,i));i._dashgramPatched=!0,e.shareToStory=i}if(e.close&&"function"==typeof e.close){const s=e.close.bind(e),i=e=>(t("webapp_close",{return_back:e?.return_back}),s(e));i._dashgramPatched=!0,e.close=i}if(e.exitFullscreen&&"function"==typeof e.exitFullscreen){const s=e.exitFullscreen.bind(e),i=()=>(t("webapp_exit_fullscreen",{}),s());i._dashgramPatched=!0,e.exitFullscreen=i}if(e.openInvoice&&"function"==typeof e.openInvoice){const s=e.openInvoice.bind(e),i=(e,i)=>(t("open_invoice",{slug:e}),s(e,i));i._dashgramPatched=!0,e.openInvoice=i}if(e.requestAccess&&"function"==typeof e.requestAccess){const s=e.requestAccess.bind(e),i=(e,i)=>(t("request_access",{access_type:e}),s(e,i));i._dashgramPatched=!0,e.requestAccess=i}if(e.requestContact&&"function"==typeof e.requestContact){const s=e.requestContact.bind(e),i=e=>(t("request_contact",{}),s(e));i._dashgramPatched=!0,e.requestContact=i}if(e.requestPhone&&"function"==typeof e.requestPhone){const s=e.requestPhone.bind(e),i=e=>(t("request_phone",{}),s(e));i._dashgramPatched=!0,e.requestPhone=i}if(e.requestLocation&&"function"==typeof e.requestLocation){const s=e.requestLocation.bind(e),i=e=>(t("request_location",{}),s(e));i._dashgramPatched=!0,e.requestLocation=i}if(e.checkLocation&&"function"==typeof e.checkLocation){const s=e.checkLocation.bind(e),i=e=>(t("check_location",{}),s(e));i._dashgramPatched=!0,e.checkLocation=i}}}}const L=new class{constructor(){this.config=null,this.context=null,this.transport=null,this.batchProcessor=null,this.trackers=[],this.isInitialized=!1}init(e){if(this.isInitialized)e.debug&&console.warn("Dashgram: Already initialized");else if("undefined"!=typeof window&&"undefined"!=typeof document)try{this.config=new o(e),"undefined"!=typeof window&&(window.__DASHGRAM_DEBUG__=this.config.isDebug()),this.context=new p,this.transport=new v(this.config),this.batchProcessor=new k(this.config,this.transport),this.setupTrackers(),this.batchProcessor.start(),this.isInitialized=!0,this.log("Initialized successfully",{projectId:this.config.get("projectId"),trackLevel:this.config.getTrackLevel()})}catch(e){throw console.error("Dashgram: Initialization failed",e),e}else e.debug&&console.warn("Dashgram: Not running in browser environment")}setupTrackers(){if(!this.config)return;const e=(e,t)=>{this.trackAuto(e,t)},t=new y(this.config,e);this.trackers.push(t),t.start();const s=new T(this.config,e);this.trackers.push(s),s.start();const i=new E(this.config,e);this.trackers.push(i),i.start()}track(e,t={}){this.ensureInitialized();const s=this.buildEvent(e,t,"manual");this.batchProcessor.addEvent(s),this.log("Tracked event",{event:e,properties:t})}trackAuto(e,t={}){if(!this.isInitialized)return;const s=this.buildEvent(e,t,"auto");this.batchProcessor.addEvent(s),this.log("Auto-tracked event",{event:e,properties:t})}buildEvent(e,t,s){return this.ensureInitialized(),{eventId:"undefined"!=typeof crypto&&crypto.randomUUID?crypto.randomUUID():"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g,e=>{const t=16*Math.random()|0;return("x"===e?t:3&t|8).toString(16)}),type:e,initData:a(),properties:Object.keys(t).length>0?t:void 0,telemetry:this.context.getTelemetry(),source:s,level:this.config.getTrackLevel(),timestamp:Date.now()}}setTrackLevel(e){this.ensureInitialized();const t=this.config.getTrackLevel();this.config.setTrackLevel(e),this.trackers.forEach(e=>{e.stop(),e.start()}),this.log("Track level changed",{from:t,to:e})}async flush(){this.ensureInitialized(),await this.batchProcessor.flushAsync(),this.log("Flushed all events")}shutdown(){this.isInitialized&&(this.trackers.forEach(e=>e.stop()),this.trackers=[],this.batchProcessor.flush(),this.batchProcessor.stop(),this.isInitialized=!1,this.log("Shutdown complete"))}ensureInitialized(){if(!this.isInitialized)throw new Error("Dashgram: SDK not initialized. Call init() first.")}log(...e){this.config?.isDebug()&&console.log("[Dashgram SDK]",...e)}};e.DashgramAPIError=s,e.DashgramConfigurationError=n,e.DashgramError=t,e.DashgramMini=L,e.NetworkError=i,e.default=L,Object.defineProperty(e,"__esModule",{value:!0})});
|
|
1
|
+
var DashgramMini=function(){"use strict";class e extends Error{constructor(t){super(t),this.name="DashgramError";const s=Error;"function"==typeof s.captureStackTrace&&s.captureStackTrace(this,e)}}class t extends e{constructor(e,s){super(`Dashgram API error (${e}): ${s}`),this.statusCode=e,this.details=s,this.name="DashgramAPIError";const i=Error;"function"==typeof i.captureStackTrace&&i.captureStackTrace(this,t)}}class s extends e{constructor(e){super(`Network error: ${e.message}`),this.originalError=e,this.name="NetworkError";const t=Error;"function"==typeof t.captureStackTrace&&t.captureStackTrace(this,s)}}class i extends e{constructor(e){super(e),this.name="DashgramConfigurationError";const t=Error;"function"==typeof t.captureStackTrace&&t.captureStackTrace(this,i)}}const n={trackLevel:1,apiUrl:"https://api.dashgram.io/v1",batchSize:10,flushInterval:5e3,debug:!1,disabled:!1};class r{constructor(e){this.config={...n,...e},this.validate()}validate(){if(!this.config.projectId)throw new i("projectId is required");if(![1,2,3].includes(this.config.trackLevel))throw new i("trackLevel must be 1, 2, or 3")}get(e){return this.config[e]}getOnError(){return this.config.onError}getTrackUrl(){return`${this.config.apiUrl.replace(/\/$/,"")}/${this.config.projectId}/webapp/track`}setTrackLevel(e){if(![1,2,3].includes(e))throw new i("trackLevel must be 1, 2, or 3");this.config.trackLevel=e}getTrackLevel(){return this.config.trackLevel}isDebug(){return this.config.debug}isDisabled(){return this.config.disabled}}function o(){if("undefined"==typeof window)return null;const e=window;return e.Telegram?.WebApp||null}function c(){const e=o();return e?.initData||""}function a(){const e=o();return e?.platform||"unknown"}function u(){const e=o();if(e?.colorScheme)return e.colorScheme;if(e?.themeParams?.bg_color){const t=e.themeParams.bg_color;try{const e=parseInt(t.slice(1),16);return.2126*(e>>16&255)+.7152*(e>>8&255)+.0722*(255&e)<128?"dark":"light"}catch{return}}}function h(e,t){const s=o();if(!s||!s.onEvent)return()=>{};try{const i=(s,i)=>{try{t(i)}catch(t){"undefined"!=typeof window&&window.__DASHGRAM_DEBUG__&&console.warn(`[Dashgram] Error in Telegram event callback for ${e}:`,t)}};return s.onEvent(e,i),()=>{try{s.offEvent&&s.offEvent(e,i)}catch{}}}catch{return()=>{}}}function d(){return"undefined"==typeof window?{platform:"unknown"}:{platform:a(),user_agent:navigator.userAgent,timezone:Intl.DateTimeFormat().resolvedOptions().timeZone||void 0,theme:u()}}class l{constructor(){this.telemetry=d()}getTelemetry(){return{...this.telemetry}}updateTelemetry(){this.telemetry=d()}}function p(e,t){let s=null,i=0;return function(...n){const r=Date.now(),o=t-(r-i);o<=0||o>t?(s&&(clearTimeout(s),s=null),i=r,e.apply(this,n)):s||(s=setTimeout(()=>{i=Date.now(),s=null,e.apply(this,n)},o))}}function g(e){try{return JSON.stringify(e)}catch(e){return"{}"}}function b(e){if(e.id)return`#${e.id}`;if(e.className&&"string"==typeof e.className){const t=e.className.trim().split(/\s+/).slice(0,2).join(".");if(t)return`${e.tagName.toLowerCase()}.${t}`}return e.tagName.toLowerCase()}function f(e,t=50){const s=e.textContent?.trim()||"";return s.length>t?s.substring(0,t)+"...":s}class m{constructor(e){this.isOnline=!0,this.pendingRequests=new Set,this.config=e,this.setupOnlineListener()}setupOnlineListener(){"undefined"!=typeof window&&(window.addEventListener("online",()=>{this.isOnline=!0,this.log("Connection restored")}),window.addEventListener("offline",()=>{this.isOnline=!1,this.log("Connection lost")}),this.isOnline=navigator.onLine)}buildPayload(e){return{origin:("undefined"==typeof window?"":window.location.origin)||void 0,updates:e}}async send(e){if(0===e.length)return;if(this.config.isDisabled())return void this.log("Tracking disabled, skipping send");if(!this.isOnline)return void this.log("Offline, skipping send");const i=this.sendRequest(e);this.pendingRequests.add(i);try{await i}catch(e){this.logError("Failed to send events:",e);const i=this.config.getOnError();if(i)try{e instanceof t||e instanceof s?i(e):e instanceof Error&&i(new s(e))}catch(e){this.logError("Error in onError callback:",e)}}finally{this.pendingRequests.delete(i)}}async sendRequest(e){const i=this.config.getTrackUrl(),n=this.buildPayload(e);try{const s=await fetch(i,{method:"POST",headers:{"Content-Type":"application/json"},body:g(n),keepalive:!0});if(!s.ok){let e=s.statusText;try{const t=await s.json();e=t.details||t.message||e}catch{}throw new t(s.status,e)}this.log(`Sent ${e.length} events successfully`)}catch(e){if(e instanceof t)throw e;if(e instanceof Error)throw new s(e);throw new s(new Error(String(e)))}}sendBeacon(e){if(0===e.length)return!0;if(this.config.isDisabled())return!0;if("undefined"==typeof navigator||!navigator.sendBeacon)return!1;const t=this.config.getTrackUrl(),s=this.buildPayload(e),i=new Blob([g(s)],{type:"application/json"}),n=navigator.sendBeacon(t,i);return this.log(`sendBeacon ${n?"succeeded":"failed"} for ${e.length} events`),n}async flush(){await Promise.all(Array.from(this.pendingRequests))}log(...e){this.config.isDebug()&&console.log("[Dashgram Transport]",...e)}logError(...e){this.config.isDebug()&&console.error("[Dashgram Transport]",...e)}}class v{constructor(e=100){this.queue=[],this.maxSize=e}enqueue(e){this.queue.push(e),this.queue.length>this.maxSize&&this.queue.shift()}flush(){const e=[...this.queue];return this.queue=[],e}peek(){return[...this.queue]}size(){return this.queue.length}isEmpty(){return 0===this.queue.length}clear(){this.queue=[]}}class _{constructor(e,t){this.flushTimer=null,this.isStarted=!1,this.config=e,this.transport=t,this.queue=new v(200)}start(){this.isStarted||(this.isStarted=!0,this.scheduleFlush(),this.setupPageUnloadHandler())}stop(){this.isStarted=!1,this.flushTimer&&(clearTimeout(this.flushTimer),this.flushTimer=null)}addEvent(e){this.queue.enqueue(e);const t=this.config.get("batchSize");this.queue.size()>=t&&this.flush()}scheduleFlush(){this.flushTimer&&clearTimeout(this.flushTimer);const e=this.config.get("flushInterval");this.flushTimer=setTimeout(()=>{this.flush(),this.isStarted&&this.scheduleFlush()},e)}flush(){const e=this.queue.flush();e.length>0&&this.transport.send(e)}async flushAsync(){const e=this.queue.flush();e.length>0&&await this.transport.send(e),await this.transport.flush()}setupPageUnloadHandler(){if("undefined"==typeof window)return;const e=()=>{const e=this.queue.flush();e.length>0&&this.transport.sendBeacon(e)};window.addEventListener("visibilitychange",()=>{"hidden"===document.visibilityState&&e()}),window.addEventListener("pagehide",e),window.addEventListener("beforeunload",e)}}class k{constructor(e,t,s){this.isActive=!1,this.config=e,this.trackCallback=t,this.level=s}start(){if(this.isActive)return;this.config.getTrackLevel()>=this.level&&(this.isActive=!0,this.setup(),this.log(`Started (level ${this.level})`))}stop(){this.isActive&&(this.isActive=!1,this.teardown(),this.log("Stopped"))}track(e,t={}){this.isActive&&this.trackCallback(e,t)}log(...e){this.config.isDebug()&&console.log(`[Dashgram ${this.constructor.name}]`,...e)}}class w extends k{constructor(e,t){super(e,t,1),this.unsubscribers=[],this.hasTrackedAppOpen=!1}setup(){"undefined"!=typeof window&&(this.trackAppOpen(),this.setupVisibilityTracking(),this.setupUnloadTracking())}teardown(){this.unsubscribers.forEach(e=>e()),this.unsubscribers=[]}trackAppOpen(){this.hasTrackedAppOpen||(this.track("app_open",{referrer:document.referrer||"direct"}),this.hasTrackedAppOpen=!0)}setupVisibilityTracking(){const e=()=>{"hidden"===document.visibilityState?this.track("app_close",{visibility_state:"hidden"}):"visible"===document.visibilityState&&this.track("app_open",{visibility_state:"visible"})};document.addEventListener("visibilitychange",e),this.unsubscribers.push(()=>{document.removeEventListener("visibilitychange",e)})}setupUnloadTracking(){const e=()=>{this.track("app_close",{reason:"unload"})};window.addEventListener("pagehide",e),this.unsubscribers.push(()=>{window.removeEventListener("pagehide",e)}),window.addEventListener("beforeunload",e),this.unsubscribers.push(()=>{window.removeEventListener("beforeunload",e)})}}class y extends k{constructor(e,t){super(e,t,2),this.unsubscribers=[],this.lastPath="",this.inputValues=new Map}setup(){"undefined"!=typeof window&&(this.trackScreenView(),this.setupHistoryTracking(),this.setupClickTracking(),this.setupFormTracking(),this.setupInputTracking(),this.setupClipboardTracking(),this.setupSelectionTracking(),this.setupErrorTracking())}teardown(){this.unsubscribers.forEach(e=>e()),this.unsubscribers=[]}trackScreenView(){const e="undefined"==typeof window?"":window.location.pathname;e!==this.lastPath&&(this.lastPath=e,this.track("screen_view",{path:e,url:"undefined"==typeof window?"":window.location.href,title:"undefined"==typeof document?"":document.title||"",referrer:document.referrer||"direct"}))}setupHistoryTracking(){const e=history.pushState,t=history.replaceState,s=()=>{this.trackScreenView()};history.pushState=function(...t){e.apply(history,t),s()},history.replaceState=function(...e){t.apply(history,e),s()},window.addEventListener("popstate",s),this.unsubscribers.push(()=>{history.pushState=e,history.replaceState=t,window.removeEventListener("popstate",s)})}setupClickTracking(){const e=e=>{const t=e.target;if(!t)return;const s=t.closest('button, [role="button"], a');if(s){if("a"===s.tagName.toLowerCase()){const e=s,t=e.href,i=!!t&&this.isExternalLink(t);this.track("link_click",{element:b(s),text:f(s),href:t||void 0,target:e.target||void 0,is_external:i,is_download:e.hasAttribute("download")})}else this.track("button_click",{element:b(s),text:f(s)})}};document.addEventListener("click",e,{capture:!0}),this.unsubscribers.push(()=>{document.removeEventListener("click",e,{capture:!0})})}isExternalLink(e){try{return new URL(e,window.location.href).origin!==window.location.origin}catch{return!1}}setupFormTracking(){const e=e=>{const t=e.target;t&&this.track("form_submit",{form_id:t.id||void 0,form_name:t.name||void 0,form_action:t.action||void 0,form_method:t.method||void 0})};document.addEventListener("submit",e,{capture:!0}),this.unsubscribers.push(()=>{document.removeEventListener("submit",e,{capture:!0})})}setupInputTracking(){const e=p(e=>{const t=e.target;if(!t)return;const s=t.tagName.toLowerCase();if(["input","textarea","select"].includes(s)){const e=t;this.inputValues.set(t,e.value||""),this.track("input_focus",{element:b(e),input_type:e.type||s,input_name:e.name||void 0,input_id:e.id||void 0})}},1e3),t=e=>{const t=e.target;if(!t)return;const s=t.tagName.toLowerCase();if(["input","textarea","select"].includes(s)){const e=t,i=this.inputValues.get(t),n=e.value||"";void 0!==i&&i!==n&&this.track("input_change",{element:b(e),input_type:e.type||s,input_name:e.name||void 0,input_id:e.id||void 0,had_value:i.length>0,has_value:n.length>0}),this.inputValues.delete(t)}};document.addEventListener("focus",e,{capture:!0}),document.addEventListener("blur",t,{capture:!0}),this.unsubscribers.push(()=>{document.removeEventListener("focus",e,{capture:!0}),document.removeEventListener("blur",t,{capture:!0}),this.inputValues.clear()})}setupClipboardTracking(){const e=e=>{const t=window.getSelection(),s=t?.toString()||"";this.track("copy",{text_length:s.length,has_selection:s.length>0})},t=e=>{const t=window.getSelection(),s=t?.toString()||"";this.track("cut",{text_length:s.length,has_selection:s.length>0})},s=e=>{const t=e.clipboardData?.getData("text")||"",s=e.target;this.track("paste",{text_length:t.length,target_element:s?b(s):void 0})};document.addEventListener("copy",e),document.addEventListener("cut",t),document.addEventListener("paste",s),this.unsubscribers.push(()=>{document.removeEventListener("copy",e),document.removeEventListener("cut",t),document.removeEventListener("paste",s)})}setupSelectionTracking(){let e;const t=()=>{clearTimeout(e),e=setTimeout(()=>{const e=window.getSelection(),t=e?.toString()||"";t.length>0&&this.track("text_select",{text_length:t.length})},500)};document.addEventListener("selectionchange",t),this.unsubscribers.push(()=>{document.removeEventListener("selectionchange",t),clearTimeout(e)})}setupErrorTracking(){const e=e=>{this.track("js_error",{message:e.message,filename:e.filename,lineno:e.lineno,colno:e.colno,stack:e.error?.stack})};window.addEventListener("error",e),this.unsubscribers.push(()=>{window.removeEventListener("error",e)});const t=e=>{this.track("unhandled_rejection",{reason:String(e.reason),promise:String(e.promise)})};window.addEventListener("unhandledrejection",t),this.unsubscribers.push(()=>{window.removeEventListener("unhandledrejection",t)})}}class T extends k{constructor(e,t){super(e,t,3),this.unsubscribers=[],this.observers=[],this.clickTracker=new Map,this.maxScrollDepth=0,this.trackedMedia=new WeakSet}setup(){"undefined"!=typeof window&&(this.setupScrollTracking(),this.setupVisibilityTracking(),this.setupRageClickTracking(),this.setupLongTaskTracking(),this.setupWebVitals(),this.setupNetworkTracking(),this.setupOrientationTracking(),this.setupMediaTracking(),this.setupTelegramTracking())}teardown(){this.unsubscribers.forEach(e=>e()),this.unsubscribers=[],this.observers.forEach(e=>e.disconnect()),this.observers=[],this.clickTracker.clear()}getScrollDepth(){const e=window.innerHeight,t=document.documentElement.scrollHeight,s=window.pageYOffset||document.documentElement.scrollTop;if(t<=e)return 100;const i=s/(t-e)*100;return Math.min(Math.round(i),100)}setupScrollTracking(){const e=p(()=>{const e=this.getScrollDepth();if(e>this.maxScrollDepth){this.maxScrollDepth=e;const t=[25,50,75,100].find(t=>e>=t&&this.maxScrollDepth-e<t);t&&this.track("scroll_depth",{depth:t,max_depth:this.maxScrollDepth})}},500);window.addEventListener("scroll",e,{passive:!0}),this.unsubscribers.push(()=>{window.removeEventListener("scroll",e)})}setupVisibilityTracking(){if(!("IntersectionObserver"in window))return;const e=new IntersectionObserver(t=>{t.forEach(t=>{if(t.isIntersecting){const s=t.target,i=s.getAttribute("data-track-visible");i&&(this.track("element_visible",{element:i,intersection_ratio:t.intersectionRatio}),e.unobserve(s))}})},{threshold:.5});document.querySelectorAll("[data-track-visible]").forEach(t=>{e.observe(t)}),this.observers.push(e);const t=new MutationObserver(t=>{t.forEach(t=>{t.addedNodes.forEach(t=>{t instanceof Element&&(t.hasAttribute("data-track-visible")&&e.observe(t),t.querySelectorAll("[data-track-visible]").forEach(t=>{e.observe(t)}))})})});t.observe(document.body,{childList:!0,subtree:!0}),this.unsubscribers.push(()=>{t.disconnect()})}setupRageClickTracking(){const e=e=>{const t=e.target;if(!t)return;const s=this.clickTracker.get(t);if(s)s.count++,clearTimeout(s.timer),s.count>=5?(this.track("rage_click",{element:t.tagName.toLowerCase(),click_count:s.count}),this.clickTracker.delete(t)):s.timer=setTimeout(()=>{this.clickTracker.delete(t)},2e3);else{const e=setTimeout(()=>{this.clickTracker.delete(t)},2e3);this.clickTracker.set(t,{count:1,timer:e})}};document.addEventListener("click",e),this.unsubscribers.push(()=>{document.removeEventListener("click",e)})}setupLongTaskTracking(){if("PerformanceObserver"in window)try{const e=new PerformanceObserver(e=>{for(const t of e.getEntries())t.duration>50&&this.track("long_task",{duration:Math.round(t.duration),start_time:Math.round(t.startTime)})});e.observe({entryTypes:["longtask"]}),this.observers.push(e)}catch(e){this.log("Long task tracking not supported")}}setupWebVitals(){if(!("PerformanceObserver"in window))return;try{const e=new PerformanceObserver(e=>{const t=e.getEntries(),s=t[t.length-1];this.track("web_vital_lcp",{value:Math.round(s.renderTime||s.loadTime),element:s.element?.tagName.toLowerCase()})});e.observe({entryTypes:["largest-contentful-paint"]}),this.observers.push(e)}catch(e){this.log("LCP tracking not supported")}try{const e=new PerformanceObserver(e=>{e.getEntries().forEach(e=>{this.track("web_vital_fid",{value:Math.round(e.processingStart-e.startTime),event_type:e.name})})});e.observe({entryTypes:["first-input"]}),this.observers.push(e)}catch(e){this.log("FID tracking not supported")}let e=0;try{const t=new PerformanceObserver(t=>{t.getEntries().forEach(t=>{t.hadRecentInput||(e+=t.value)})});t.observe({entryTypes:["layout-shift"]}),this.observers.push(t);const s=()=>{e>0&&this.track("web_vital_cls",{value:Math.round(1e3*e)/1e3})};window.addEventListener("visibilitychange",()=>{"hidden"===document.visibilityState&&s()}),this.unsubscribers.push(()=>{s()})}catch(e){this.log("CLS tracking not supported")}}setupNetworkTracking(){const e=()=>{this.track("network_status",{status:"online",effective_type:navigator.connection?.effectiveType,downlink:navigator.connection?.downlink,rtt:navigator.connection?.rtt})},t=()=>{this.track("network_status",{status:"offline"})};window.addEventListener("online",e),window.addEventListener("offline",t),this.unsubscribers.push(()=>{window.removeEventListener("online",e),window.removeEventListener("offline",t)});const s=navigator.connection;if(s){const e=()=>{this.track("network_change",{effective_type:s.effectiveType,downlink:s.downlink,rtt:s.rtt,save_data:s.saveData})};s.addEventListener("change",e),this.unsubscribers.push(()=>{s.removeEventListener("change",e)})}}setupOrientationTracking(){const e=()=>{const e=screen.orientation?.type||(window.innerWidth>window.innerHeight?"landscape":"portrait");this.track("orientation_change",{orientation:e,angle:screen.orientation?.angle,width:window.innerWidth,height:window.innerHeight})};screen.orientation?(screen.orientation.addEventListener("change",e),this.unsubscribers.push(()=>{screen.orientation.removeEventListener("change",e)})):(window.addEventListener("orientationchange",e),this.unsubscribers.push(()=>{window.removeEventListener("orientationchange",e)}))}setupMediaTracking(){const e=e=>{const t=e.target;if(!t||this.trackedMedia.has(t))return;const s=t.tagName.toLowerCase(),i=e.type,n={media_type:s,src:t.currentSrc||t.src,duration:isFinite(t.duration)?Math.round(t.duration):void 0,current_time:Math.round(t.currentTime),muted:t.muted,volume:Math.round(100*t.volume)};"play"===i?this.track("media_play",n):"pause"===i?this.track("media_pause",{...n,percent_played:t.duration?Math.round(t.currentTime/t.duration*100):0}):"ended"===i?this.track("media_ended",{...n,completed:!0}):"error"===i&&this.track("media_error",{media_type:s,src:t.currentSrc||t.src,error:t.error?.message||"unknown"})},t=t=>{this.trackedMedia.has(t)||(this.trackedMedia.add(t),t.addEventListener("play",e),t.addEventListener("pause",e),t.addEventListener("ended",e),t.addEventListener("error",e))};document.querySelectorAll("video, audio").forEach(e=>{t(e)});const s=new MutationObserver(e=>{e.forEach(e=>{e.addedNodes.forEach(e=>{e instanceof HTMLMediaElement&&t(e),e instanceof Element&&e.querySelectorAll("video, audio").forEach(e=>{t(e)})})})});s.observe(document.body,{childList:!0,subtree:!0}),this.observers.push(s)}setupTelegramTracking(){const e=window.Telegram?.WebApp,t=(e,t)=>{this.track(`telegram_${e}`,t||{})},s=h("themeChanged",()=>{t("theme_changed",{color_scheme:e?.colorScheme,theme_params:e?.themeParams})});this.unsubscribers.push(s);const i=h("viewportChanged",s=>{t("viewport_changed",{is_state_stable:s?.isStateStable,is_expanded:e?.isExpanded,viewport_height:e?.viewportHeight,viewport_stable_height:e?.viewportStableHeight})});this.unsubscribers.push(i);const n=h("safeAreaChanged",()=>{t("safe_area_changed",{safe_area:e?.safeAreaInset})});this.unsubscribers.push(n);const r=h("contentSafeAreaChanged",()=>{t("content_safe_area_changed",{content_safe_area:e?.contentSafeAreaInset})});this.unsubscribers.push(r);const o=h("backButtonClicked",()=>{t("back_button_clicked",{})});this.unsubscribers.push(o);const c=h("mainButtonClicked",()=>{t("main_button_clicked",{button_text:e?.MainButton?.text})});this.unsubscribers.push(c);const a=h("invoiceClosed",e=>{t("invoice_closed",{url:e?.url,status:e?.status})});this.unsubscribers.push(a);const u=h("popupClosed",e=>{t("popup_closed",{button_id:e?.button_id})});this.unsubscribers.push(u);const d=h("qrTextReceived",e=>{t("qr_text_received",{data:e?.data})});this.unsubscribers.push(d);const l=h("scanQrPopupClosed",()=>{t("scan_qr_popup_closed",{})});this.unsubscribers.push(l);const p=h("clipboardTextReceived",e=>{t("clipboard_text_received",{data:e?.data})});this.unsubscribers.push(p);const g=h("writeAccessRequested",e=>{t("write_access_requested",{status:e?.status})});this.unsubscribers.push(g);const b=h("fileDownloadRequested",e=>{t("file_download_requested",{status:e?.status})});this.unsubscribers.push(b);const f=h("customMethodInvoked",e=>{t("custom_method_invoked",{req_id:e?.req_id,result:e?.result,error:e?.error})});this.unsubscribers.push(f);const m=h("fullscreenChanged",e=>{t("fullscreen_changed",{is_fullscreen:e?.isFullscreen})});this.unsubscribers.push(m);const v=h("fullscreenFailed",e=>{t("fullscreen_failed",{error:e?.error})});this.unsubscribers.push(v);const _=h("homeScreenAdded",()=>{t("home_screen_added",{})});this.unsubscribers.push(_);const k=h("homeScreenChecked",e=>{t("home_screen_checked",{status:e?.status})});this.unsubscribers.push(k);const w=h("preparedMessageSent",()=>{t("prepared_message_sent",{})});this.unsubscribers.push(w);const y=h("preparedMessageFailed",e=>{t("prepared_message_failed",{error:e?.error})});this.unsubscribers.push(y);const T=h("emojiStatusSet",()=>{t("emoji_status_set",{})});this.unsubscribers.push(T);const E=h("emojiStatusFailed",e=>{t("emoji_status_failed",{error:e?.error})});this.unsubscribers.push(E);const L=h("emojiStatusAccessRequested",e=>{t("emoji_status_access_requested",{status:e?.status})});this.unsubscribers.push(L);const S=h("settingsButtonClicked",()=>{t("settings_button_clicked",{})});this.unsubscribers.push(S);const x=h("secondaryButtonClicked",()=>{t("secondary_button_clicked",{})});this.unsubscribers.push(x);const q=h("shareMessageSent",()=>{t("share_message_sent",{})});this.unsubscribers.push(q);const A=h("shareMessageFailed",e=>{t("share_message_failed",{error:e?.error})});this.unsubscribers.push(A);const D=h("locationManagerUpdated",()=>{const s=e?.LocationManager;t("location_manager_updated",{is_inited:s?.isInited,is_location_available:s?.isLocationAvailable,is_access_requested:s?.isAccessRequested,is_access_granted:s?.isAccessGranted})});this.unsubscribers.push(D);const I=h("locationRequested",e=>{t("location_requested",{available:!1!==e?.available,latitude:e?.latitude,longitude:e?.longitude,altitude:e?.altitude,course:e?.course,speed:e?.speed,horizontal_accuracy:e?.horizontal_accuracy,vertical_accuracy:e?.vertical_accuracy,course_accuracy:e?.course_accuracy,speed_accuracy:e?.speed_accuracy})});this.unsubscribers.push(I);const P=h("accelerometerStarted",()=>{t("accelerometer_started",{})});this.unsubscribers.push(P);const C=h("accelerometerStopped",()=>{t("accelerometer_stopped",{})});this.unsubscribers.push(C);const M=h("accelerometerChanged",()=>{const s=e?.Accelerometer;t("accelerometer_changed",{x:s?.x,y:s?.y,z:s?.z})});this.unsubscribers.push(M);const O=h("accelerometerFailed",e=>{t("accelerometer_failed",{error:e?.error})});this.unsubscribers.push(O);const z=h("deviceOrientationStarted",()=>{t("device_orientation_started",{})});this.unsubscribers.push(z);const R=h("deviceOrientationStopped",()=>{t("device_orientation_stopped",{})});this.unsubscribers.push(R);const F=h("deviceOrientationChanged",()=>{const s=e?.DeviceOrientation;t("device_orientation_changed",{absolute:s?.absolute,alpha:s?.alpha,beta:s?.beta,gamma:s?.gamma})});this.unsubscribers.push(F);const j=h("deviceOrientationFailed",e=>{t("device_orientation_failed",{error:e?.error})});this.unsubscribers.push(j);const U=h("gyroscopeStarted",()=>{t("gyroscope_started",{})});this.unsubscribers.push(U);const N=h("gyroscopeStopped",()=>{t("gyroscope_stopped",{})});this.unsubscribers.push(N);const B=h("gyroscopeChanged",()=>{const s=e?.Gyroscope;t("gyroscope_changed",{x:s?.x,y:s?.y,z:s?.z})});this.unsubscribers.push(B);const $=h("gyroscopeFailed",e=>{t("gyroscope_failed",{error:e?.error})});this.unsubscribers.push($);const V=h("contactRequested",e=>{t("contact_requested",{status:e?.status})});this.unsubscribers.push(V);const H=h("activated",()=>{t("activated",{})});this.unsubscribers.push(H);const W=h("deactivated",()=>{t("deactivated",{})});this.unsubscribers.push(W);const G=h("biometricManagerUpdated",()=>{const s=e?.BiometricManager;t("biometric_manager_updated",{is_inited:s?.isInited,is_biometric_available:s?.isBiometricAvailable,biometric_type:s?.biometricType,is_access_requested:s?.isAccessRequested,is_access_granted:s?.isAccessGranted,is_biometric_token_saved:s?.isBiometricTokenSaved,device_id:s?.deviceId})});this.unsubscribers.push(G);const Q=h("biometricAuthRequested",e=>{t("biometric_auth_requested",{is_authenticated:e?.isAuthenticated,biometric_token:e?.biometricToken})});this.unsubscribers.push(Q);const K=h("biometricTokenUpdated",e=>{t("biometric_token_updated",{is_updated:e?.isUpdated})});this.unsubscribers.push(K),this.patchWebAppMethods(e,t)}patchWebAppMethods(e,t){if(e&&!e.openLink?._dashgramPatched){if(e.openLink&&"function"==typeof e.openLink){const s=e.openLink.bind(e),i=(e,i)=>(t("open_link",{url:e,options:i}),s(e,i));i._dashgramPatched=!0,e.openLink=i}if(e.openTelegramLink&&"function"==typeof e.openTelegramLink){const s=e.openTelegramLink.bind(e),i=e=>(t("open_telegram_link",{url:e}),s(e));i._dashgramPatched=!0,e.openTelegramLink=i}if(e.switchInlineQuery&&"function"==typeof e.switchInlineQuery){const s=e.switchInlineQuery.bind(e),i=(e,i)=>(t("switch_inline_query",{query:e,choose_chat_types:i}),s(e,i));i._dashgramPatched=!0,e.switchInlineQuery=i}if(e.shareToStory&&"function"==typeof e.shareToStory){const s=e.shareToStory.bind(e),i=(e,i)=>(t("share_story",{media_url:e,params:i}),s(e,i));i._dashgramPatched=!0,e.shareToStory=i}if(e.close&&"function"==typeof e.close){const s=e.close.bind(e),i=e=>(t("webapp_close",{return_back:e?.return_back}),s(e));i._dashgramPatched=!0,e.close=i}if(e.exitFullscreen&&"function"==typeof e.exitFullscreen){const s=e.exitFullscreen.bind(e),i=()=>(t("webapp_exit_fullscreen",{}),s());i._dashgramPatched=!0,e.exitFullscreen=i}if(e.openInvoice&&"function"==typeof e.openInvoice){const s=e.openInvoice.bind(e),i=(e,i)=>(t("open_invoice",{slug:e}),s(e,i));i._dashgramPatched=!0,e.openInvoice=i}if(e.requestAccess&&"function"==typeof e.requestAccess){const s=e.requestAccess.bind(e),i=(e,i)=>(t("request_access",{access_type:e}),s(e,i));i._dashgramPatched=!0,e.requestAccess=i}if(e.requestContact&&"function"==typeof e.requestContact){const s=e.requestContact.bind(e),i=e=>(t("request_contact",{}),s(e));i._dashgramPatched=!0,e.requestContact=i}if(e.requestPhone&&"function"==typeof e.requestPhone){const s=e.requestPhone.bind(e),i=e=>(t("request_phone",{}),s(e));i._dashgramPatched=!0,e.requestPhone=i}if(e.requestLocation&&"function"==typeof e.requestLocation){const s=e.requestLocation.bind(e),i=e=>(t("request_location",{}),s(e));i._dashgramPatched=!0,e.requestLocation=i}if(e.checkLocation&&"function"==typeof e.checkLocation){const s=e.checkLocation.bind(e),i=e=>(t("check_location",{}),s(e));i._dashgramPatched=!0,e.checkLocation=i}}}}return new class{constructor(){this.config=null,this.context=null,this.transport=null,this.batchProcessor=null,this.trackers=[],this.isInitialized=!1}init(e){if(this.isInitialized)e.debug&&console.warn("Dashgram: Already initialized");else if("undefined"!=typeof window&&"undefined"!=typeof document)try{this.config=new r(e),"undefined"!=typeof window&&(window.__DASHGRAM_DEBUG__=this.config.isDebug()),this.context=new l,this.transport=new m(this.config),this.batchProcessor=new _(this.config,this.transport),this.setupTrackers(),this.batchProcessor.start(),this.isInitialized=!0,this.log("Initialized successfully",{projectId:this.config.get("projectId"),trackLevel:this.config.getTrackLevel()})}catch(e){throw console.error("Dashgram: Initialization failed",e),e}else e.debug&&console.warn("Dashgram: Not running in browser environment")}setupTrackers(){if(!this.config)return;const e=(e,t)=>{this.trackAuto(e,t)},t=new w(this.config,e);this.trackers.push(t),t.start();const s=new y(this.config,e);this.trackers.push(s),s.start();const i=new T(this.config,e);this.trackers.push(i),i.start()}track(e,t={}){this.ensureInitialized();const s=this.buildEvent(e,t,"manual");this.batchProcessor.addEvent(s),this.log("Tracked event",{event:e,properties:t})}trackAuto(e,t={}){if(!this.isInitialized)return;const s=this.buildEvent(e,t,"auto");this.batchProcessor.addEvent(s),this.log("Auto-tracked event",{event:e,properties:t})}buildEvent(e,t,s){return this.ensureInitialized(),{eventId:"undefined"!=typeof crypto&&crypto.randomUUID?crypto.randomUUID():"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g,e=>{const t=16*Math.random()|0;return("x"===e?t:3&t|8).toString(16)}),type:e,initData:c(),properties:Object.keys(t).length>0?t:void 0,telemetry:this.context.getTelemetry(),source:s,level:this.config.getTrackLevel(),timestamp:Date.now()}}setTrackLevel(e){this.ensureInitialized();const t=this.config.getTrackLevel();this.config.setTrackLevel(e),this.trackers.forEach(e=>{e.stop(),e.start()}),this.log("Track level changed",{from:t,to:e})}async flush(){this.ensureInitialized(),await this.batchProcessor.flushAsync(),this.log("Flushed all events")}shutdown(){this.isInitialized&&(this.trackers.forEach(e=>e.stop()),this.trackers=[],this.batchProcessor.flush(),this.batchProcessor.stop(),this.isInitialized=!1,this.log("Shutdown complete"))}ensureInitialized(){if(!this.isInitialized)throw new Error("Dashgram: SDK not initialized. Call init() first.")}log(...e){this.config?.isDebug()&&console.log("[Dashgram SDK]",...e)}}}();
|
|
2
2
|
//# sourceMappingURL=dashgram.min.js.map
|
package/dist/dashgram.min.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dashgram.min.js","sources":["../src/errors.ts","../src/core/config.ts","../src/utils/telegram.ts","../src/utils/device.ts","../src/core/context.ts","../src/utils/helpers.ts","../src/transport/transport.ts","../src/core/event-queue.ts","../src/transport/batch-processor.ts","../src/trackers/base-tracker.ts","../src/trackers/core-tracker.ts","../src/trackers/interaction-tracker.ts","../src/trackers/deep-tracker.ts","../src/index.ts"],"sourcesContent":["/**\n * Extended ErrorConstructor interface for V8-specific methods\n */\ninterface ErrorConstructorWithCapture {\n captureStackTrace?(error: Error, constructor?: Function): void\n}\n\n/**\n * Base error class for all Dashgram SDK errors\n */\nexport class DashgramError extends Error {\n constructor(message: string) {\n super(message)\n this.name = \"DashgramError\"\n const ErrorWithCapture = Error as unknown as ErrorConstructorWithCapture\n if (typeof ErrorWithCapture.captureStackTrace === \"function\") {\n ErrorWithCapture.captureStackTrace(this, DashgramError)\n }\n }\n}\n\n/**\n * Error thrown when the Dashgram API returns an error response\n */\nexport class DashgramAPIError extends DashgramError {\n constructor(public statusCode: number, public details: string) {\n super(`Dashgram API error (${statusCode}): ${details}`)\n this.name = \"DashgramAPIError\"\n const ErrorWithCapture = Error as unknown as ErrorConstructorWithCapture\n if (typeof ErrorWithCapture.captureStackTrace === \"function\") {\n ErrorWithCapture.captureStackTrace(this, DashgramAPIError)\n }\n }\n}\n\n/**\n * Error thrown when a network request fails\n */\nexport class NetworkError extends DashgramError {\n constructor(public originalError: Error) {\n super(`Network error: ${originalError.message}`)\n this.name = \"NetworkError\"\n const ErrorWithCapture = Error as unknown as ErrorConstructorWithCapture\n if (typeof ErrorWithCapture.captureStackTrace === \"function\") {\n ErrorWithCapture.captureStackTrace(this, NetworkError)\n }\n }\n}\n\n/**\n * Error thrown when SDK is used incorrectly (e.g., not initialized)\n */\nexport class DashgramConfigurationError extends DashgramError {\n constructor(message: string) {\n super(message)\n this.name = \"DashgramConfigurationError\"\n const ErrorWithCapture = Error as unknown as ErrorConstructorWithCapture\n if (typeof ErrorWithCapture.captureStackTrace === \"function\") {\n ErrorWithCapture.captureStackTrace(this, DashgramConfigurationError)\n }\n }\n}\n","import type { DashgramConfig, TrackLevel } from \"../types\"\nimport { DashgramConfigurationError } from \"../errors\"\n\n/**\n * Default configuration\n */\nconst DEFAULT_CONFIG: Required<Omit<DashgramConfig, \"projectId\" | \"onError\">> = {\n trackLevel: 1,\n apiUrl: \"https://api.dashgram.io/v1\",\n batchSize: 10,\n flushInterval: 5000, // 5 seconds\n debug: false,\n disabled: false\n}\n\n/**\n * Configuration manager\n */\nexport class Config {\n private config: Required<Omit<DashgramConfig, \"onError\">> & Pick<DashgramConfig, \"onError\">\n\n constructor(userConfig: DashgramConfig) {\n this.config = {\n ...DEFAULT_CONFIG,\n ...userConfig\n } as Required<Omit<DashgramConfig, \"onError\">> & Pick<DashgramConfig, \"onError\">\n\n this.validate()\n }\n\n /**\n * Validate configuration\n */\n private validate(): void {\n if (!this.config.projectId) {\n throw new DashgramConfigurationError(\"projectId is required\")\n }\n\n if (![1, 2, 3].includes(this.config.trackLevel)) {\n throw new DashgramConfigurationError(\"trackLevel must be 1, 2, or 3\")\n }\n }\n\n /**\n * Get configuration value\n */\n get<K extends keyof Required<Omit<DashgramConfig, \"onError\">>>(key: K): Required<Omit<DashgramConfig, \"onError\">>[K] {\n return this.config[key]\n }\n\n /**\n * Get error handler callback\n */\n getOnError(): DashgramConfig[\"onError\"] {\n return this.config.onError\n }\n\n /**\n * Get the full API URL for tracking\n */\n getTrackUrl(): string {\n const baseUrl = this.config.apiUrl.replace(/\\/$/, \"\")\n return `${baseUrl}/${this.config.projectId}/webapp/track`\n }\n\n /**\n * Set track level\n */\n setTrackLevel(level: TrackLevel): void {\n if (![1, 2, 3].includes(level)) {\n throw new DashgramConfigurationError(\"trackLevel must be 1, 2, or 3\")\n }\n this.config.trackLevel = level\n }\n\n /**\n * Get track level\n */\n getTrackLevel(): TrackLevel {\n return this.config.trackLevel\n }\n\n /**\n * Check if debug mode is enabled\n */\n isDebug(): boolean {\n return this.config.debug\n }\n\n /**\n * Check if tracking is disabled\n */\n isDisabled(): boolean {\n return this.config.disabled\n }\n}\n","import type { TelegramWebApp, TelegramWindow } from \"../types\"\n\n/**\n * Get Telegram WebApp instance\n */\nexport function getTelegramWebApp(): TelegramWebApp | null {\n if (typeof window === \"undefined\") {\n return null\n }\n\n const win = window as TelegramWindow\n return win.Telegram?.WebApp || null\n}\n\n/**\n * Check if running inside Telegram Mini App\n */\nexport function isTelegramMiniApp(): boolean {\n return getTelegramWebApp() !== null\n}\n\n/**\n * Get raw Telegram initData string (passed as-is to backend)\n */\nexport function getTelegramInitData(): string {\n const webApp = getTelegramWebApp()\n return webApp?.initData || \"\"\n}\n\n/**\n * Get Telegram platform\n */\nexport function getTelegramPlatform(): string {\n const webApp = getTelegramWebApp()\n return webApp?.platform || \"unknown\"\n}\n\n/**\n * Get Telegram theme (light/dark)\n */\nexport function getTelegramTheme(): string | undefined {\n const webApp = getTelegramWebApp()\n\n // Use colorScheme directly if available\n if (webApp?.colorScheme) {\n return webApp.colorScheme\n }\n\n // Fallback: detect from themeParams\n if (webApp?.themeParams?.bg_color) {\n const bgColor = webApp.themeParams.bg_color\n try {\n const rgb = parseInt(bgColor.slice(1), 16)\n const r = (rgb >> 16) & 0xff\n const g = (rgb >> 8) & 0xff\n const b = (rgb >> 0) & 0xff\n const luma = 0.2126 * r + 0.7152 * g + 0.0722 * b\n return luma < 128 ? \"dark\" : \"light\"\n } catch {\n return undefined\n }\n }\n\n return undefined\n}\n\n/**\n * Subscribe to Telegram WebApp events\n */\nexport function subscribeToTelegramEvent(event: string, callback: (eventData?: unknown) => void): () => void {\n const webApp = getTelegramWebApp()\n\n if (!webApp || !webApp.onEvent) {\n return () => {}\n }\n\n try {\n const wrappedCallback = (_eventType: string, eventData?: unknown) => {\n try {\n callback(eventData)\n } catch (error) {\n if (\n typeof window !== \"undefined\" &&\n (window as typeof window & { __DASHGRAM_DEBUG__?: boolean }).__DASHGRAM_DEBUG__\n ) {\n console.warn(`[Dashgram] Error in Telegram event callback for ${event}:`, error)\n }\n }\n }\n\n webApp.onEvent(event, wrappedCallback)\n\n return () => {\n try {\n if (webApp.offEvent) {\n webApp.offEvent(event, wrappedCallback)\n }\n } catch {\n // Ignore unsubscribe errors silently\n }\n }\n } catch {\n return () => {}\n }\n}\n","import type { Telemetry } from \"../types\"\nimport { getTelegramPlatform, getTelegramTheme } from \"./telegram\"\n\n/**\n * Get telemetry data for events\n */\nexport function getTelemetry(): Telemetry {\n if (typeof window === \"undefined\") {\n return {\n platform: \"unknown\"\n }\n }\n\n return {\n platform: getTelegramPlatform(),\n user_agent: navigator.userAgent,\n timezone: Intl.DateTimeFormat().resolvedOptions().timeZone || undefined,\n theme: getTelegramTheme()\n }\n}\n\n/**\n * Get current URL\n */\nexport function getCurrentUrl(): string {\n if (typeof window === \"undefined\") {\n return \"\"\n }\n\n return window.location.href\n}\n\n/**\n * Get current page path\n */\nexport function getCurrentPath(): string {\n if (typeof window === \"undefined\") {\n return \"\"\n }\n\n return window.location.pathname\n}\n\n/**\n * Get page title\n */\nexport function getPageTitle(): string {\n if (typeof document === \"undefined\") {\n return \"\"\n }\n\n return document.title || \"\"\n}\n\n/**\n * Get current origin\n */\nexport function getCurrentOrigin(): string {\n if (typeof window === \"undefined\") {\n return \"\"\n }\n\n return window.location.origin\n}\n","import type { Telemetry } from \"../types\"\nimport { getTelemetry } from \"../utils/device\"\n\n/**\n * Context manager - maintains telemetry data\n */\nexport class Context {\n private telemetry: Telemetry\n\n constructor() {\n this.telemetry = getTelemetry()\n }\n\n /**\n * Get current telemetry\n */\n getTelemetry(): Telemetry {\n return { ...this.telemetry }\n }\n\n /**\n * Update telemetry (e.g., after theme change)\n */\n updateTelemetry(): void {\n this.telemetry = getTelemetry()\n }\n}\n","/**\n * Generate a UUID v4\n */\nexport function generateUUID(): string {\n if (typeof crypto !== 'undefined' && crypto.randomUUID) {\n return crypto.randomUUID();\n }\n\n // Fallback for older browsers\n return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => {\n const r = (Math.random() * 16) | 0;\n const v = c === 'x' ? r : (r & 0x3) | 0x8;\n return v.toString(16);\n });\n}\n\n/**\n * Get current ISO 8601 timestamp\n */\nexport function getTimestamp(): string {\n return new Date().toISOString();\n}\n\n/**\n * Throttle function execution\n */\nexport function throttle<T extends (...args: any[]) => any>(\n func: T,\n wait: number\n): (...args: Parameters<T>) => void {\n let timeout: ReturnType<typeof setTimeout> | null = null;\n let previous = 0;\n\n return function (this: any, ...args: Parameters<T>) {\n const now = Date.now();\n const remaining = wait - (now - previous);\n\n if (remaining <= 0 || remaining > wait) {\n if (timeout) {\n clearTimeout(timeout);\n timeout = null;\n }\n previous = now;\n func.apply(this, args);\n } else if (!timeout) {\n timeout = setTimeout(() => {\n previous = Date.now();\n timeout = null;\n func.apply(this, args);\n }, remaining);\n }\n };\n}\n\n/**\n * Debounce function execution\n */\nexport function debounce<T extends (...args: any[]) => any>(\n func: T,\n wait: number\n): (...args: Parameters<T>) => void {\n let timeout: ReturnType<typeof setTimeout> | null = null;\n\n return function (this: any, ...args: Parameters<T>) {\n if (timeout) {\n clearTimeout(timeout);\n }\n timeout = setTimeout(() => {\n func.apply(this, args);\n }, wait);\n };\n}\n\n/**\n * Safe JSON stringify\n */\nexport function safeStringify(obj: any): string {\n try {\n return JSON.stringify(obj);\n } catch (error) {\n return '{}';\n }\n}\n\n/**\n * Check if code is running in browser\n */\nexport function isBrowser(): boolean {\n return typeof window !== 'undefined' && typeof document !== 'undefined';\n}\n\n/**\n * Get element selector path\n */\nexport function getElementSelector(element: Element): string {\n if (element.id) {\n return `#${element.id}`;\n }\n\n if (element.className && typeof element.className === 'string') {\n const classes = element.className.trim().split(/\\s+/).slice(0, 2).join('.');\n if (classes) {\n return `${element.tagName.toLowerCase()}.${classes}`;\n }\n }\n\n return element.tagName.toLowerCase();\n}\n\n/**\n * Get element text content (truncated)\n */\nexport function getElementText(element: Element, maxLength = 50): string {\n const text = element.textContent?.trim() || '';\n return text.length > maxLength ? text.substring(0, maxLength) + '...' : text;\n}\n\n\n\n\n\n","import type { WebAppEvent, WebAppTrackRequest } from \"../types\"\nimport type { Config } from \"../core/config\"\nimport { safeStringify } from \"../utils/helpers\"\nimport { DashgramAPIError, NetworkError } from \"../errors\"\nimport { getCurrentOrigin } from \"../utils/device\"\n\n/**\n * Transport layer - sends events to backend\n */\nexport class Transport {\n private config: Config\n private isOnline: boolean = true\n private pendingRequests: Set<Promise<void>> = new Set()\n\n constructor(config: Config) {\n this.config = config\n this.setupOnlineListener()\n }\n\n /**\n * Setup online/offline listener\n */\n private setupOnlineListener(): void {\n if (typeof window === \"undefined\") {\n return\n }\n\n window.addEventListener(\"online\", () => {\n this.isOnline = true\n this.log(\"Connection restored\")\n })\n\n window.addEventListener(\"offline\", () => {\n this.isOnline = false\n this.log(\"Connection lost\")\n })\n\n this.isOnline = navigator.onLine\n }\n\n /**\n * Build request payload\n */\n private buildPayload(events: WebAppEvent[]): WebAppTrackRequest {\n return {\n origin: getCurrentOrigin() || undefined,\n updates: events\n }\n }\n\n /**\n * Send events to backend\n */\n async send(events: WebAppEvent[]): Promise<void> {\n if (events.length === 0) {\n return\n }\n\n if (this.config.isDisabled()) {\n this.log(\"Tracking disabled, skipping send\")\n return\n }\n\n if (!this.isOnline) {\n this.log(\"Offline, skipping send\")\n return\n }\n\n const request = this.sendRequest(events)\n this.pendingRequests.add(request)\n\n try {\n await request\n } catch (error) {\n this.logError(\"Failed to send events:\", error)\n\n const onError = this.config.getOnError()\n if (onError) {\n try {\n if (error instanceof DashgramAPIError || error instanceof NetworkError) {\n onError(error)\n } else if (error instanceof Error) {\n onError(new NetworkError(error))\n }\n } catch (handlerError) {\n this.logError(\"Error in onError callback:\", handlerError)\n }\n }\n } finally {\n this.pendingRequests.delete(request)\n }\n }\n\n /**\n * Send request to backend\n */\n private async sendRequest(events: WebAppEvent[]): Promise<void> {\n const url = this.config.getTrackUrl()\n const payload = this.buildPayload(events)\n\n try {\n const response = await fetch(url, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\"\n },\n body: safeStringify(payload),\n keepalive: true\n })\n\n if (!response.ok) {\n let details = response.statusText\n try {\n const errorData = await response.json()\n details = errorData.details || errorData.message || details\n } catch {\n // Ignore JSON parse errors\n }\n\n throw new DashgramAPIError(response.status, details)\n }\n\n this.log(`Sent ${events.length} events successfully`)\n } catch (error) {\n if (error instanceof DashgramAPIError) {\n throw error\n }\n\n if (error instanceof Error) {\n throw new NetworkError(error)\n }\n\n throw new NetworkError(new Error(String(error)))\n }\n }\n\n /**\n * Send events using sendBeacon (for page unload)\n */\n sendBeacon(events: WebAppEvent[]): boolean {\n if (events.length === 0) {\n return true\n }\n\n if (this.config.isDisabled()) {\n return true\n }\n\n if (typeof navigator === \"undefined\" || !navigator.sendBeacon) {\n return false\n }\n\n const url = this.config.getTrackUrl()\n const payload = this.buildPayload(events)\n\n const blob = new Blob([safeStringify(payload)], { type: \"application/json\" })\n const sent = navigator.sendBeacon(url, blob)\n\n this.log(`sendBeacon ${sent ? \"succeeded\" : \"failed\"} for ${events.length} events`)\n\n return sent\n }\n\n /**\n * Wait for all pending requests to complete\n */\n async flush(): Promise<void> {\n await Promise.all(Array.from(this.pendingRequests))\n }\n\n /**\n * Log debug message\n */\n private log(...args: unknown[]): void {\n if (this.config.isDebug()) {\n console.log(\"[Dashgram Transport]\", ...args)\n }\n }\n\n /**\n * Log error message\n */\n private logError(...args: unknown[]): void {\n if (this.config.isDebug()) {\n console.error(\"[Dashgram Transport]\", ...args)\n }\n }\n}\n","import type { WebAppEvent } from \"../types\"\n\n/**\n * Event queue manager\n */\nexport class EventQueue {\n private queue: WebAppEvent[] = []\n private maxSize: number\n\n constructor(maxSize: number = 100) {\n this.maxSize = maxSize\n }\n\n /**\n * Add event to queue\n */\n enqueue(event: WebAppEvent): void {\n this.queue.push(event)\n\n // Prevent queue from growing too large\n if (this.queue.length > this.maxSize) {\n this.queue.shift()\n }\n }\n\n /**\n * Get all events and clear queue\n */\n flush(): WebAppEvent[] {\n const events = [...this.queue]\n this.queue = []\n return events\n }\n\n /**\n * Get events without clearing queue\n */\n peek(): WebAppEvent[] {\n return [...this.queue]\n }\n\n /**\n * Get queue size\n */\n size(): number {\n return this.queue.length\n }\n\n /**\n * Check if queue is empty\n */\n isEmpty(): boolean {\n return this.queue.length === 0\n }\n\n /**\n * Clear queue\n */\n clear(): void {\n this.queue = []\n }\n}\n","import type { WebAppEvent } from \"../types\"\nimport type { Config } from \"../core/config\"\nimport { EventQueue } from \"../core/event-queue\"\nimport { Transport } from \"./transport\"\n\n/**\n * Batch processor - batches events and sends them periodically\n */\nexport class BatchProcessor {\n private config: Config\n private queue: EventQueue\n private transport: Transport\n private flushTimer: ReturnType<typeof setTimeout> | null = null\n private isStarted: boolean = false\n\n constructor(config: Config, transport: Transport) {\n this.config = config\n this.transport = transport\n this.queue = new EventQueue(200)\n }\n\n /**\n * Start batch processor\n */\n start(): void {\n if (this.isStarted) {\n return\n }\n\n this.isStarted = true\n this.scheduleFlush()\n this.setupPageUnloadHandler()\n }\n\n /**\n * Stop batch processor\n */\n stop(): void {\n this.isStarted = false\n\n if (this.flushTimer) {\n clearTimeout(this.flushTimer)\n this.flushTimer = null\n }\n }\n\n /**\n * Add event to batch\n */\n addEvent(event: WebAppEvent): void {\n this.queue.enqueue(event)\n\n // Auto-flush if batch size reached\n const batchSize = this.config.get(\"batchSize\")\n if (this.queue.size() >= batchSize) {\n this.flush()\n }\n }\n\n /**\n * Schedule periodic flush\n */\n private scheduleFlush(): void {\n if (this.flushTimer) {\n clearTimeout(this.flushTimer)\n }\n\n const interval = this.config.get(\"flushInterval\")\n this.flushTimer = setTimeout(() => {\n this.flush()\n\n if (this.isStarted) {\n this.scheduleFlush()\n }\n }, interval)\n }\n\n /**\n * Flush all events\n */\n flush(): void {\n const events = this.queue.flush()\n\n if (events.length > 0) {\n this.transport.send(events)\n }\n }\n\n /**\n * Flush all events and wait for completion\n */\n async flushAsync(): Promise<void> {\n const events = this.queue.flush()\n\n if (events.length > 0) {\n await this.transport.send(events)\n }\n\n await this.transport.flush()\n }\n\n /**\n * Setup page unload handler\n */\n private setupPageUnloadHandler(): void {\n if (typeof window === \"undefined\") {\n return\n }\n\n const handleUnload = () => {\n const events = this.queue.flush()\n if (events.length > 0) {\n this.transport.sendBeacon(events)\n }\n }\n\n window.addEventListener(\"visibilitychange\", () => {\n if (document.visibilityState === \"hidden\") {\n handleUnload()\n }\n })\n\n window.addEventListener(\"pagehide\", handleUnload)\n window.addEventListener(\"beforeunload\", handleUnload)\n }\n}\n","import type { TrackLevel, EventProperties } from \"../types\"\nimport type { Config } from \"../core/config\"\n\n/**\n * Callback for tracking events\n */\nexport type TrackCallback = (event: string, properties: EventProperties) => void\n\n/**\n * Base tracker class\n */\nexport abstract class BaseTracker {\n protected config: Config\n protected trackCallback: TrackCallback\n protected isActive: boolean = false\n protected level: TrackLevel\n\n constructor(config: Config, trackCallback: TrackCallback, level: TrackLevel) {\n this.config = config\n this.trackCallback = trackCallback\n this.level = level\n }\n\n /**\n * Start tracking\n */\n start(): void {\n if (this.isActive) {\n return\n }\n\n const currentLevel = this.config.getTrackLevel()\n\n // Only start if current track level meets required level\n if (currentLevel >= this.level) {\n this.isActive = true\n this.setup()\n this.log(`Started (level ${this.level})`)\n }\n }\n\n /**\n * Stop tracking\n */\n stop(): void {\n if (!this.isActive) {\n return\n }\n\n this.isActive = false\n this.teardown()\n this.log(`Stopped`)\n }\n\n /**\n * Track event\n */\n protected track(event: string, properties: EventProperties = {}): void {\n if (!this.isActive) {\n return\n }\n\n this.trackCallback(event, properties)\n }\n\n /**\n * Setup tracking (implement in subclass)\n */\n protected abstract setup(): void\n\n /**\n * Teardown tracking (implement in subclass)\n */\n protected abstract teardown(): void\n\n /**\n * Log debug message\n */\n protected log(...args: unknown[]): void {\n if (this.config.isDebug()) {\n console.log(`[Dashgram ${this.constructor.name}]`, ...args)\n }\n }\n}\n","import { BaseTracker } from \"./base-tracker\"\nimport type { Config } from \"../core/config\"\nimport type { TrackCallback } from \"./base-tracker\"\n\n/**\n * Core tracker (Level 1)\n * Tracks: app_open, app_close\n */\nexport class CoreTracker extends BaseTracker {\n private unsubscribers: (() => void)[] = []\n private hasTrackedAppOpen = false\n\n constructor(config: Config, trackCallback: TrackCallback) {\n super(config, trackCallback, 1)\n }\n\n protected setup(): void {\n if (typeof window === \"undefined\") {\n return\n }\n\n // Track app_open on first load\n this.trackAppOpen()\n\n // Track app_close on visibility change and page unload\n this.setupVisibilityTracking()\n this.setupUnloadTracking()\n }\n\n protected teardown(): void {\n this.unsubscribers.forEach(unsubscribe => unsubscribe())\n this.unsubscribers = []\n }\n\n /**\n * Track app_open event\n */\n private trackAppOpen(): void {\n if (this.hasTrackedAppOpen) {\n return\n }\n\n this.track(\"app_open\", {\n referrer: document.referrer || \"direct\"\n })\n\n this.hasTrackedAppOpen = true\n }\n\n /**\n * Setup visibility tracking\n */\n private setupVisibilityTracking(): void {\n const handleVisibilityChange = () => {\n if (document.visibilityState === \"hidden\") {\n this.track(\"app_close\", {\n visibility_state: \"hidden\"\n })\n } else if (document.visibilityState === \"visible\") {\n this.track(\"app_open\", {\n visibility_state: \"visible\"\n })\n }\n }\n\n document.addEventListener(\"visibilitychange\", handleVisibilityChange)\n\n this.unsubscribers.push(() => {\n document.removeEventListener(\"visibilitychange\", handleVisibilityChange)\n })\n }\n\n /**\n * Setup page unload tracking\n */\n private setupUnloadTracking(): void {\n const handleUnload = () => {\n this.track(\"app_close\", {\n reason: \"unload\"\n })\n }\n\n window.addEventListener(\"pagehide\", handleUnload)\n\n this.unsubscribers.push(() => {\n window.removeEventListener(\"pagehide\", handleUnload)\n })\n\n window.addEventListener(\"beforeunload\", handleUnload)\n\n this.unsubscribers.push(() => {\n window.removeEventListener(\"beforeunload\", handleUnload)\n })\n }\n}\n","import { BaseTracker } from \"./base-tracker\"\nimport type { Config } from \"../core/config\"\nimport type { TrackCallback } from \"./base-tracker\"\nimport { throttle } from \"../utils/helpers\"\nimport { getElementSelector, getElementText } from \"../utils/helpers\"\nimport { getCurrentPath, getPageTitle, getCurrentUrl } from \"../utils/device\"\n\n/**\n * Interaction tracker (Level 2)\n * Tracks: screen_view, button_click, link_click, form_submit, input_focus, input_change,\n * copy, cut, paste, text_select, errors\n */\nexport class InteractionTracker extends BaseTracker {\n private unsubscribers: (() => void)[] = []\n private lastPath: string = \"\"\n private inputValues = new Map<HTMLElement, string>()\n\n constructor(config: Config, trackCallback: TrackCallback) {\n super(config, trackCallback, 2)\n }\n\n protected setup(): void {\n if (typeof window === \"undefined\") {\n return\n }\n\n // Track initial screen view\n this.trackScreenView()\n\n // Setup tracking\n this.setupHistoryTracking()\n this.setupClickTracking()\n this.setupFormTracking()\n this.setupInputTracking()\n this.setupClipboardTracking()\n this.setupSelectionTracking()\n this.setupErrorTracking()\n }\n\n protected teardown(): void {\n this.unsubscribers.forEach(unsubscribe => unsubscribe())\n this.unsubscribers = []\n }\n\n /**\n * Track screen view\n */\n private trackScreenView(): void {\n const path = getCurrentPath()\n\n if (path === this.lastPath) {\n return\n }\n\n this.lastPath = path\n\n this.track(\"screen_view\", {\n path,\n url: getCurrentUrl(),\n title: getPageTitle(),\n referrer: document.referrer || \"direct\"\n })\n }\n\n /**\n * Setup history tracking (for SPAs)\n */\n private setupHistoryTracking(): void {\n // Patch pushState and replaceState\n const originalPushState = history.pushState\n const originalReplaceState = history.replaceState\n\n const trackOnHistoryChange = () => {\n this.trackScreenView()\n }\n\n history.pushState = function (...args) {\n originalPushState.apply(history, args)\n trackOnHistoryChange()\n }\n\n history.replaceState = function (...args) {\n originalReplaceState.apply(history, args)\n trackOnHistoryChange()\n }\n\n // Listen to popstate (back/forward buttons)\n window.addEventListener(\"popstate\", trackOnHistoryChange)\n\n this.unsubscribers.push(() => {\n history.pushState = originalPushState\n history.replaceState = originalReplaceState\n window.removeEventListener(\"popstate\", trackOnHistoryChange)\n })\n }\n\n /**\n * Setup click tracking\n */\n private setupClickTracking(): void {\n const handleClick = (event: MouseEvent) => {\n const target = event.target as Element\n if (!target) return\n\n // Find closest interactive element\n const button = target.closest('button, [role=\"button\"], a')\n\n if (button) {\n const tagName = button.tagName.toLowerCase()\n const isLink = tagName === \"a\"\n\n if (isLink) {\n const anchor = button as HTMLAnchorElement\n const href = anchor.href\n const isExternal = href ? this.isExternalLink(href) : false\n\n this.track(\"link_click\", {\n element: getElementSelector(button),\n text: getElementText(button),\n href: href || undefined,\n target: anchor.target || undefined,\n is_external: isExternal,\n is_download: anchor.hasAttribute(\"download\")\n })\n } else {\n this.track(\"button_click\", {\n element: getElementSelector(button),\n text: getElementText(button)\n })\n }\n }\n }\n\n document.addEventListener(\"click\", handleClick, { capture: true })\n\n this.unsubscribers.push(() => {\n document.removeEventListener(\"click\", handleClick, { capture: true })\n })\n }\n\n /**\n * Check if a URL is external\n */\n private isExternalLink(url: string): boolean {\n try {\n const linkUrl = new URL(url, window.location.href)\n return linkUrl.origin !== window.location.origin\n } catch {\n return false\n }\n }\n\n /**\n * Setup form tracking\n */\n private setupFormTracking(): void {\n const handleSubmit = (event: SubmitEvent) => {\n const form = event.target as HTMLFormElement\n if (!form) return\n\n this.track(\"form_submit\", {\n form_id: form.id || undefined,\n form_name: form.name || undefined,\n form_action: form.action || undefined,\n form_method: form.method || undefined\n })\n }\n\n document.addEventListener(\"submit\", handleSubmit, { capture: true })\n\n this.unsubscribers.push(() => {\n document.removeEventListener(\"submit\", handleSubmit, { capture: true })\n })\n }\n\n /**\n * Setup input tracking (focus and change)\n */\n private setupInputTracking(): void {\n // Track input focus\n const handleFocus = throttle((event: FocusEvent) => {\n const target = event.target as HTMLElement\n if (!target) return\n\n const tagName = target.tagName.toLowerCase()\n if ([\"input\", \"textarea\", \"select\"].includes(tagName)) {\n const input = target as HTMLInputElement\n\n // Store initial value for change detection\n this.inputValues.set(target, input.value || \"\")\n\n this.track(\"input_focus\", {\n element: getElementSelector(input),\n input_type: input.type || tagName,\n input_name: input.name || undefined,\n input_id: input.id || undefined\n })\n }\n }, 1000)\n\n // Track input change (on blur, only if value changed)\n const handleBlur = (event: FocusEvent) => {\n const target = event.target as HTMLElement\n if (!target) return\n\n const tagName = target.tagName.toLowerCase()\n if ([\"input\", \"textarea\", \"select\"].includes(tagName)) {\n const input = target as HTMLInputElement\n const previousValue = this.inputValues.get(target)\n const currentValue = input.value || \"\"\n\n // Only track if value actually changed\n if (previousValue !== undefined && previousValue !== currentValue) {\n this.track(\"input_change\", {\n element: getElementSelector(input),\n input_type: input.type || tagName,\n input_name: input.name || undefined,\n input_id: input.id || undefined,\n had_value: previousValue.length > 0,\n has_value: currentValue.length > 0\n })\n }\n\n this.inputValues.delete(target)\n }\n }\n\n document.addEventListener(\"focus\", handleFocus, { capture: true })\n document.addEventListener(\"blur\", handleBlur, { capture: true })\n\n this.unsubscribers.push(() => {\n document.removeEventListener(\"focus\", handleFocus, { capture: true })\n document.removeEventListener(\"blur\", handleBlur, { capture: true })\n this.inputValues.clear()\n })\n }\n\n /**\n * Setup clipboard tracking (copy, cut, paste)\n */\n private setupClipboardTracking(): void {\n const handleCopy = (_event: ClipboardEvent) => {\n const selection = window.getSelection()\n const selectedText = selection?.toString() || \"\"\n\n this.track(\"copy\", {\n text_length: selectedText.length,\n has_selection: selectedText.length > 0\n })\n }\n\n const handleCut = (_event: ClipboardEvent) => {\n const selection = window.getSelection()\n const selectedText = selection?.toString() || \"\"\n\n this.track(\"cut\", {\n text_length: selectedText.length,\n has_selection: selectedText.length > 0\n })\n }\n\n const handlePaste = (event: ClipboardEvent) => {\n const pastedText = event.clipboardData?.getData(\"text\") || \"\"\n const target = event.target as HTMLElement\n\n this.track(\"paste\", {\n text_length: pastedText.length,\n target_element: target ? getElementSelector(target) : undefined\n })\n }\n\n document.addEventListener(\"copy\", handleCopy)\n document.addEventListener(\"cut\", handleCut)\n document.addEventListener(\"paste\", handlePaste)\n\n this.unsubscribers.push(() => {\n document.removeEventListener(\"copy\", handleCopy)\n document.removeEventListener(\"cut\", handleCut)\n document.removeEventListener(\"paste\", handlePaste)\n })\n }\n\n /**\n * Setup text selection tracking\n */\n private setupSelectionTracking(): void {\n let selectionTimeout: any\n\n const handleSelectionChange = () => {\n // Debounce selection events\n clearTimeout(selectionTimeout)\n selectionTimeout = setTimeout(() => {\n const selection = window.getSelection()\n const selectedText = selection?.toString() || \"\"\n\n if (selectedText.length > 0) {\n this.track(\"text_select\", {\n text_length: selectedText.length\n })\n }\n }, 500)\n }\n\n document.addEventListener(\"selectionchange\", handleSelectionChange)\n\n this.unsubscribers.push(() => {\n document.removeEventListener(\"selectionchange\", handleSelectionChange)\n clearTimeout(selectionTimeout)\n })\n }\n\n /**\n * Setup error tracking\n */\n private setupErrorTracking(): void {\n // Track JavaScript errors\n const handleError = (event: ErrorEvent) => {\n this.track(\"js_error\", {\n message: event.message,\n filename: event.filename,\n lineno: event.lineno,\n colno: event.colno,\n stack: event.error?.stack\n })\n }\n\n window.addEventListener(\"error\", handleError)\n\n this.unsubscribers.push(() => {\n window.removeEventListener(\"error\", handleError)\n })\n\n // Track unhandled promise rejections\n const handleRejection = (event: PromiseRejectionEvent) => {\n this.track(\"unhandled_rejection\", {\n reason: String(event.reason),\n promise: String(event.promise)\n })\n }\n\n window.addEventListener(\"unhandledrejection\", handleRejection)\n\n this.unsubscribers.push(() => {\n window.removeEventListener(\"unhandledrejection\", handleRejection)\n })\n }\n}\n","import { BaseTracker } from \"./base-tracker\"\nimport type { Config } from \"../core/config\"\nimport type { TrackCallback } from \"./base-tracker\"\nimport { throttle } from \"../utils/helpers\"\nimport { subscribeToTelegramEvent } from \"../utils/telegram\"\n\n/**\n * Deep tracker (Level 3)\n * Tracks: scroll_depth, element_visible, rage_click, long_task, web_vitals,\n * network_status, orientation_change, media events, Telegram events\n */\nexport class DeepTracker extends BaseTracker {\n private unsubscribers: (() => void)[] = []\n private observers: Array<IntersectionObserver | PerformanceObserver | MutationObserver> = []\n private clickTracker = new Map<Element, { count: number; timer: any }>()\n private maxScrollDepth = 0\n private trackedMedia = new WeakSet<HTMLMediaElement>()\n\n constructor(config: Config, trackCallback: TrackCallback) {\n super(config, trackCallback, 3)\n }\n\n protected setup(): void {\n if (typeof window === \"undefined\") {\n return\n }\n\n this.setupScrollTracking()\n this.setupVisibilityTracking()\n this.setupRageClickTracking()\n this.setupLongTaskTracking()\n this.setupWebVitals()\n this.setupNetworkTracking()\n this.setupOrientationTracking()\n this.setupMediaTracking()\n this.setupTelegramTracking()\n }\n\n protected teardown(): void {\n this.unsubscribers.forEach(unsubscribe => unsubscribe())\n this.unsubscribers = []\n\n this.observers.forEach(observer => observer.disconnect())\n this.observers = []\n\n this.clickTracker.clear()\n }\n\n /**\n * Calculate scroll depth percentage\n */\n private getScrollDepth(): number {\n const windowHeight = window.innerHeight\n const documentHeight = document.documentElement.scrollHeight\n const scrollTop = window.pageYOffset || document.documentElement.scrollTop\n\n if (documentHeight <= windowHeight) {\n return 100\n }\n\n const maxScroll = documentHeight - windowHeight\n const scrollPercentage = (scrollTop / maxScroll) * 100\n\n return Math.min(Math.round(scrollPercentage), 100)\n }\n\n /**\n * Setup scroll depth tracking\n */\n private setupScrollTracking(): void {\n const handleScroll = throttle(() => {\n const depth = this.getScrollDepth()\n\n // Track milestones: 25%, 50%, 75%, 100%\n if (depth > this.maxScrollDepth) {\n this.maxScrollDepth = depth\n\n const milestones = [25, 50, 75, 100]\n const milestone = milestones.find(m => depth >= m && this.maxScrollDepth - depth < m)\n\n if (milestone) {\n this.track(\"scroll_depth\", {\n depth: milestone,\n max_depth: this.maxScrollDepth\n })\n }\n }\n }, 500)\n\n window.addEventListener(\"scroll\", handleScroll, { passive: true })\n\n this.unsubscribers.push(() => {\n window.removeEventListener(\"scroll\", handleScroll)\n })\n }\n\n /**\n * Setup element visibility tracking\n */\n private setupVisibilityTracking(): void {\n if (!(\"IntersectionObserver\" in window)) {\n return\n }\n\n const observer = new IntersectionObserver(\n entries => {\n entries.forEach(entry => {\n if (entry.isIntersecting) {\n const element = entry.target\n const selector = element.getAttribute(\"data-track-visible\")\n\n if (selector) {\n this.track(\"element_visible\", {\n element: selector,\n intersection_ratio: entry.intersectionRatio\n })\n\n // Stop observing after first visibility\n observer.unobserve(element)\n }\n }\n })\n },\n { threshold: 0.5 }\n )\n\n // Observe elements with data-track-visible attribute\n document.querySelectorAll(\"[data-track-visible]\").forEach(element => {\n observer.observe(element)\n })\n\n this.observers.push(observer)\n\n // Also observe dynamically added elements (with MutationObserver)\n const mutationObserver = new MutationObserver(mutations => {\n mutations.forEach(mutation => {\n mutation.addedNodes.forEach(node => {\n if (node instanceof Element) {\n if (node.hasAttribute(\"data-track-visible\")) {\n observer.observe(node)\n }\n node.querySelectorAll(\"[data-track-visible]\").forEach(el => {\n observer.observe(el)\n })\n }\n })\n })\n })\n\n mutationObserver.observe(document.body, {\n childList: true,\n subtree: true\n })\n\n this.unsubscribers.push(() => {\n mutationObserver.disconnect()\n })\n }\n\n /**\n * Setup rage click tracking\n */\n private setupRageClickTracking(): void {\n const RAGE_THRESHOLD = 5 // 5 clicks\n const RAGE_TIMEOUT = 2000 // within 2 seconds\n\n const handleClick = (event: MouseEvent) => {\n const target = event.target as Element\n if (!target) return\n\n const tracker = this.clickTracker.get(target)\n\n if (tracker) {\n tracker.count++\n clearTimeout(tracker.timer)\n\n if (tracker.count >= RAGE_THRESHOLD) {\n this.track(\"rage_click\", {\n element: target.tagName.toLowerCase(),\n click_count: tracker.count\n })\n\n this.clickTracker.delete(target)\n } else {\n tracker.timer = setTimeout(() => {\n this.clickTracker.delete(target)\n }, RAGE_TIMEOUT)\n }\n } else {\n const timer = setTimeout(() => {\n this.clickTracker.delete(target)\n }, RAGE_TIMEOUT)\n\n this.clickTracker.set(target, { count: 1, timer })\n }\n }\n\n document.addEventListener(\"click\", handleClick)\n\n this.unsubscribers.push(() => {\n document.removeEventListener(\"click\", handleClick)\n })\n }\n\n /**\n * Setup long task tracking\n */\n private setupLongTaskTracking(): void {\n if (!(\"PerformanceObserver\" in window)) {\n return\n }\n\n try {\n const observer = new PerformanceObserver(list => {\n for (const entry of list.getEntries()) {\n if (entry.duration > 50) {\n // Tasks longer than 50ms\n this.track(\"long_task\", {\n duration: Math.round(entry.duration),\n start_time: Math.round(entry.startTime)\n })\n }\n }\n })\n\n observer.observe({ entryTypes: [\"longtask\"] })\n this.observers.push(observer)\n } catch (error) {\n // longtask might not be supported\n this.log(\"Long task tracking not supported\")\n }\n }\n\n /**\n * Setup Web Vitals tracking\n */\n private setupWebVitals(): void {\n if (!(\"PerformanceObserver\" in window)) {\n return\n }\n\n // Track Largest Contentful Paint (LCP)\n try {\n const lcpObserver = new PerformanceObserver(list => {\n const entries = list.getEntries()\n const lastEntry = entries[entries.length - 1] as any\n\n this.track(\"web_vital_lcp\", {\n value: Math.round(lastEntry.renderTime || lastEntry.loadTime),\n element: lastEntry.element?.tagName.toLowerCase()\n })\n })\n\n lcpObserver.observe({ entryTypes: [\"largest-contentful-paint\"] })\n this.observers.push(lcpObserver)\n } catch (error) {\n this.log(\"LCP tracking not supported\")\n }\n\n // Track First Input Delay (FID)\n try {\n const fidObserver = new PerformanceObserver(list => {\n const entries = list.getEntries()\n entries.forEach((entry: any) => {\n this.track(\"web_vital_fid\", {\n value: Math.round(entry.processingStart - entry.startTime),\n event_type: entry.name\n })\n })\n })\n\n fidObserver.observe({ entryTypes: [\"first-input\"] })\n this.observers.push(fidObserver)\n } catch (error) {\n this.log(\"FID tracking not supported\")\n }\n\n // Track Cumulative Layout Shift (CLS)\n let clsValue = 0\n\n try {\n const clsObserver = new PerformanceObserver(list => {\n const entries = list.getEntries()\n entries.forEach((entry: any) => {\n if (!entry.hadRecentInput) {\n clsValue += entry.value\n }\n })\n })\n\n clsObserver.observe({ entryTypes: [\"layout-shift\"] })\n this.observers.push(clsObserver)\n\n // Report CLS on page hide\n const reportCLS = () => {\n if (clsValue > 0) {\n this.track(\"web_vital_cls\", {\n value: Math.round(clsValue * 1000) / 1000\n })\n }\n }\n\n window.addEventListener(\"visibilitychange\", () => {\n if (document.visibilityState === \"hidden\") {\n reportCLS()\n }\n })\n\n this.unsubscribers.push(() => {\n reportCLS()\n })\n } catch (error) {\n this.log(\"CLS tracking not supported\")\n }\n }\n\n /**\n * Setup network status tracking (online/offline)\n */\n private setupNetworkTracking(): void {\n const handleOnline = () => {\n this.track(\"network_status\", {\n status: \"online\",\n effective_type: (navigator as any).connection?.effectiveType,\n downlink: (navigator as any).connection?.downlink,\n rtt: (navigator as any).connection?.rtt\n })\n }\n\n const handleOffline = () => {\n this.track(\"network_status\", {\n status: \"offline\"\n })\n }\n\n window.addEventListener(\"online\", handleOnline)\n window.addEventListener(\"offline\", handleOffline)\n\n this.unsubscribers.push(() => {\n window.removeEventListener(\"online\", handleOnline)\n window.removeEventListener(\"offline\", handleOffline)\n })\n\n // Track network changes if supported\n const connection = (navigator as any).connection\n if (connection) {\n const handleConnectionChange = () => {\n this.track(\"network_change\", {\n effective_type: connection.effectiveType,\n downlink: connection.downlink,\n rtt: connection.rtt,\n save_data: connection.saveData\n })\n }\n\n connection.addEventListener(\"change\", handleConnectionChange)\n\n this.unsubscribers.push(() => {\n connection.removeEventListener(\"change\", handleConnectionChange)\n })\n }\n }\n\n /**\n * Setup device orientation change tracking\n */\n private setupOrientationTracking(): void {\n const handleOrientationChange = () => {\n const orientation =\n screen.orientation?.type || (window.innerWidth > window.innerHeight ? \"landscape\" : \"portrait\")\n\n this.track(\"orientation_change\", {\n orientation: orientation,\n angle: screen.orientation?.angle,\n width: window.innerWidth,\n height: window.innerHeight\n })\n }\n\n // Use screen.orientation API if available, fallback to resize\n if (screen.orientation) {\n screen.orientation.addEventListener(\"change\", handleOrientationChange)\n this.unsubscribers.push(() => {\n screen.orientation.removeEventListener(\"change\", handleOrientationChange)\n })\n } else {\n // Fallback for older browsers\n window.addEventListener(\"orientationchange\", handleOrientationChange)\n this.unsubscribers.push(() => {\n window.removeEventListener(\"orientationchange\", handleOrientationChange)\n })\n }\n }\n\n /**\n * Setup media (video/audio) event tracking\n */\n private setupMediaTracking(): void {\n const trackMediaEvent = (event: Event) => {\n const media = event.target as HTMLMediaElement\n if (!media || this.trackedMedia.has(media)) return\n\n const mediaType = media.tagName.toLowerCase() // \"video\" or \"audio\"\n const eventType = event.type\n\n const baseProps = {\n media_type: mediaType,\n src: media.currentSrc || media.src,\n duration: isFinite(media.duration) ? Math.round(media.duration) : undefined,\n current_time: Math.round(media.currentTime),\n muted: media.muted,\n volume: Math.round(media.volume * 100)\n }\n\n if (eventType === \"play\") {\n this.track(\"media_play\", baseProps)\n } else if (eventType === \"pause\") {\n this.track(\"media_pause\", {\n ...baseProps,\n percent_played: media.duration ? Math.round((media.currentTime / media.duration) * 100) : 0\n })\n } else if (eventType === \"ended\") {\n this.track(\"media_ended\", {\n ...baseProps,\n completed: true\n })\n } else if (eventType === \"error\") {\n this.track(\"media_error\", {\n media_type: mediaType,\n src: media.currentSrc || media.src,\n error: media.error?.message || \"unknown\"\n })\n }\n }\n\n // Track events on existing media elements\n const setupMediaElement = (media: HTMLMediaElement) => {\n if (this.trackedMedia.has(media)) return\n this.trackedMedia.add(media)\n\n media.addEventListener(\"play\", trackMediaEvent)\n media.addEventListener(\"pause\", trackMediaEvent)\n media.addEventListener(\"ended\", trackMediaEvent)\n media.addEventListener(\"error\", trackMediaEvent)\n }\n\n // Setup existing media elements\n document.querySelectorAll(\"video, audio\").forEach(media => {\n setupMediaElement(media as HTMLMediaElement)\n })\n\n // Watch for dynamically added media elements\n const observer = new MutationObserver(mutations => {\n mutations.forEach(mutation => {\n mutation.addedNodes.forEach(node => {\n if (node instanceof HTMLMediaElement) {\n setupMediaElement(node)\n }\n if (node instanceof Element) {\n node.querySelectorAll(\"video, audio\").forEach(media => {\n setupMediaElement(media as HTMLMediaElement)\n })\n }\n })\n })\n })\n\n observer.observe(document.body, {\n childList: true,\n subtree: true\n })\n\n this.observers.push(observer)\n }\n\n /**\n * Setup Telegram WebApp event tracking\n * Tracks ALL available Telegram WebApp events\n */\n private setupTelegramTracking(): void {\n const webApp = (window as any).Telegram?.WebApp\n\n // Helper to track event with data\n const trackEvent = (eventName: string, data?: any) => {\n this.track(`telegram_${eventName}`, data || {})\n }\n\n // Theme and appearance events\n // Official event: themeChanged\n // No payload; read values from WebApp.colorScheme and WebApp.themeParams\n const unsubTheme = subscribeToTelegramEvent(\"themeChanged\", () => {\n trackEvent(\"theme_changed\", {\n color_scheme: webApp?.colorScheme,\n theme_params: webApp?.themeParams\n })\n })\n this.unsubscribers.push(unsubTheme)\n\n // Viewport events\n // Official event: viewportChanged\n // Payload: {isStateStable: boolean}\n const unsubViewport = subscribeToTelegramEvent(\"viewportChanged\", (eventData: any) => {\n trackEvent(\"viewport_changed\", {\n is_state_stable: eventData?.isStateStable,\n is_expanded: webApp?.isExpanded,\n viewport_height: webApp?.viewportHeight,\n viewport_stable_height: webApp?.viewportStableHeight\n })\n })\n this.unsubscribers.push(unsubViewport)\n\n // Safe area events (Bot API 7.10+)\n // Official event: safeAreaChanged\n // No payload; read values from WebApp.safeAreaInset\n const unsubSafeArea = subscribeToTelegramEvent(\"safeAreaChanged\", () => {\n trackEvent(\"safe_area_changed\", {\n safe_area: webApp?.safeAreaInset\n })\n })\n this.unsubscribers.push(unsubSafeArea)\n\n // Official event: contentSafeAreaChanged (Bot API 7.10+)\n // No payload; read values from WebApp.contentSafeAreaInset\n const unsubContentSafeArea = subscribeToTelegramEvent(\"contentSafeAreaChanged\", () => {\n trackEvent(\"content_safe_area_changed\", {\n content_safe_area: webApp?.contentSafeAreaInset\n })\n })\n this.unsubscribers.push(unsubContentSafeArea)\n\n // Visibility events\n // Note: activated/deactivated events (Bot API 8.0+) track app visibility state\n // The isVisible property on WebApp can be read directly but there's no separate visibilityChanged event\n\n // Button events\n // Official event: backButtonClicked (Bot API 6.1+)\n // No payload\n const unsubBackButton = subscribeToTelegramEvent(\"backButtonClicked\", () => {\n trackEvent(\"back_button_clicked\", {})\n })\n this.unsubscribers.push(unsubBackButton)\n\n // Official event: mainButtonClicked\n // No payload; read button text from WebApp.MainButton.text\n const unsubMainButton = subscribeToTelegramEvent(\"mainButtonClicked\", () => {\n trackEvent(\"main_button_clicked\", {\n button_text: webApp?.MainButton?.text\n })\n })\n this.unsubscribers.push(unsubMainButton)\n\n // Invoice events\n // Note: invoiceClosed is the official event (Bot API 6.1+)\n // Official payload: {url: string, status: 'paid' | 'cancelled' | 'failed' | 'pending'}\n const unsubInvoice = subscribeToTelegramEvent(\"invoiceClosed\", (eventData: any) => {\n trackEvent(\"invoice_closed\", {\n url: eventData?.url,\n status: eventData?.status\n })\n })\n this.unsubscribers.push(unsubInvoice)\n\n // Popup events (Bot API 6.2+)\n // Official event: popupClosed\n // Payload: {button_id: string | null}\n const unsubPopup = subscribeToTelegramEvent(\"popupClosed\", (eventData: any) => {\n trackEvent(\"popup_closed\", {\n button_id: eventData?.button_id\n })\n })\n this.unsubscribers.push(unsubPopup)\n\n // QR code events (Bot API 6.4+)\n // Official event: qrTextReceived\n // Payload: {data: string}\n const unsubQrText = subscribeToTelegramEvent(\"qrTextReceived\", (eventData: any) => {\n trackEvent(\"qr_text_received\", {\n data: eventData?.data\n })\n })\n this.unsubscribers.push(unsubQrText)\n\n // Official event: scanQrPopupClosed (Bot API 6.4+)\n // No payload\n const unsubScanQr = subscribeToTelegramEvent(\"scanQrPopupClosed\", () => {\n trackEvent(\"scan_qr_popup_closed\", {})\n })\n this.unsubscribers.push(unsubScanQr)\n\n // Clipboard events (Bot API 6.4+)\n // Official event: clipboardTextReceived\n // Payload: {data: string | null} (null if clipboard is empty or permission denied)\n const unsubClipboard = subscribeToTelegramEvent(\"clipboardTextReceived\", (eventData: any) => {\n trackEvent(\"clipboard_text_received\", {\n data: eventData?.data\n })\n })\n this.unsubscribers.push(unsubClipboard)\n\n // Permission events\n // Official event: writeAccessRequested (Bot API 6.9+)\n // Payload: {status: 'allowed' | 'cancelled'}\n const unsubWriteAccess = subscribeToTelegramEvent(\"writeAccessRequested\", (eventData: any) => {\n trackEvent(\"write_access_requested\", {\n status: eventData?.status\n })\n })\n this.unsubscribers.push(unsubWriteAccess)\n\n // File download events (Bot API 8.0+)\n // Official event: fileDownloadRequested\n // Payload: {status: 'downloading' | 'cancelled'}\n const unsubFileDownload = subscribeToTelegramEvent(\"fileDownloadRequested\", (eventData: any) => {\n trackEvent(\"file_download_requested\", {\n status: eventData?.status\n })\n })\n this.unsubscribers.push(unsubFileDownload)\n\n // Custom method events (Bot API 6.9+)\n // Official event: customMethodInvoked\n // Payload: {req_id: string, result?: any, error?: string}\n const unsubCustomMethod = subscribeToTelegramEvent(\"customMethodInvoked\", (eventData: any) => {\n trackEvent(\"custom_method_invoked\", {\n req_id: eventData?.req_id,\n result: eventData?.result,\n error: eventData?.error\n })\n })\n this.unsubscribers.push(unsubCustomMethod)\n\n // Fullscreen events (Bot API 8.0+)\n // Official event: fullscreenChanged\n // Payload: {isFullscreen: boolean}\n const unsubFullscreen = subscribeToTelegramEvent(\"fullscreenChanged\", (eventData: any) => {\n trackEvent(\"fullscreen_changed\", {\n is_fullscreen: eventData?.isFullscreen\n })\n })\n this.unsubscribers.push(unsubFullscreen)\n\n // Official event: fullscreenFailed\n // Payload: {error: 'UNSUPPORTED' | 'ALREADY_FULLSCREEN'}\n const unsubFullscreenFailed = subscribeToTelegramEvent(\"fullscreenFailed\", (eventData: any) => {\n trackEvent(\"fullscreen_failed\", {\n error: eventData?.error\n })\n })\n this.unsubscribers.push(unsubFullscreenFailed)\n\n // Home screen events (Bot API 8.0+)\n // Official event: homeScreenAdded\n // No payload\n const unsubHomeScreenAdded = subscribeToTelegramEvent(\"homeScreenAdded\", () => {\n trackEvent(\"home_screen_added\", {})\n })\n this.unsubscribers.push(unsubHomeScreenAdded)\n\n // Official event: homeScreenChecked\n // Payload: {status: 'unsupported' | 'unknown' | 'added' | 'missed'}\n const unsubHomeScreenChecked = subscribeToTelegramEvent(\"homeScreenChecked\", (eventData: any) => {\n trackEvent(\"home_screen_checked\", {\n status: eventData?.status\n })\n })\n this.unsubscribers.push(unsubHomeScreenChecked)\n\n // Prepared message events (Bot API 8.0+)\n // Official event: preparedMessageSent\n // No payload (message was sent successfully)\n const unsubPreparedMessageSent = subscribeToTelegramEvent(\"preparedMessageSent\", () => {\n trackEvent(\"prepared_message_sent\", {})\n })\n this.unsubscribers.push(unsubPreparedMessageSent)\n\n // Official event: preparedMessageFailed\n // Payload: {error: 'UNSUPPORTED' | 'MESSAGE_EXPIRED' | 'MESSAGE_SEND_FAILED' | 'USER_DECLINED' | 'UNKNOWN_ERROR'}\n const unsubPreparedMessageFailed = subscribeToTelegramEvent(\"preparedMessageFailed\", (eventData: any) => {\n trackEvent(\"prepared_message_failed\", {\n error: eventData?.error\n })\n })\n this.unsubscribers.push(unsubPreparedMessageFailed)\n\n // Emoji status events (Bot API 8.0+)\n // Official event: emojiStatusSet\n // No payload (status was set successfully)\n const unsubEmojiStatusSet = subscribeToTelegramEvent(\"emojiStatusSet\", () => {\n trackEvent(\"emoji_status_set\", {})\n })\n this.unsubscribers.push(unsubEmojiStatusSet)\n\n // Official event: emojiStatusFailed\n // Payload: {error: 'UNSUPPORTED' | 'SUGGESTED_EMOJI_INVALID' | 'DURATION_INVALID' | 'USER_DECLINED' | 'SERVER_ERROR' | 'UNKNOWN_ERROR'}\n const unsubEmojiStatusFailed = subscribeToTelegramEvent(\"emojiStatusFailed\", (eventData: any) => {\n trackEvent(\"emoji_status_failed\", {\n error: eventData?.error\n })\n })\n this.unsubscribers.push(unsubEmojiStatusFailed)\n\n // Official event: emojiStatusAccessRequested\n // Payload: {status: 'allowed' | 'cancelled'}\n const unsubEmojiStatusAccess = subscribeToTelegramEvent(\"emojiStatusAccessRequested\", (eventData: any) => {\n trackEvent(\"emoji_status_access_requested\", {\n status: eventData?.status\n })\n })\n this.unsubscribers.push(unsubEmojiStatusAccess)\n\n // Settings button events (Bot API 6.1+)\n // Official event: settingsButtonClicked\n // No payload\n const unsubSettingsButton = subscribeToTelegramEvent(\"settingsButtonClicked\", () => {\n trackEvent(\"settings_button_clicked\", {})\n })\n this.unsubscribers.push(unsubSettingsButton)\n\n // Secondary button events (Bot API 7.10+)\n // Official event: secondaryButtonClicked\n // No payload\n const unsubSecondaryButton = subscribeToTelegramEvent(\"secondaryButtonClicked\", () => {\n trackEvent(\"secondary_button_clicked\", {})\n })\n this.unsubscribers.push(unsubSecondaryButton)\n\n // Share message events (Bot API 8.0+)\n // Official event: shareMessageSent\n // No payload (message was shared successfully)\n const unsubShareMessageSent = subscribeToTelegramEvent(\"shareMessageSent\", () => {\n trackEvent(\"share_message_sent\", {})\n })\n this.unsubscribers.push(unsubShareMessageSent)\n\n // Official event: shareMessageFailed\n // Payload: {error: 'UNSUPPORTED' | 'MESSAGE_EXPIRED' | 'MESSAGE_SEND_FAILED' | 'USER_DECLINED' | 'UNKNOWN_ERROR'}\n const unsubShareMessageFailed = subscribeToTelegramEvent(\"shareMessageFailed\", (eventData: any) => {\n trackEvent(\"share_message_failed\", {\n error: eventData?.error\n })\n })\n this.unsubscribers.push(unsubShareMessageFailed)\n\n // Location events (Bot API 8.0+)\n // Official event: locationManagerUpdated\n // Fires when LocationManager object is updated\n const unsubLocationManager = subscribeToTelegramEvent(\"locationManagerUpdated\", () => {\n const locationManager = webApp?.LocationManager\n trackEvent(\"location_manager_updated\", {\n is_inited: locationManager?.isInited,\n is_location_available: locationManager?.isLocationAvailable,\n is_access_requested: locationManager?.isAccessRequested,\n is_access_granted: locationManager?.isAccessGranted\n })\n })\n this.unsubscribers.push(unsubLocationManager)\n\n // Official event: locationRequested (Bot API 8.0+)\n // Payload: {locationData?: LocationData} where LocationData has latitude, longitude, etc.\n const unsubLocationRequested = subscribeToTelegramEvent(\"locationRequested\", (eventData: any) => {\n trackEvent(\"location_requested\", {\n available: eventData?.available !== false,\n latitude: eventData?.latitude,\n longitude: eventData?.longitude,\n altitude: eventData?.altitude,\n course: eventData?.course,\n speed: eventData?.speed,\n horizontal_accuracy: eventData?.horizontal_accuracy,\n vertical_accuracy: eventData?.vertical_accuracy,\n course_accuracy: eventData?.course_accuracy,\n speed_accuracy: eventData?.speed_accuracy\n })\n })\n this.unsubscribers.push(unsubLocationRequested)\n\n // Accelerometer events (Bot API 8.0+)\n // Official events: accelerometerStarted, accelerometerStopped, accelerometerChanged, accelerometerFailed\n const unsubAccelerometerStarted = subscribeToTelegramEvent(\"accelerometerStarted\", () => {\n trackEvent(\"accelerometer_started\", {})\n })\n this.unsubscribers.push(unsubAccelerometerStarted)\n\n const unsubAccelerometerStopped = subscribeToTelegramEvent(\"accelerometerStopped\", () => {\n trackEvent(\"accelerometer_stopped\", {})\n })\n this.unsubscribers.push(unsubAccelerometerStopped)\n\n // accelerometerChanged fires with no payload; read values from Accelerometer object\n const unsubAccelerometerChanged = subscribeToTelegramEvent(\"accelerometerChanged\", () => {\n const accelerometer = webApp?.Accelerometer\n trackEvent(\"accelerometer_changed\", {\n x: accelerometer?.x,\n y: accelerometer?.y,\n z: accelerometer?.z\n })\n })\n this.unsubscribers.push(unsubAccelerometerChanged)\n\n // accelerometerFailed payload: {error: 'UNSUPPORTED'}\n const unsubAccelerometerFailed = subscribeToTelegramEvent(\"accelerometerFailed\", (eventData: any) => {\n trackEvent(\"accelerometer_failed\", {\n error: eventData?.error\n })\n })\n this.unsubscribers.push(unsubAccelerometerFailed)\n\n // Device orientation events (Bot API 8.0+)\n // Official events: deviceOrientationStarted, deviceOrientationStopped, deviceOrientationChanged, deviceOrientationFailed\n const unsubDeviceOrientationStarted = subscribeToTelegramEvent(\"deviceOrientationStarted\", () => {\n trackEvent(\"device_orientation_started\", {})\n })\n this.unsubscribers.push(unsubDeviceOrientationStarted)\n\n const unsubDeviceOrientationStopped = subscribeToTelegramEvent(\"deviceOrientationStopped\", () => {\n trackEvent(\"device_orientation_stopped\", {})\n })\n this.unsubscribers.push(unsubDeviceOrientationStopped)\n\n // deviceOrientationChanged fires with no payload; read values from DeviceOrientation object\n const unsubDeviceOrientationChanged = subscribeToTelegramEvent(\"deviceOrientationChanged\", () => {\n const deviceOrientation = webApp?.DeviceOrientation\n trackEvent(\"device_orientation_changed\", {\n absolute: deviceOrientation?.absolute,\n alpha: deviceOrientation?.alpha,\n beta: deviceOrientation?.beta,\n gamma: deviceOrientation?.gamma\n })\n })\n this.unsubscribers.push(unsubDeviceOrientationChanged)\n\n // deviceOrientationFailed payload: {error: 'UNSUPPORTED'}\n const unsubDeviceOrientationFailed = subscribeToTelegramEvent(\"deviceOrientationFailed\", (eventData: any) => {\n trackEvent(\"device_orientation_failed\", {\n error: eventData?.error\n })\n })\n this.unsubscribers.push(unsubDeviceOrientationFailed)\n\n // Gyroscope events (Bot API 8.0+)\n // Official events: gyroscopeStarted, gyroscopeStopped, gyroscopeChanged, gyroscopeFailed\n const unsubGyroscopeStarted = subscribeToTelegramEvent(\"gyroscopeStarted\", () => {\n trackEvent(\"gyroscope_started\", {})\n })\n this.unsubscribers.push(unsubGyroscopeStarted)\n\n const unsubGyroscopeStopped = subscribeToTelegramEvent(\"gyroscopeStopped\", () => {\n trackEvent(\"gyroscope_stopped\", {})\n })\n this.unsubscribers.push(unsubGyroscopeStopped)\n\n // gyroscopeChanged fires with no payload; read values from Gyroscope object\n const unsubGyroscopeChanged = subscribeToTelegramEvent(\"gyroscopeChanged\", () => {\n const gyroscope = webApp?.Gyroscope\n trackEvent(\"gyroscope_changed\", {\n x: gyroscope?.x,\n y: gyroscope?.y,\n z: gyroscope?.z\n })\n })\n this.unsubscribers.push(unsubGyroscopeChanged)\n\n // gyroscopeFailed payload: {error: 'UNSUPPORTED'}\n const unsubGyroscopeFailed = subscribeToTelegramEvent(\"gyroscopeFailed\", (eventData: any) => {\n trackEvent(\"gyroscope_failed\", {\n error: eventData?.error\n })\n })\n this.unsubscribers.push(unsubGyroscopeFailed)\n\n // Contact events (Bot API 6.9+)\n // Official event: contactRequested\n // Payload: {status: 'sent' | 'cancelled'}\n const unsubContactRequested = subscribeToTelegramEvent(\"contactRequested\", (eventData: any) => {\n trackEvent(\"contact_requested\", {\n status: eventData?.status\n })\n })\n this.unsubscribers.push(unsubContactRequested)\n\n // App state events (Bot API 8.0+)\n // Official event: activated\n // Fires when Mini App becomes active (user switches to it)\n // No payload\n const unsubActivated = subscribeToTelegramEvent(\"activated\", () => {\n trackEvent(\"activated\", {})\n })\n this.unsubscribers.push(unsubActivated)\n\n // Official event: deactivated (Bot API 8.0+)\n // Fires when Mini App becomes inactive (user switches away)\n // No payload\n const unsubDeactivated = subscribeToTelegramEvent(\"deactivated\", () => {\n trackEvent(\"deactivated\", {})\n })\n this.unsubscribers.push(unsubDeactivated)\n\n // Biometric events (Bot API 7.2+)\n // Official event: biometricManagerUpdated\n // Fires when BiometricManager object is updated\n const unsubBiometricManager = subscribeToTelegramEvent(\"biometricManagerUpdated\", () => {\n const biometricManager = webApp?.BiometricManager\n trackEvent(\"biometric_manager_updated\", {\n is_inited: biometricManager?.isInited,\n is_biometric_available: biometricManager?.isBiometricAvailable,\n biometric_type: biometricManager?.biometricType,\n is_access_requested: biometricManager?.isAccessRequested,\n is_access_granted: biometricManager?.isAccessGranted,\n is_biometric_token_saved: biometricManager?.isBiometricTokenSaved,\n device_id: biometricManager?.deviceId\n })\n })\n this.unsubscribers.push(unsubBiometricManager)\n\n // Official event: biometricAuthRequested (Bot API 7.2+)\n // Payload: {isAuthenticated: boolean, biometricToken?: string}\n const unsubBiometricAuth = subscribeToTelegramEvent(\"biometricAuthRequested\", (eventData: any) => {\n trackEvent(\"biometric_auth_requested\", {\n is_authenticated: eventData?.isAuthenticated,\n biometric_token: eventData?.biometricToken\n })\n })\n this.unsubscribers.push(unsubBiometricAuth)\n\n // Official event: biometricTokenUpdated (Bot API 7.2+)\n // Payload: {isUpdated: boolean}\n const unsubBiometricToken = subscribeToTelegramEvent(\"biometricTokenUpdated\", (eventData: any) => {\n trackEvent(\"biometric_token_updated\", {\n is_updated: eventData?.isUpdated\n })\n })\n this.unsubscribers.push(unsubBiometricToken)\n\n // Note: Cloud storage operations (CloudStorage.setItem, getItem, etc.) use callbacks,\n // not WebApp.onEvent() events. Storage tracking is done via method patching if needed.\n\n // Patch webApp methods to track their calls\n this.patchWebAppMethods(webApp, trackEvent)\n }\n\n /**\n * Patch Telegram WebApp methods to track their calls\n * Prevents double-patching by checking if method is already patched\n */\n private patchWebAppMethods(webApp: any, trackEvent: (eventName: string, data?: any) => void): void {\n if (!webApp) return\n\n // Check if already patched (prevent double-patching)\n if ((webApp.openLink as any)?._dashgramPatched) {\n return\n }\n\n // Track openLink calls\n if (webApp.openLink && typeof webApp.openLink === \"function\") {\n const originalOpenLink = webApp.openLink.bind(webApp)\n const patchedOpenLink = (url: string, options?: any) => {\n trackEvent(\"open_link\", {\n url: url,\n options: options\n })\n return originalOpenLink(url, options)\n }\n patchedOpenLink._dashgramPatched = true\n webApp.openLink = patchedOpenLink\n }\n\n // Track openTelegramLink calls\n if (webApp.openTelegramLink && typeof webApp.openTelegramLink === \"function\") {\n const originalOpenTelegramLink = webApp.openTelegramLink.bind(webApp)\n const patchedOpenTelegramLink = (url: string) => {\n trackEvent(\"open_telegram_link\", {\n url: url\n })\n return originalOpenTelegramLink(url)\n }\n patchedOpenTelegramLink._dashgramPatched = true\n webApp.openTelegramLink = patchedOpenTelegramLink\n }\n\n // Track switchInlineQuery calls\n if (webApp.switchInlineQuery && typeof webApp.switchInlineQuery === \"function\") {\n const originalSwitchInlineQuery = webApp.switchInlineQuery.bind(webApp)\n const patchedSwitchInlineQuery = (query: string, chooseChatTypes?: string[]) => {\n trackEvent(\"switch_inline_query\", {\n query: query,\n choose_chat_types: chooseChatTypes\n })\n return originalSwitchInlineQuery(query, chooseChatTypes)\n }\n patchedSwitchInlineQuery._dashgramPatched = true\n webApp.switchInlineQuery = patchedSwitchInlineQuery\n }\n\n // Track shareStory calls\n if (webApp.shareToStory && typeof webApp.shareToStory === \"function\") {\n const originalShareToStory = webApp.shareToStory.bind(webApp)\n const patchedShareToStory = (mediaUrl: string, params?: any) => {\n trackEvent(\"share_story\", {\n media_url: mediaUrl,\n params: params\n })\n return originalShareToStory(mediaUrl, params)\n }\n patchedShareToStory._dashgramPatched = true\n webApp.shareToStory = patchedShareToStory\n }\n\n // Track close calls\n if (webApp.close && typeof webApp.close === \"function\") {\n const originalClose = webApp.close.bind(webApp)\n const patchedClose = (options?: any) => {\n trackEvent(\"webapp_close\", {\n return_back: options?.return_back\n })\n return originalClose(options)\n }\n patchedClose._dashgramPatched = true\n webApp.close = patchedClose\n }\n\n // Track exitFullscreen calls\n if (webApp.exitFullscreen && typeof webApp.exitFullscreen === \"function\") {\n const originalExitFullscreen = webApp.exitFullscreen.bind(webApp)\n const patchedExitFullscreen = () => {\n trackEvent(\"webapp_exit_fullscreen\", {})\n return originalExitFullscreen()\n }\n patchedExitFullscreen._dashgramPatched = true\n webApp.exitFullscreen = patchedExitFullscreen\n }\n\n // Track openInvoice calls (triggers invoice_opened event)\n if (webApp.openInvoice && typeof webApp.openInvoice === \"function\") {\n const originalOpenInvoice = webApp.openInvoice.bind(webApp)\n const patchedOpenInvoice = (slug: string, callback?: (status: string) => void) => {\n trackEvent(\"open_invoice\", {\n slug: slug\n })\n return originalOpenInvoice(slug, callback)\n }\n patchedOpenInvoice._dashgramPatched = true\n webApp.openInvoice = patchedOpenInvoice\n }\n\n // Track requestAccess calls (triggers write_access_requested event)\n if (webApp.requestAccess && typeof webApp.requestAccess === \"function\") {\n const originalRequestAccess = webApp.requestAccess.bind(webApp)\n const patchedRequestAccess = (accessType: string, callback?: (status: string) => void) => {\n trackEvent(\"request_access\", {\n access_type: accessType\n })\n return originalRequestAccess(accessType, callback)\n }\n patchedRequestAccess._dashgramPatched = true\n webApp.requestAccess = patchedRequestAccess\n }\n\n // Track requestContact calls (triggers contact_requested event)\n if (webApp.requestContact && typeof webApp.requestContact === \"function\") {\n const originalRequestContact = webApp.requestContact.bind(webApp)\n const patchedRequestContact = (callback?: (status: string) => void) => {\n trackEvent(\"request_contact\", {})\n return originalRequestContact(callback)\n }\n patchedRequestContact._dashgramPatched = true\n webApp.requestContact = patchedRequestContact\n }\n\n // Track requestPhone calls (triggers phone_requested event)\n if (webApp.requestPhone && typeof webApp.requestPhone === \"function\") {\n const originalRequestPhone = webApp.requestPhone.bind(webApp)\n const patchedRequestPhone = (callback?: (status: string) => void) => {\n trackEvent(\"request_phone\", {})\n return originalRequestPhone(callback)\n }\n patchedRequestPhone._dashgramPatched = true\n webApp.requestPhone = patchedRequestPhone\n }\n\n // Track requestLocation calls (triggers location_requested event)\n if (webApp.requestLocation && typeof webApp.requestLocation === \"function\") {\n const originalRequestLocation = webApp.requestLocation.bind(webApp)\n const patchedRequestLocation = (callback?: (status: string, location?: any) => void) => {\n trackEvent(\"request_location\", {})\n return originalRequestLocation(callback)\n }\n patchedRequestLocation._dashgramPatched = true\n webApp.requestLocation = patchedRequestLocation\n }\n\n // Track checkLocation calls (triggers location_checked event)\n if (webApp.checkLocation && typeof webApp.checkLocation === \"function\") {\n const originalCheckLocation = webApp.checkLocation.bind(webApp)\n const patchedCheckLocation = (callback?: (isAvailable: boolean, location?: any) => void) => {\n trackEvent(\"check_location\", {})\n return originalCheckLocation(callback)\n }\n patchedCheckLocation._dashgramPatched = true\n webApp.checkLocation = patchedCheckLocation\n }\n }\n}\n","import type { DashgramConfig, WebAppEvent, EventProperties, TrackLevel } from \"./types\"\nimport { Config } from \"./core/config\"\nimport { Context } from \"./core/context\"\nimport { Transport } from \"./transport/transport\"\nimport { BatchProcessor } from \"./transport/batch-processor\"\nimport { CoreTracker } from \"./trackers/core-tracker\"\nimport { InteractionTracker } from \"./trackers/interaction-tracker\"\nimport { DeepTracker } from \"./trackers/deep-tracker\"\nimport { generateUUID, isBrowser } from \"./utils/helpers\"\nimport { getTelegramInitData } from \"./utils/telegram\"\n\n/**\n * Main Dashgram SDK class\n */\nclass DashgramSDK {\n private config: Config | null = null\n private context: Context | null = null\n private transport: Transport | null = null\n private batchProcessor: BatchProcessor | null = null\n private trackers: Array<CoreTracker | InteractionTracker | DeepTracker> = []\n private isInitialized = false\n\n /**\n * Initialize Dashgram SDK\n */\n init(userConfig: DashgramConfig): void {\n if (this.isInitialized) {\n if (userConfig.debug) {\n console.warn(\"Dashgram: Already initialized\")\n }\n return\n }\n\n if (!isBrowser()) {\n if (userConfig.debug) {\n console.warn(\"Dashgram: Not running in browser environment\")\n }\n return\n }\n\n try {\n // Initialize core components\n this.config = new Config(userConfig)\n\n // Set debug flag for global access\n if (typeof window !== \"undefined\") {\n ;(window as typeof window & { __DASHGRAM_DEBUG__?: boolean }).__DASHGRAM_DEBUG__ = this.config.isDebug()\n }\n\n this.context = new Context()\n this.transport = new Transport(this.config)\n this.batchProcessor = new BatchProcessor(this.config, this.transport)\n\n // Setup trackers\n this.setupTrackers()\n\n // Start batch processor\n this.batchProcessor.start()\n\n this.isInitialized = true\n\n this.log(\"Initialized successfully\", {\n projectId: this.config.get(\"projectId\"),\n trackLevel: this.config.getTrackLevel()\n })\n } catch (error) {\n console.error(\"Dashgram: Initialization failed\", error)\n throw error\n }\n }\n\n /**\n * Setup trackers based on track level\n */\n private setupTrackers(): void {\n if (!this.config) return\n\n const trackCallback = (event: string, properties: EventProperties) => {\n this.trackAuto(event, properties)\n }\n\n // Core tracker (Level 1)\n const coreTracker = new CoreTracker(this.config, trackCallback)\n this.trackers.push(coreTracker)\n coreTracker.start()\n\n // Interaction tracker (Level 2)\n const interactionTracker = new InteractionTracker(this.config, trackCallback)\n this.trackers.push(interactionTracker)\n interactionTracker.start()\n\n // Deep tracker (Level 3)\n const deepTracker = new DeepTracker(this.config, trackCallback)\n this.trackers.push(deepTracker)\n deepTracker.start()\n }\n\n /**\n * Track custom event (manual)\n */\n track(event: string, properties: EventProperties = {}): void {\n this.ensureInitialized()\n\n const fullEvent = this.buildEvent(event, properties, \"manual\")\n this.batchProcessor!.addEvent(fullEvent)\n\n this.log(\"Tracked event\", { event, properties })\n }\n\n /**\n * Track auto event (internal use by trackers)\n */\n private trackAuto(event: string, properties: EventProperties = {}): void {\n if (!this.isInitialized) return\n\n const fullEvent = this.buildEvent(event, properties, \"auto\")\n this.batchProcessor!.addEvent(fullEvent)\n\n this.log(\"Auto-tracked event\", { event, properties })\n }\n\n /**\n * Build full event object matching backend contract\n */\n private buildEvent(type: string, properties: EventProperties, source: \"auto\" | \"manual\"): WebAppEvent {\n this.ensureInitialized()\n\n return {\n eventId: generateUUID(),\n type,\n initData: getTelegramInitData(),\n properties: Object.keys(properties).length > 0 ? properties : undefined,\n telemetry: this.context!.getTelemetry(),\n source,\n level: this.config!.getTrackLevel(),\n timestamp: Date.now()\n }\n }\n\n /**\n * Set track level\n */\n setTrackLevel(level: TrackLevel): void {\n this.ensureInitialized()\n\n const oldLevel = this.config!.getTrackLevel()\n this.config!.setTrackLevel(level)\n\n // Restart trackers with new level\n this.trackers.forEach(tracker => {\n tracker.stop()\n tracker.start()\n })\n\n this.log(\"Track level changed\", { from: oldLevel, to: level })\n }\n\n /**\n * Flush all pending events\n */\n async flush(): Promise<void> {\n this.ensureInitialized()\n\n await this.batchProcessor!.flushAsync()\n\n this.log(\"Flushed all events\")\n }\n\n /**\n * Shutdown SDK\n */\n shutdown(): void {\n if (!this.isInitialized) {\n return\n }\n\n // Stop all trackers\n this.trackers.forEach(tracker => tracker.stop())\n this.trackers = []\n\n // Flush and stop batch processor\n this.batchProcessor!.flush()\n this.batchProcessor!.stop()\n\n this.isInitialized = false\n\n this.log(\"Shutdown complete\")\n }\n\n /**\n * Ensure SDK is initialized\n */\n private ensureInitialized(): void {\n if (!this.isInitialized) {\n throw new Error(\"Dashgram: SDK not initialized. Call init() first.\")\n }\n }\n\n /**\n * Log debug message\n */\n private log(...args: unknown[]): void {\n if (this.config?.isDebug()) {\n console.log(\"[Dashgram SDK]\", ...args)\n }\n }\n}\n\n// Create singleton instance\nconst DashgramMini = new DashgramSDK()\n\n// Export types\nexport type { DashgramConfig, WebAppEvent, EventProperties, TrackLevel }\n\n// Export error classes\nexport { DashgramError, DashgramAPIError, NetworkError, DashgramConfigurationError } from \"./errors\"\n\n// Export singleton\nexport { DashgramMini }\n\n// Default export\nexport default DashgramMini\n"],"names":["DashgramError","Error","constructor","message","super","this","name","ErrorWithCapture","captureStackTrace","DashgramAPIError","statusCode","details","NetworkError","originalError","DashgramConfigurationError","DEFAULT_CONFIG","trackLevel","apiUrl","batchSize","flushInterval","debug","disabled","Config","userConfig","config","validate","projectId","includes","get","key","getOnError","onError","getTrackUrl","replace","setTrackLevel","level","getTrackLevel","isDebug","isDisabled","getTelegramWebApp","window","win","Telegram","WebApp","getTelegramInitData","webApp","initData","getTelegramPlatform","platform","getTelegramTheme","colorScheme","themeParams","bg_color","bgColor","rgb","parseInt","slice","subscribeToTelegramEvent","event","callback","onEvent","wrappedCallback","_eventType","eventData","error","__DASHGRAM_DEBUG__","console","warn","offEvent","getTelemetry","user_agent","navigator","userAgent","timezone","Intl","DateTimeFormat","resolvedOptions","timeZone","undefined","theme","Context","telemetry","updateTelemetry","throttle","func","wait","timeout","previous","args","now","Date","remaining","clearTimeout","apply","setTimeout","safeStringify","obj","JSON","stringify","getElementSelector","element","id","className","classes","trim","split","join","tagName","toLowerCase","getElementText","maxLength","text","textContent","length","substring","Transport","isOnline","pendingRequests","Set","setupOnlineListener","addEventListener","log","onLine","buildPayload","events","origin","location","updates","send","request","sendRequest","add","logError","handlerError","delete","url","payload","response","fetch","method","headers","body","keepalive","ok","statusText","errorData","json","status","String","sendBeacon","blob","Blob","type","sent","flush","Promise","all","Array","from","EventQueue","maxSize","queue","enqueue","push","shift","peek","size","isEmpty","clear","BatchProcessor","transport","flushTimer","isStarted","start","scheduleFlush","setupPageUnloadHandler","stop","addEvent","interval","flushAsync","handleUnload","document","visibilityState","BaseTracker","trackCallback","isActive","setup","teardown","track","properties","CoreTracker","unsubscribers","hasTrackedAppOpen","trackAppOpen","setupVisibilityTracking","setupUnloadTracking","forEach","unsubscribe","referrer","handleVisibilityChange","visibility_state","removeEventListener","reason","InteractionTracker","lastPath","inputValues","Map","trackScreenView","setupHistoryTracking","setupClickTracking","setupFormTracking","setupInputTracking","setupClipboardTracking","setupSelectionTracking","setupErrorTracking","path","pathname","href","title","originalPushState","history","pushState","originalReplaceState","replaceState","trackOnHistoryChange","handleClick","target","button","closest","anchor","isExternal","isExternalLink","is_external","is_download","hasAttribute","capture","URL","handleSubmit","form","form_id","form_name","form_action","action","form_method","handleFocus","input","set","value","input_type","input_name","input_id","handleBlur","previousValue","currentValue","had_value","has_value","handleCopy","_event","selection","getSelection","selectedText","toString","text_length","has_selection","handleCut","handlePaste","pastedText","clipboardData","getData","target_element","selectionTimeout","handleSelectionChange","handleError","filename","lineno","colno","stack","handleRejection","promise","DeepTracker","observers","clickTracker","maxScrollDepth","trackedMedia","WeakSet","setupScrollTracking","setupRageClickTracking","setupLongTaskTracking","setupWebVitals","setupNetworkTracking","setupOrientationTracking","setupMediaTracking","setupTelegramTracking","observer","disconnect","getScrollDepth","windowHeight","innerHeight","documentHeight","documentElement","scrollHeight","scrollTop","pageYOffset","scrollPercentage","Math","min","round","handleScroll","depth","milestone","find","m","max_depth","passive","IntersectionObserver","entries","entry","isIntersecting","selector","getAttribute","intersection_ratio","intersectionRatio","unobserve","threshold","querySelectorAll","observe","mutationObserver","MutationObserver","mutations","mutation","addedNodes","node","Element","el","childList","subtree","tracker","count","timer","click_count","PerformanceObserver","list","getEntries","duration","start_time","startTime","entryTypes","lcpObserver","lastEntry","renderTime","loadTime","fidObserver","processingStart","event_type","clsValue","clsObserver","hadRecentInput","reportCLS","handleOnline","effective_type","connection","effectiveType","downlink","rtt","handleOffline","handleConnectionChange","save_data","saveData","handleOrientationChange","orientation","screen","innerWidth","angle","width","height","trackMediaEvent","media","has","mediaType","eventType","baseProps","media_type","src","currentSrc","isFinite","current_time","currentTime","muted","volume","percent_played","completed","setupMediaElement","HTMLMediaElement","trackEvent","eventName","data","unsubTheme","color_scheme","theme_params","unsubViewport","is_state_stable","isStateStable","is_expanded","isExpanded","viewport_height","viewportHeight","viewport_stable_height","viewportStableHeight","unsubSafeArea","safe_area","safeAreaInset","unsubContentSafeArea","content_safe_area","contentSafeAreaInset","unsubBackButton","unsubMainButton","button_text","MainButton","unsubInvoice","unsubPopup","button_id","unsubQrText","unsubScanQr","unsubClipboard","unsubWriteAccess","unsubFileDownload","unsubCustomMethod","req_id","result","unsubFullscreen","is_fullscreen","isFullscreen","unsubFullscreenFailed","unsubHomeScreenAdded","unsubHomeScreenChecked","unsubPreparedMessageSent","unsubPreparedMessageFailed","unsubEmojiStatusSet","unsubEmojiStatusFailed","unsubEmojiStatusAccess","unsubSettingsButton","unsubSecondaryButton","unsubShareMessageSent","unsubShareMessageFailed","unsubLocationManager","locationManager","LocationManager","is_inited","isInited","is_location_available","isLocationAvailable","is_access_requested","isAccessRequested","is_access_granted","isAccessGranted","unsubLocationRequested","available","latitude","longitude","altitude","course","speed","horizontal_accuracy","vertical_accuracy","course_accuracy","speed_accuracy","unsubAccelerometerStarted","unsubAccelerometerStopped","unsubAccelerometerChanged","accelerometer","Accelerometer","x","y","z","unsubAccelerometerFailed","unsubDeviceOrientationStarted","unsubDeviceOrientationStopped","unsubDeviceOrientationChanged","deviceOrientation","DeviceOrientation","absolute","alpha","beta","gamma","unsubDeviceOrientationFailed","unsubGyroscopeStarted","unsubGyroscopeStopped","unsubGyroscopeChanged","gyroscope","Gyroscope","unsubGyroscopeFailed","unsubContactRequested","unsubActivated","unsubDeactivated","unsubBiometricManager","biometricManager","BiometricManager","is_biometric_available","isBiometricAvailable","biometric_type","biometricType","is_biometric_token_saved","isBiometricTokenSaved","device_id","deviceId","unsubBiometricAuth","is_authenticated","isAuthenticated","biometric_token","biometricToken","unsubBiometricToken","is_updated","isUpdated","patchWebAppMethods","openLink","_dashgramPatched","originalOpenLink","bind","patchedOpenLink","options","openTelegramLink","originalOpenTelegramLink","patchedOpenTelegramLink","switchInlineQuery","originalSwitchInlineQuery","patchedSwitchInlineQuery","query","chooseChatTypes","choose_chat_types","shareToStory","originalShareToStory","patchedShareToStory","mediaUrl","params","media_url","close","originalClose","patchedClose","return_back","exitFullscreen","originalExitFullscreen","patchedExitFullscreen","openInvoice","originalOpenInvoice","patchedOpenInvoice","slug","requestAccess","originalRequestAccess","patchedRequestAccess","accessType","access_type","requestContact","originalRequestContact","patchedRequestContact","requestPhone","originalRequestPhone","patchedRequestPhone","requestLocation","originalRequestLocation","patchedRequestLocation","checkLocation","originalCheckLocation","patchedCheckLocation","DashgramMini","context","batchProcessor","trackers","isInitialized","init","setupTrackers","trackAuto","coreTracker","interactionTracker","deepTracker","ensureInitialized","fullEvent","buildEvent","source","eventId","crypto","randomUUID","c","r","random","Object","keys","timestamp","oldLevel","to","shutdown"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"dashgram.min.js","sources":["../src/errors.ts","../src/core/config.ts","../src/utils/telegram.ts","../src/utils/device.ts","../src/core/context.ts","../src/utils/helpers.ts","../src/transport/transport.ts","../src/core/event-queue.ts","../src/transport/batch-processor.ts","../src/trackers/base-tracker.ts","../src/trackers/core-tracker.ts","../src/trackers/interaction-tracker.ts","../src/trackers/deep-tracker.ts","../src/index.ts"],"sourcesContent":["/**\n * Extended ErrorConstructor interface for V8-specific methods\n */\ninterface ErrorConstructorWithCapture {\n captureStackTrace?(error: Error, constructor?: Function): void\n}\n\n/**\n * Base error class for all Dashgram SDK errors\n */\nexport class DashgramError extends Error {\n constructor(message: string) {\n super(message)\n this.name = \"DashgramError\"\n const ErrorWithCapture = Error as unknown as ErrorConstructorWithCapture\n if (typeof ErrorWithCapture.captureStackTrace === \"function\") {\n ErrorWithCapture.captureStackTrace(this, DashgramError)\n }\n }\n}\n\n/**\n * Error thrown when the Dashgram API returns an error response\n */\nexport class DashgramAPIError extends DashgramError {\n constructor(public statusCode: number, public details: string) {\n super(`Dashgram API error (${statusCode}): ${details}`)\n this.name = \"DashgramAPIError\"\n const ErrorWithCapture = Error as unknown as ErrorConstructorWithCapture\n if (typeof ErrorWithCapture.captureStackTrace === \"function\") {\n ErrorWithCapture.captureStackTrace(this, DashgramAPIError)\n }\n }\n}\n\n/**\n * Error thrown when a network request fails\n */\nexport class NetworkError extends DashgramError {\n constructor(public originalError: Error) {\n super(`Network error: ${originalError.message}`)\n this.name = \"NetworkError\"\n const ErrorWithCapture = Error as unknown as ErrorConstructorWithCapture\n if (typeof ErrorWithCapture.captureStackTrace === \"function\") {\n ErrorWithCapture.captureStackTrace(this, NetworkError)\n }\n }\n}\n\n/**\n * Error thrown when SDK is used incorrectly (e.g., not initialized)\n */\nexport class DashgramConfigurationError extends DashgramError {\n constructor(message: string) {\n super(message)\n this.name = \"DashgramConfigurationError\"\n const ErrorWithCapture = Error as unknown as ErrorConstructorWithCapture\n if (typeof ErrorWithCapture.captureStackTrace === \"function\") {\n ErrorWithCapture.captureStackTrace(this, DashgramConfigurationError)\n }\n }\n}\n","import type { DashgramConfig, TrackLevel } from \"../types\"\nimport { DashgramConfigurationError } from \"../errors\"\n\n/**\n * Default configuration\n */\nconst DEFAULT_CONFIG: Required<Omit<DashgramConfig, \"projectId\" | \"onError\">> = {\n trackLevel: 1,\n apiUrl: \"https://api.dashgram.io/v1\",\n batchSize: 10,\n flushInterval: 5000, // 5 seconds\n debug: false,\n disabled: false\n}\n\n/**\n * Configuration manager\n */\nexport class Config {\n private config: Required<Omit<DashgramConfig, \"onError\">> & Pick<DashgramConfig, \"onError\">\n\n constructor(userConfig: DashgramConfig) {\n this.config = {\n ...DEFAULT_CONFIG,\n ...userConfig\n } as Required<Omit<DashgramConfig, \"onError\">> & Pick<DashgramConfig, \"onError\">\n\n this.validate()\n }\n\n /**\n * Validate configuration\n */\n private validate(): void {\n if (!this.config.projectId) {\n throw new DashgramConfigurationError(\"projectId is required\")\n }\n\n if (![1, 2, 3].includes(this.config.trackLevel)) {\n throw new DashgramConfigurationError(\"trackLevel must be 1, 2, or 3\")\n }\n }\n\n /**\n * Get configuration value\n */\n get<K extends keyof Required<Omit<DashgramConfig, \"onError\">>>(key: K): Required<Omit<DashgramConfig, \"onError\">>[K] {\n return this.config[key]\n }\n\n /**\n * Get error handler callback\n */\n getOnError(): DashgramConfig[\"onError\"] {\n return this.config.onError\n }\n\n /**\n * Get the full API URL for tracking\n */\n getTrackUrl(): string {\n const baseUrl = this.config.apiUrl.replace(/\\/$/, \"\")\n return `${baseUrl}/${this.config.projectId}/webapp/track`\n }\n\n /**\n * Set track level\n */\n setTrackLevel(level: TrackLevel): void {\n if (![1, 2, 3].includes(level)) {\n throw new DashgramConfigurationError(\"trackLevel must be 1, 2, or 3\")\n }\n this.config.trackLevel = level\n }\n\n /**\n * Get track level\n */\n getTrackLevel(): TrackLevel {\n return this.config.trackLevel\n }\n\n /**\n * Check if debug mode is enabled\n */\n isDebug(): boolean {\n return this.config.debug\n }\n\n /**\n * Check if tracking is disabled\n */\n isDisabled(): boolean {\n return this.config.disabled\n }\n}\n","import type { TelegramWebApp, TelegramWindow } from \"../types\"\n\n/**\n * Get Telegram WebApp instance\n */\nexport function getTelegramWebApp(): TelegramWebApp | null {\n if (typeof window === \"undefined\") {\n return null\n }\n\n const win = window as TelegramWindow\n return win.Telegram?.WebApp || null\n}\n\n/**\n * Check if running inside Telegram Mini App\n */\nexport function isTelegramMiniApp(): boolean {\n return getTelegramWebApp() !== null\n}\n\n/**\n * Get raw Telegram initData string (passed as-is to backend)\n */\nexport function getTelegramInitData(): string {\n const webApp = getTelegramWebApp()\n return webApp?.initData || \"\"\n}\n\n/**\n * Get Telegram platform\n */\nexport function getTelegramPlatform(): string {\n const webApp = getTelegramWebApp()\n return webApp?.platform || \"unknown\"\n}\n\n/**\n * Get Telegram theme (light/dark)\n */\nexport function getTelegramTheme(): string | undefined {\n const webApp = getTelegramWebApp()\n\n // Use colorScheme directly if available\n if (webApp?.colorScheme) {\n return webApp.colorScheme\n }\n\n // Fallback: detect from themeParams\n if (webApp?.themeParams?.bg_color) {\n const bgColor = webApp.themeParams.bg_color\n try {\n const rgb = parseInt(bgColor.slice(1), 16)\n const r = (rgb >> 16) & 0xff\n const g = (rgb >> 8) & 0xff\n const b = (rgb >> 0) & 0xff\n const luma = 0.2126 * r + 0.7152 * g + 0.0722 * b\n return luma < 128 ? \"dark\" : \"light\"\n } catch {\n return undefined\n }\n }\n\n return undefined\n}\n\n/**\n * Subscribe to Telegram WebApp events\n */\nexport function subscribeToTelegramEvent(event: string, callback: (eventData?: unknown) => void): () => void {\n const webApp = getTelegramWebApp()\n\n if (!webApp || !webApp.onEvent) {\n return () => {}\n }\n\n try {\n const wrappedCallback = (_eventType: string, eventData?: unknown) => {\n try {\n callback(eventData)\n } catch (error) {\n if (\n typeof window !== \"undefined\" &&\n (window as typeof window & { __DASHGRAM_DEBUG__?: boolean }).__DASHGRAM_DEBUG__\n ) {\n console.warn(`[Dashgram] Error in Telegram event callback for ${event}:`, error)\n }\n }\n }\n\n webApp.onEvent(event, wrappedCallback)\n\n return () => {\n try {\n if (webApp.offEvent) {\n webApp.offEvent(event, wrappedCallback)\n }\n } catch {\n // Ignore unsubscribe errors silently\n }\n }\n } catch {\n return () => {}\n }\n}\n","import type { Telemetry } from \"../types\"\nimport { getTelegramPlatform, getTelegramTheme } from \"./telegram\"\n\n/**\n * Get telemetry data for events\n */\nexport function getTelemetry(): Telemetry {\n if (typeof window === \"undefined\") {\n return {\n platform: \"unknown\"\n }\n }\n\n return {\n platform: getTelegramPlatform(),\n user_agent: navigator.userAgent,\n timezone: Intl.DateTimeFormat().resolvedOptions().timeZone || undefined,\n theme: getTelegramTheme()\n }\n}\n\n/**\n * Get current URL\n */\nexport function getCurrentUrl(): string {\n if (typeof window === \"undefined\") {\n return \"\"\n }\n\n return window.location.href\n}\n\n/**\n * Get current page path\n */\nexport function getCurrentPath(): string {\n if (typeof window === \"undefined\") {\n return \"\"\n }\n\n return window.location.pathname\n}\n\n/**\n * Get page title\n */\nexport function getPageTitle(): string {\n if (typeof document === \"undefined\") {\n return \"\"\n }\n\n return document.title || \"\"\n}\n\n/**\n * Get current origin\n */\nexport function getCurrentOrigin(): string {\n if (typeof window === \"undefined\") {\n return \"\"\n }\n\n return window.location.origin\n}\n","import type { Telemetry } from \"../types\"\nimport { getTelemetry } from \"../utils/device\"\n\n/**\n * Context manager - maintains telemetry data\n */\nexport class Context {\n private telemetry: Telemetry\n\n constructor() {\n this.telemetry = getTelemetry()\n }\n\n /**\n * Get current telemetry\n */\n getTelemetry(): Telemetry {\n return { ...this.telemetry }\n }\n\n /**\n * Update telemetry (e.g., after theme change)\n */\n updateTelemetry(): void {\n this.telemetry = getTelemetry()\n }\n}\n","/**\n * Generate a UUID v4\n */\nexport function generateUUID(): string {\n if (typeof crypto !== 'undefined' && crypto.randomUUID) {\n return crypto.randomUUID();\n }\n\n // Fallback for older browsers\n return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => {\n const r = (Math.random() * 16) | 0;\n const v = c === 'x' ? r : (r & 0x3) | 0x8;\n return v.toString(16);\n });\n}\n\n/**\n * Get current ISO 8601 timestamp\n */\nexport function getTimestamp(): string {\n return new Date().toISOString();\n}\n\n/**\n * Throttle function execution\n */\nexport function throttle<T extends (...args: any[]) => any>(\n func: T,\n wait: number\n): (...args: Parameters<T>) => void {\n let timeout: ReturnType<typeof setTimeout> | null = null;\n let previous = 0;\n\n return function (this: any, ...args: Parameters<T>) {\n const now = Date.now();\n const remaining = wait - (now - previous);\n\n if (remaining <= 0 || remaining > wait) {\n if (timeout) {\n clearTimeout(timeout);\n timeout = null;\n }\n previous = now;\n func.apply(this, args);\n } else if (!timeout) {\n timeout = setTimeout(() => {\n previous = Date.now();\n timeout = null;\n func.apply(this, args);\n }, remaining);\n }\n };\n}\n\n/**\n * Debounce function execution\n */\nexport function debounce<T extends (...args: any[]) => any>(\n func: T,\n wait: number\n): (...args: Parameters<T>) => void {\n let timeout: ReturnType<typeof setTimeout> | null = null;\n\n return function (this: any, ...args: Parameters<T>) {\n if (timeout) {\n clearTimeout(timeout);\n }\n timeout = setTimeout(() => {\n func.apply(this, args);\n }, wait);\n };\n}\n\n/**\n * Safe JSON stringify\n */\nexport function safeStringify(obj: any): string {\n try {\n return JSON.stringify(obj);\n } catch (error) {\n return '{}';\n }\n}\n\n/**\n * Check if code is running in browser\n */\nexport function isBrowser(): boolean {\n return typeof window !== 'undefined' && typeof document !== 'undefined';\n}\n\n/**\n * Get element selector path\n */\nexport function getElementSelector(element: Element): string {\n if (element.id) {\n return `#${element.id}`;\n }\n\n if (element.className && typeof element.className === 'string') {\n const classes = element.className.trim().split(/\\s+/).slice(0, 2).join('.');\n if (classes) {\n return `${element.tagName.toLowerCase()}.${classes}`;\n }\n }\n\n return element.tagName.toLowerCase();\n}\n\n/**\n * Get element text content (truncated)\n */\nexport function getElementText(element: Element, maxLength = 50): string {\n const text = element.textContent?.trim() || '';\n return text.length > maxLength ? text.substring(0, maxLength) + '...' : text;\n}\n\n\n\n\n\n","import type { WebAppEvent, WebAppTrackRequest } from \"../types\"\nimport type { Config } from \"../core/config\"\nimport { safeStringify } from \"../utils/helpers\"\nimport { DashgramAPIError, NetworkError } from \"../errors\"\nimport { getCurrentOrigin } from \"../utils/device\"\n\n/**\n * Transport layer - sends events to backend\n */\nexport class Transport {\n private config: Config\n private isOnline: boolean = true\n private pendingRequests: Set<Promise<void>> = new Set()\n\n constructor(config: Config) {\n this.config = config\n this.setupOnlineListener()\n }\n\n /**\n * Setup online/offline listener\n */\n private setupOnlineListener(): void {\n if (typeof window === \"undefined\") {\n return\n }\n\n window.addEventListener(\"online\", () => {\n this.isOnline = true\n this.log(\"Connection restored\")\n })\n\n window.addEventListener(\"offline\", () => {\n this.isOnline = false\n this.log(\"Connection lost\")\n })\n\n this.isOnline = navigator.onLine\n }\n\n /**\n * Build request payload\n */\n private buildPayload(events: WebAppEvent[]): WebAppTrackRequest {\n return {\n origin: getCurrentOrigin() || undefined,\n updates: events\n }\n }\n\n /**\n * Send events to backend\n */\n async send(events: WebAppEvent[]): Promise<void> {\n if (events.length === 0) {\n return\n }\n\n if (this.config.isDisabled()) {\n this.log(\"Tracking disabled, skipping send\")\n return\n }\n\n if (!this.isOnline) {\n this.log(\"Offline, skipping send\")\n return\n }\n\n const request = this.sendRequest(events)\n this.pendingRequests.add(request)\n\n try {\n await request\n } catch (error) {\n this.logError(\"Failed to send events:\", error)\n\n const onError = this.config.getOnError()\n if (onError) {\n try {\n if (error instanceof DashgramAPIError || error instanceof NetworkError) {\n onError(error)\n } else if (error instanceof Error) {\n onError(new NetworkError(error))\n }\n } catch (handlerError) {\n this.logError(\"Error in onError callback:\", handlerError)\n }\n }\n } finally {\n this.pendingRequests.delete(request)\n }\n }\n\n /**\n * Send request to backend\n */\n private async sendRequest(events: WebAppEvent[]): Promise<void> {\n const url = this.config.getTrackUrl()\n const payload = this.buildPayload(events)\n\n try {\n const response = await fetch(url, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\"\n },\n body: safeStringify(payload),\n keepalive: true\n })\n\n if (!response.ok) {\n let details = response.statusText\n try {\n const errorData = await response.json()\n details = errorData.details || errorData.message || details\n } catch {\n // Ignore JSON parse errors\n }\n\n throw new DashgramAPIError(response.status, details)\n }\n\n this.log(`Sent ${events.length} events successfully`)\n } catch (error) {\n if (error instanceof DashgramAPIError) {\n throw error\n }\n\n if (error instanceof Error) {\n throw new NetworkError(error)\n }\n\n throw new NetworkError(new Error(String(error)))\n }\n }\n\n /**\n * Send events using sendBeacon (for page unload)\n */\n sendBeacon(events: WebAppEvent[]): boolean {\n if (events.length === 0) {\n return true\n }\n\n if (this.config.isDisabled()) {\n return true\n }\n\n if (typeof navigator === \"undefined\" || !navigator.sendBeacon) {\n return false\n }\n\n const url = this.config.getTrackUrl()\n const payload = this.buildPayload(events)\n\n const blob = new Blob([safeStringify(payload)], { type: \"application/json\" })\n const sent = navigator.sendBeacon(url, blob)\n\n this.log(`sendBeacon ${sent ? \"succeeded\" : \"failed\"} for ${events.length} events`)\n\n return sent\n }\n\n /**\n * Wait for all pending requests to complete\n */\n async flush(): Promise<void> {\n await Promise.all(Array.from(this.pendingRequests))\n }\n\n /**\n * Log debug message\n */\n private log(...args: unknown[]): void {\n if (this.config.isDebug()) {\n console.log(\"[Dashgram Transport]\", ...args)\n }\n }\n\n /**\n * Log error message\n */\n private logError(...args: unknown[]): void {\n if (this.config.isDebug()) {\n console.error(\"[Dashgram Transport]\", ...args)\n }\n }\n}\n","import type { WebAppEvent } from \"../types\"\n\n/**\n * Event queue manager\n */\nexport class EventQueue {\n private queue: WebAppEvent[] = []\n private maxSize: number\n\n constructor(maxSize: number = 100) {\n this.maxSize = maxSize\n }\n\n /**\n * Add event to queue\n */\n enqueue(event: WebAppEvent): void {\n this.queue.push(event)\n\n // Prevent queue from growing too large\n if (this.queue.length > this.maxSize) {\n this.queue.shift()\n }\n }\n\n /**\n * Get all events and clear queue\n */\n flush(): WebAppEvent[] {\n const events = [...this.queue]\n this.queue = []\n return events\n }\n\n /**\n * Get events without clearing queue\n */\n peek(): WebAppEvent[] {\n return [...this.queue]\n }\n\n /**\n * Get queue size\n */\n size(): number {\n return this.queue.length\n }\n\n /**\n * Check if queue is empty\n */\n isEmpty(): boolean {\n return this.queue.length === 0\n }\n\n /**\n * Clear queue\n */\n clear(): void {\n this.queue = []\n }\n}\n","import type { WebAppEvent } from \"../types\"\nimport type { Config } from \"../core/config\"\nimport { EventQueue } from \"../core/event-queue\"\nimport { Transport } from \"./transport\"\n\n/**\n * Batch processor - batches events and sends them periodically\n */\nexport class BatchProcessor {\n private config: Config\n private queue: EventQueue\n private transport: Transport\n private flushTimer: ReturnType<typeof setTimeout> | null = null\n private isStarted: boolean = false\n\n constructor(config: Config, transport: Transport) {\n this.config = config\n this.transport = transport\n this.queue = new EventQueue(200)\n }\n\n /**\n * Start batch processor\n */\n start(): void {\n if (this.isStarted) {\n return\n }\n\n this.isStarted = true\n this.scheduleFlush()\n this.setupPageUnloadHandler()\n }\n\n /**\n * Stop batch processor\n */\n stop(): void {\n this.isStarted = false\n\n if (this.flushTimer) {\n clearTimeout(this.flushTimer)\n this.flushTimer = null\n }\n }\n\n /**\n * Add event to batch\n */\n addEvent(event: WebAppEvent): void {\n this.queue.enqueue(event)\n\n // Auto-flush if batch size reached\n const batchSize = this.config.get(\"batchSize\")\n if (this.queue.size() >= batchSize) {\n this.flush()\n }\n }\n\n /**\n * Schedule periodic flush\n */\n private scheduleFlush(): void {\n if (this.flushTimer) {\n clearTimeout(this.flushTimer)\n }\n\n const interval = this.config.get(\"flushInterval\")\n this.flushTimer = setTimeout(() => {\n this.flush()\n\n if (this.isStarted) {\n this.scheduleFlush()\n }\n }, interval)\n }\n\n /**\n * Flush all events\n */\n flush(): void {\n const events = this.queue.flush()\n\n if (events.length > 0) {\n this.transport.send(events)\n }\n }\n\n /**\n * Flush all events and wait for completion\n */\n async flushAsync(): Promise<void> {\n const events = this.queue.flush()\n\n if (events.length > 0) {\n await this.transport.send(events)\n }\n\n await this.transport.flush()\n }\n\n /**\n * Setup page unload handler\n */\n private setupPageUnloadHandler(): void {\n if (typeof window === \"undefined\") {\n return\n }\n\n const handleUnload = () => {\n const events = this.queue.flush()\n if (events.length > 0) {\n this.transport.sendBeacon(events)\n }\n }\n\n window.addEventListener(\"visibilitychange\", () => {\n if (document.visibilityState === \"hidden\") {\n handleUnload()\n }\n })\n\n window.addEventListener(\"pagehide\", handleUnload)\n window.addEventListener(\"beforeunload\", handleUnload)\n }\n}\n","import type { TrackLevel, EventProperties } from \"../types\"\nimport type { Config } from \"../core/config\"\n\n/**\n * Callback for tracking events\n */\nexport type TrackCallback = (event: string, properties: EventProperties) => void\n\n/**\n * Base tracker class\n */\nexport abstract class BaseTracker {\n protected config: Config\n protected trackCallback: TrackCallback\n protected isActive: boolean = false\n protected level: TrackLevel\n\n constructor(config: Config, trackCallback: TrackCallback, level: TrackLevel) {\n this.config = config\n this.trackCallback = trackCallback\n this.level = level\n }\n\n /**\n * Start tracking\n */\n start(): void {\n if (this.isActive) {\n return\n }\n\n const currentLevel = this.config.getTrackLevel()\n\n // Only start if current track level meets required level\n if (currentLevel >= this.level) {\n this.isActive = true\n this.setup()\n this.log(`Started (level ${this.level})`)\n }\n }\n\n /**\n * Stop tracking\n */\n stop(): void {\n if (!this.isActive) {\n return\n }\n\n this.isActive = false\n this.teardown()\n this.log(`Stopped`)\n }\n\n /**\n * Track event\n */\n protected track(event: string, properties: EventProperties = {}): void {\n if (!this.isActive) {\n return\n }\n\n this.trackCallback(event, properties)\n }\n\n /**\n * Setup tracking (implement in subclass)\n */\n protected abstract setup(): void\n\n /**\n * Teardown tracking (implement in subclass)\n */\n protected abstract teardown(): void\n\n /**\n * Log debug message\n */\n protected log(...args: unknown[]): void {\n if (this.config.isDebug()) {\n console.log(`[Dashgram ${this.constructor.name}]`, ...args)\n }\n }\n}\n","import { BaseTracker } from \"./base-tracker\"\nimport type { Config } from \"../core/config\"\nimport type { TrackCallback } from \"./base-tracker\"\n\n/**\n * Core tracker (Level 1)\n * Tracks: app_open, app_close\n */\nexport class CoreTracker extends BaseTracker {\n private unsubscribers: (() => void)[] = []\n private hasTrackedAppOpen = false\n\n constructor(config: Config, trackCallback: TrackCallback) {\n super(config, trackCallback, 1)\n }\n\n protected setup(): void {\n if (typeof window === \"undefined\") {\n return\n }\n\n // Track app_open on first load\n this.trackAppOpen()\n\n // Track app_close on visibility change and page unload\n this.setupVisibilityTracking()\n this.setupUnloadTracking()\n }\n\n protected teardown(): void {\n this.unsubscribers.forEach(unsubscribe => unsubscribe())\n this.unsubscribers = []\n }\n\n /**\n * Track app_open event\n */\n private trackAppOpen(): void {\n if (this.hasTrackedAppOpen) {\n return\n }\n\n this.track(\"app_open\", {\n referrer: document.referrer || \"direct\"\n })\n\n this.hasTrackedAppOpen = true\n }\n\n /**\n * Setup visibility tracking\n */\n private setupVisibilityTracking(): void {\n const handleVisibilityChange = () => {\n if (document.visibilityState === \"hidden\") {\n this.track(\"app_close\", {\n visibility_state: \"hidden\"\n })\n } else if (document.visibilityState === \"visible\") {\n this.track(\"app_open\", {\n visibility_state: \"visible\"\n })\n }\n }\n\n document.addEventListener(\"visibilitychange\", handleVisibilityChange)\n\n this.unsubscribers.push(() => {\n document.removeEventListener(\"visibilitychange\", handleVisibilityChange)\n })\n }\n\n /**\n * Setup page unload tracking\n */\n private setupUnloadTracking(): void {\n const handleUnload = () => {\n this.track(\"app_close\", {\n reason: \"unload\"\n })\n }\n\n window.addEventListener(\"pagehide\", handleUnload)\n\n this.unsubscribers.push(() => {\n window.removeEventListener(\"pagehide\", handleUnload)\n })\n\n window.addEventListener(\"beforeunload\", handleUnload)\n\n this.unsubscribers.push(() => {\n window.removeEventListener(\"beforeunload\", handleUnload)\n })\n }\n}\n","import { BaseTracker } from \"./base-tracker\"\nimport type { Config } from \"../core/config\"\nimport type { TrackCallback } from \"./base-tracker\"\nimport { throttle } from \"../utils/helpers\"\nimport { getElementSelector, getElementText } from \"../utils/helpers\"\nimport { getCurrentPath, getPageTitle, getCurrentUrl } from \"../utils/device\"\n\n/**\n * Interaction tracker (Level 2)\n * Tracks: screen_view, button_click, link_click, form_submit, input_focus, input_change,\n * copy, cut, paste, text_select, errors\n */\nexport class InteractionTracker extends BaseTracker {\n private unsubscribers: (() => void)[] = []\n private lastPath: string = \"\"\n private inputValues = new Map<HTMLElement, string>()\n\n constructor(config: Config, trackCallback: TrackCallback) {\n super(config, trackCallback, 2)\n }\n\n protected setup(): void {\n if (typeof window === \"undefined\") {\n return\n }\n\n // Track initial screen view\n this.trackScreenView()\n\n // Setup tracking\n this.setupHistoryTracking()\n this.setupClickTracking()\n this.setupFormTracking()\n this.setupInputTracking()\n this.setupClipboardTracking()\n this.setupSelectionTracking()\n this.setupErrorTracking()\n }\n\n protected teardown(): void {\n this.unsubscribers.forEach(unsubscribe => unsubscribe())\n this.unsubscribers = []\n }\n\n /**\n * Track screen view\n */\n private trackScreenView(): void {\n const path = getCurrentPath()\n\n if (path === this.lastPath) {\n return\n }\n\n this.lastPath = path\n\n this.track(\"screen_view\", {\n path,\n url: getCurrentUrl(),\n title: getPageTitle(),\n referrer: document.referrer || \"direct\"\n })\n }\n\n /**\n * Setup history tracking (for SPAs)\n */\n private setupHistoryTracking(): void {\n // Patch pushState and replaceState\n const originalPushState = history.pushState\n const originalReplaceState = history.replaceState\n\n const trackOnHistoryChange = () => {\n this.trackScreenView()\n }\n\n history.pushState = function (...args) {\n originalPushState.apply(history, args)\n trackOnHistoryChange()\n }\n\n history.replaceState = function (...args) {\n originalReplaceState.apply(history, args)\n trackOnHistoryChange()\n }\n\n // Listen to popstate (back/forward buttons)\n window.addEventListener(\"popstate\", trackOnHistoryChange)\n\n this.unsubscribers.push(() => {\n history.pushState = originalPushState\n history.replaceState = originalReplaceState\n window.removeEventListener(\"popstate\", trackOnHistoryChange)\n })\n }\n\n /**\n * Setup click tracking\n */\n private setupClickTracking(): void {\n const handleClick = (event: MouseEvent) => {\n const target = event.target as Element\n if (!target) return\n\n // Find closest interactive element\n const button = target.closest('button, [role=\"button\"], a')\n\n if (button) {\n const tagName = button.tagName.toLowerCase()\n const isLink = tagName === \"a\"\n\n if (isLink) {\n const anchor = button as HTMLAnchorElement\n const href = anchor.href\n const isExternal = href ? this.isExternalLink(href) : false\n\n this.track(\"link_click\", {\n element: getElementSelector(button),\n text: getElementText(button),\n href: href || undefined,\n target: anchor.target || undefined,\n is_external: isExternal,\n is_download: anchor.hasAttribute(\"download\")\n })\n } else {\n this.track(\"button_click\", {\n element: getElementSelector(button),\n text: getElementText(button)\n })\n }\n }\n }\n\n document.addEventListener(\"click\", handleClick, { capture: true })\n\n this.unsubscribers.push(() => {\n document.removeEventListener(\"click\", handleClick, { capture: true })\n })\n }\n\n /**\n * Check if a URL is external\n */\n private isExternalLink(url: string): boolean {\n try {\n const linkUrl = new URL(url, window.location.href)\n return linkUrl.origin !== window.location.origin\n } catch {\n return false\n }\n }\n\n /**\n * Setup form tracking\n */\n private setupFormTracking(): void {\n const handleSubmit = (event: SubmitEvent) => {\n const form = event.target as HTMLFormElement\n if (!form) return\n\n this.track(\"form_submit\", {\n form_id: form.id || undefined,\n form_name: form.name || undefined,\n form_action: form.action || undefined,\n form_method: form.method || undefined\n })\n }\n\n document.addEventListener(\"submit\", handleSubmit, { capture: true })\n\n this.unsubscribers.push(() => {\n document.removeEventListener(\"submit\", handleSubmit, { capture: true })\n })\n }\n\n /**\n * Setup input tracking (focus and change)\n */\n private setupInputTracking(): void {\n // Track input focus\n const handleFocus = throttle((event: FocusEvent) => {\n const target = event.target as HTMLElement\n if (!target) return\n\n const tagName = target.tagName.toLowerCase()\n if ([\"input\", \"textarea\", \"select\"].includes(tagName)) {\n const input = target as HTMLInputElement\n\n // Store initial value for change detection\n this.inputValues.set(target, input.value || \"\")\n\n this.track(\"input_focus\", {\n element: getElementSelector(input),\n input_type: input.type || tagName,\n input_name: input.name || undefined,\n input_id: input.id || undefined\n })\n }\n }, 1000)\n\n // Track input change (on blur, only if value changed)\n const handleBlur = (event: FocusEvent) => {\n const target = event.target as HTMLElement\n if (!target) return\n\n const tagName = target.tagName.toLowerCase()\n if ([\"input\", \"textarea\", \"select\"].includes(tagName)) {\n const input = target as HTMLInputElement\n const previousValue = this.inputValues.get(target)\n const currentValue = input.value || \"\"\n\n // Only track if value actually changed\n if (previousValue !== undefined && previousValue !== currentValue) {\n this.track(\"input_change\", {\n element: getElementSelector(input),\n input_type: input.type || tagName,\n input_name: input.name || undefined,\n input_id: input.id || undefined,\n had_value: previousValue.length > 0,\n has_value: currentValue.length > 0\n })\n }\n\n this.inputValues.delete(target)\n }\n }\n\n document.addEventListener(\"focus\", handleFocus, { capture: true })\n document.addEventListener(\"blur\", handleBlur, { capture: true })\n\n this.unsubscribers.push(() => {\n document.removeEventListener(\"focus\", handleFocus, { capture: true })\n document.removeEventListener(\"blur\", handleBlur, { capture: true })\n this.inputValues.clear()\n })\n }\n\n /**\n * Setup clipboard tracking (copy, cut, paste)\n */\n private setupClipboardTracking(): void {\n const handleCopy = (_event: ClipboardEvent) => {\n const selection = window.getSelection()\n const selectedText = selection?.toString() || \"\"\n\n this.track(\"copy\", {\n text_length: selectedText.length,\n has_selection: selectedText.length > 0\n })\n }\n\n const handleCut = (_event: ClipboardEvent) => {\n const selection = window.getSelection()\n const selectedText = selection?.toString() || \"\"\n\n this.track(\"cut\", {\n text_length: selectedText.length,\n has_selection: selectedText.length > 0\n })\n }\n\n const handlePaste = (event: ClipboardEvent) => {\n const pastedText = event.clipboardData?.getData(\"text\") || \"\"\n const target = event.target as HTMLElement\n\n this.track(\"paste\", {\n text_length: pastedText.length,\n target_element: target ? getElementSelector(target) : undefined\n })\n }\n\n document.addEventListener(\"copy\", handleCopy)\n document.addEventListener(\"cut\", handleCut)\n document.addEventListener(\"paste\", handlePaste)\n\n this.unsubscribers.push(() => {\n document.removeEventListener(\"copy\", handleCopy)\n document.removeEventListener(\"cut\", handleCut)\n document.removeEventListener(\"paste\", handlePaste)\n })\n }\n\n /**\n * Setup text selection tracking\n */\n private setupSelectionTracking(): void {\n let selectionTimeout: any\n\n const handleSelectionChange = () => {\n // Debounce selection events\n clearTimeout(selectionTimeout)\n selectionTimeout = setTimeout(() => {\n const selection = window.getSelection()\n const selectedText = selection?.toString() || \"\"\n\n if (selectedText.length > 0) {\n this.track(\"text_select\", {\n text_length: selectedText.length\n })\n }\n }, 500)\n }\n\n document.addEventListener(\"selectionchange\", handleSelectionChange)\n\n this.unsubscribers.push(() => {\n document.removeEventListener(\"selectionchange\", handleSelectionChange)\n clearTimeout(selectionTimeout)\n })\n }\n\n /**\n * Setup error tracking\n */\n private setupErrorTracking(): void {\n // Track JavaScript errors\n const handleError = (event: ErrorEvent) => {\n this.track(\"js_error\", {\n message: event.message,\n filename: event.filename,\n lineno: event.lineno,\n colno: event.colno,\n stack: event.error?.stack\n })\n }\n\n window.addEventListener(\"error\", handleError)\n\n this.unsubscribers.push(() => {\n window.removeEventListener(\"error\", handleError)\n })\n\n // Track unhandled promise rejections\n const handleRejection = (event: PromiseRejectionEvent) => {\n this.track(\"unhandled_rejection\", {\n reason: String(event.reason),\n promise: String(event.promise)\n })\n }\n\n window.addEventListener(\"unhandledrejection\", handleRejection)\n\n this.unsubscribers.push(() => {\n window.removeEventListener(\"unhandledrejection\", handleRejection)\n })\n }\n}\n","import { BaseTracker } from \"./base-tracker\"\nimport type { Config } from \"../core/config\"\nimport type { TrackCallback } from \"./base-tracker\"\nimport { throttle } from \"../utils/helpers\"\nimport { subscribeToTelegramEvent } from \"../utils/telegram\"\n\n/**\n * Deep tracker (Level 3)\n * Tracks: scroll_depth, element_visible, rage_click, long_task, web_vitals,\n * network_status, orientation_change, media events, Telegram events\n */\nexport class DeepTracker extends BaseTracker {\n private unsubscribers: (() => void)[] = []\n private observers: Array<IntersectionObserver | PerformanceObserver | MutationObserver> = []\n private clickTracker = new Map<Element, { count: number; timer: any }>()\n private maxScrollDepth = 0\n private trackedMedia = new WeakSet<HTMLMediaElement>()\n\n constructor(config: Config, trackCallback: TrackCallback) {\n super(config, trackCallback, 3)\n }\n\n protected setup(): void {\n if (typeof window === \"undefined\") {\n return\n }\n\n this.setupScrollTracking()\n this.setupVisibilityTracking()\n this.setupRageClickTracking()\n this.setupLongTaskTracking()\n this.setupWebVitals()\n this.setupNetworkTracking()\n this.setupOrientationTracking()\n this.setupMediaTracking()\n this.setupTelegramTracking()\n }\n\n protected teardown(): void {\n this.unsubscribers.forEach(unsubscribe => unsubscribe())\n this.unsubscribers = []\n\n this.observers.forEach(observer => observer.disconnect())\n this.observers = []\n\n this.clickTracker.clear()\n }\n\n /**\n * Calculate scroll depth percentage\n */\n private getScrollDepth(): number {\n const windowHeight = window.innerHeight\n const documentHeight = document.documentElement.scrollHeight\n const scrollTop = window.pageYOffset || document.documentElement.scrollTop\n\n if (documentHeight <= windowHeight) {\n return 100\n }\n\n const maxScroll = documentHeight - windowHeight\n const scrollPercentage = (scrollTop / maxScroll) * 100\n\n return Math.min(Math.round(scrollPercentage), 100)\n }\n\n /**\n * Setup scroll depth tracking\n */\n private setupScrollTracking(): void {\n const handleScroll = throttle(() => {\n const depth = this.getScrollDepth()\n\n // Track milestones: 25%, 50%, 75%, 100%\n if (depth > this.maxScrollDepth) {\n this.maxScrollDepth = depth\n\n const milestones = [25, 50, 75, 100]\n const milestone = milestones.find(m => depth >= m && this.maxScrollDepth - depth < m)\n\n if (milestone) {\n this.track(\"scroll_depth\", {\n depth: milestone,\n max_depth: this.maxScrollDepth\n })\n }\n }\n }, 500)\n\n window.addEventListener(\"scroll\", handleScroll, { passive: true })\n\n this.unsubscribers.push(() => {\n window.removeEventListener(\"scroll\", handleScroll)\n })\n }\n\n /**\n * Setup element visibility tracking\n */\n private setupVisibilityTracking(): void {\n if (!(\"IntersectionObserver\" in window)) {\n return\n }\n\n const observer = new IntersectionObserver(\n entries => {\n entries.forEach(entry => {\n if (entry.isIntersecting) {\n const element = entry.target\n const selector = element.getAttribute(\"data-track-visible\")\n\n if (selector) {\n this.track(\"element_visible\", {\n element: selector,\n intersection_ratio: entry.intersectionRatio\n })\n\n // Stop observing after first visibility\n observer.unobserve(element)\n }\n }\n })\n },\n { threshold: 0.5 }\n )\n\n // Observe elements with data-track-visible attribute\n document.querySelectorAll(\"[data-track-visible]\").forEach(element => {\n observer.observe(element)\n })\n\n this.observers.push(observer)\n\n // Also observe dynamically added elements (with MutationObserver)\n const mutationObserver = new MutationObserver(mutations => {\n mutations.forEach(mutation => {\n mutation.addedNodes.forEach(node => {\n if (node instanceof Element) {\n if (node.hasAttribute(\"data-track-visible\")) {\n observer.observe(node)\n }\n node.querySelectorAll(\"[data-track-visible]\").forEach(el => {\n observer.observe(el)\n })\n }\n })\n })\n })\n\n mutationObserver.observe(document.body, {\n childList: true,\n subtree: true\n })\n\n this.unsubscribers.push(() => {\n mutationObserver.disconnect()\n })\n }\n\n /**\n * Setup rage click tracking\n */\n private setupRageClickTracking(): void {\n const RAGE_THRESHOLD = 5 // 5 clicks\n const RAGE_TIMEOUT = 2000 // within 2 seconds\n\n const handleClick = (event: MouseEvent) => {\n const target = event.target as Element\n if (!target) return\n\n const tracker = this.clickTracker.get(target)\n\n if (tracker) {\n tracker.count++\n clearTimeout(tracker.timer)\n\n if (tracker.count >= RAGE_THRESHOLD) {\n this.track(\"rage_click\", {\n element: target.tagName.toLowerCase(),\n click_count: tracker.count\n })\n\n this.clickTracker.delete(target)\n } else {\n tracker.timer = setTimeout(() => {\n this.clickTracker.delete(target)\n }, RAGE_TIMEOUT)\n }\n } else {\n const timer = setTimeout(() => {\n this.clickTracker.delete(target)\n }, RAGE_TIMEOUT)\n\n this.clickTracker.set(target, { count: 1, timer })\n }\n }\n\n document.addEventListener(\"click\", handleClick)\n\n this.unsubscribers.push(() => {\n document.removeEventListener(\"click\", handleClick)\n })\n }\n\n /**\n * Setup long task tracking\n */\n private setupLongTaskTracking(): void {\n if (!(\"PerformanceObserver\" in window)) {\n return\n }\n\n try {\n const observer = new PerformanceObserver(list => {\n for (const entry of list.getEntries()) {\n if (entry.duration > 50) {\n // Tasks longer than 50ms\n this.track(\"long_task\", {\n duration: Math.round(entry.duration),\n start_time: Math.round(entry.startTime)\n })\n }\n }\n })\n\n observer.observe({ entryTypes: [\"longtask\"] })\n this.observers.push(observer)\n } catch (error) {\n // longtask might not be supported\n this.log(\"Long task tracking not supported\")\n }\n }\n\n /**\n * Setup Web Vitals tracking\n */\n private setupWebVitals(): void {\n if (!(\"PerformanceObserver\" in window)) {\n return\n }\n\n // Track Largest Contentful Paint (LCP)\n try {\n const lcpObserver = new PerformanceObserver(list => {\n const entries = list.getEntries()\n const lastEntry = entries[entries.length - 1] as any\n\n this.track(\"web_vital_lcp\", {\n value: Math.round(lastEntry.renderTime || lastEntry.loadTime),\n element: lastEntry.element?.tagName.toLowerCase()\n })\n })\n\n lcpObserver.observe({ entryTypes: [\"largest-contentful-paint\"] })\n this.observers.push(lcpObserver)\n } catch (error) {\n this.log(\"LCP tracking not supported\")\n }\n\n // Track First Input Delay (FID)\n try {\n const fidObserver = new PerformanceObserver(list => {\n const entries = list.getEntries()\n entries.forEach((entry: any) => {\n this.track(\"web_vital_fid\", {\n value: Math.round(entry.processingStart - entry.startTime),\n event_type: entry.name\n })\n })\n })\n\n fidObserver.observe({ entryTypes: [\"first-input\"] })\n this.observers.push(fidObserver)\n } catch (error) {\n this.log(\"FID tracking not supported\")\n }\n\n // Track Cumulative Layout Shift (CLS)\n let clsValue = 0\n\n try {\n const clsObserver = new PerformanceObserver(list => {\n const entries = list.getEntries()\n entries.forEach((entry: any) => {\n if (!entry.hadRecentInput) {\n clsValue += entry.value\n }\n })\n })\n\n clsObserver.observe({ entryTypes: [\"layout-shift\"] })\n this.observers.push(clsObserver)\n\n // Report CLS on page hide\n const reportCLS = () => {\n if (clsValue > 0) {\n this.track(\"web_vital_cls\", {\n value: Math.round(clsValue * 1000) / 1000\n })\n }\n }\n\n window.addEventListener(\"visibilitychange\", () => {\n if (document.visibilityState === \"hidden\") {\n reportCLS()\n }\n })\n\n this.unsubscribers.push(() => {\n reportCLS()\n })\n } catch (error) {\n this.log(\"CLS tracking not supported\")\n }\n }\n\n /**\n * Setup network status tracking (online/offline)\n */\n private setupNetworkTracking(): void {\n const handleOnline = () => {\n this.track(\"network_status\", {\n status: \"online\",\n effective_type: (navigator as any).connection?.effectiveType,\n downlink: (navigator as any).connection?.downlink,\n rtt: (navigator as any).connection?.rtt\n })\n }\n\n const handleOffline = () => {\n this.track(\"network_status\", {\n status: \"offline\"\n })\n }\n\n window.addEventListener(\"online\", handleOnline)\n window.addEventListener(\"offline\", handleOffline)\n\n this.unsubscribers.push(() => {\n window.removeEventListener(\"online\", handleOnline)\n window.removeEventListener(\"offline\", handleOffline)\n })\n\n // Track network changes if supported\n const connection = (navigator as any).connection\n if (connection) {\n const handleConnectionChange = () => {\n this.track(\"network_change\", {\n effective_type: connection.effectiveType,\n downlink: connection.downlink,\n rtt: connection.rtt,\n save_data: connection.saveData\n })\n }\n\n connection.addEventListener(\"change\", handleConnectionChange)\n\n this.unsubscribers.push(() => {\n connection.removeEventListener(\"change\", handleConnectionChange)\n })\n }\n }\n\n /**\n * Setup device orientation change tracking\n */\n private setupOrientationTracking(): void {\n const handleOrientationChange = () => {\n const orientation =\n screen.orientation?.type || (window.innerWidth > window.innerHeight ? \"landscape\" : \"portrait\")\n\n this.track(\"orientation_change\", {\n orientation: orientation,\n angle: screen.orientation?.angle,\n width: window.innerWidth,\n height: window.innerHeight\n })\n }\n\n // Use screen.orientation API if available, fallback to resize\n if (screen.orientation) {\n screen.orientation.addEventListener(\"change\", handleOrientationChange)\n this.unsubscribers.push(() => {\n screen.orientation.removeEventListener(\"change\", handleOrientationChange)\n })\n } else {\n // Fallback for older browsers\n window.addEventListener(\"orientationchange\", handleOrientationChange)\n this.unsubscribers.push(() => {\n window.removeEventListener(\"orientationchange\", handleOrientationChange)\n })\n }\n }\n\n /**\n * Setup media (video/audio) event tracking\n */\n private setupMediaTracking(): void {\n const trackMediaEvent = (event: Event) => {\n const media = event.target as HTMLMediaElement\n if (!media || this.trackedMedia.has(media)) return\n\n const mediaType = media.tagName.toLowerCase() // \"video\" or \"audio\"\n const eventType = event.type\n\n const baseProps = {\n media_type: mediaType,\n src: media.currentSrc || media.src,\n duration: isFinite(media.duration) ? Math.round(media.duration) : undefined,\n current_time: Math.round(media.currentTime),\n muted: media.muted,\n volume: Math.round(media.volume * 100)\n }\n\n if (eventType === \"play\") {\n this.track(\"media_play\", baseProps)\n } else if (eventType === \"pause\") {\n this.track(\"media_pause\", {\n ...baseProps,\n percent_played: media.duration ? Math.round((media.currentTime / media.duration) * 100) : 0\n })\n } else if (eventType === \"ended\") {\n this.track(\"media_ended\", {\n ...baseProps,\n completed: true\n })\n } else if (eventType === \"error\") {\n this.track(\"media_error\", {\n media_type: mediaType,\n src: media.currentSrc || media.src,\n error: media.error?.message || \"unknown\"\n })\n }\n }\n\n // Track events on existing media elements\n const setupMediaElement = (media: HTMLMediaElement) => {\n if (this.trackedMedia.has(media)) return\n this.trackedMedia.add(media)\n\n media.addEventListener(\"play\", trackMediaEvent)\n media.addEventListener(\"pause\", trackMediaEvent)\n media.addEventListener(\"ended\", trackMediaEvent)\n media.addEventListener(\"error\", trackMediaEvent)\n }\n\n // Setup existing media elements\n document.querySelectorAll(\"video, audio\").forEach(media => {\n setupMediaElement(media as HTMLMediaElement)\n })\n\n // Watch for dynamically added media elements\n const observer = new MutationObserver(mutations => {\n mutations.forEach(mutation => {\n mutation.addedNodes.forEach(node => {\n if (node instanceof HTMLMediaElement) {\n setupMediaElement(node)\n }\n if (node instanceof Element) {\n node.querySelectorAll(\"video, audio\").forEach(media => {\n setupMediaElement(media as HTMLMediaElement)\n })\n }\n })\n })\n })\n\n observer.observe(document.body, {\n childList: true,\n subtree: true\n })\n\n this.observers.push(observer)\n }\n\n /**\n * Setup Telegram WebApp event tracking\n * Tracks ALL available Telegram WebApp events\n */\n private setupTelegramTracking(): void {\n const webApp = (window as any).Telegram?.WebApp\n\n // Helper to track event with data\n const trackEvent = (eventName: string, data?: any) => {\n this.track(`telegram_${eventName}`, data || {})\n }\n\n // Theme and appearance events\n // Official event: themeChanged\n // No payload; read values from WebApp.colorScheme and WebApp.themeParams\n const unsubTheme = subscribeToTelegramEvent(\"themeChanged\", () => {\n trackEvent(\"theme_changed\", {\n color_scheme: webApp?.colorScheme,\n theme_params: webApp?.themeParams\n })\n })\n this.unsubscribers.push(unsubTheme)\n\n // Viewport events\n // Official event: viewportChanged\n // Payload: {isStateStable: boolean}\n const unsubViewport = subscribeToTelegramEvent(\"viewportChanged\", (eventData: any) => {\n trackEvent(\"viewport_changed\", {\n is_state_stable: eventData?.isStateStable,\n is_expanded: webApp?.isExpanded,\n viewport_height: webApp?.viewportHeight,\n viewport_stable_height: webApp?.viewportStableHeight\n })\n })\n this.unsubscribers.push(unsubViewport)\n\n // Safe area events (Bot API 7.10+)\n // Official event: safeAreaChanged\n // No payload; read values from WebApp.safeAreaInset\n const unsubSafeArea = subscribeToTelegramEvent(\"safeAreaChanged\", () => {\n trackEvent(\"safe_area_changed\", {\n safe_area: webApp?.safeAreaInset\n })\n })\n this.unsubscribers.push(unsubSafeArea)\n\n // Official event: contentSafeAreaChanged (Bot API 7.10+)\n // No payload; read values from WebApp.contentSafeAreaInset\n const unsubContentSafeArea = subscribeToTelegramEvent(\"contentSafeAreaChanged\", () => {\n trackEvent(\"content_safe_area_changed\", {\n content_safe_area: webApp?.contentSafeAreaInset\n })\n })\n this.unsubscribers.push(unsubContentSafeArea)\n\n // Visibility events\n // Note: activated/deactivated events (Bot API 8.0+) track app visibility state\n // The isVisible property on WebApp can be read directly but there's no separate visibilityChanged event\n\n // Button events\n // Official event: backButtonClicked (Bot API 6.1+)\n // No payload\n const unsubBackButton = subscribeToTelegramEvent(\"backButtonClicked\", () => {\n trackEvent(\"back_button_clicked\", {})\n })\n this.unsubscribers.push(unsubBackButton)\n\n // Official event: mainButtonClicked\n // No payload; read button text from WebApp.MainButton.text\n const unsubMainButton = subscribeToTelegramEvent(\"mainButtonClicked\", () => {\n trackEvent(\"main_button_clicked\", {\n button_text: webApp?.MainButton?.text\n })\n })\n this.unsubscribers.push(unsubMainButton)\n\n // Invoice events\n // Note: invoiceClosed is the official event (Bot API 6.1+)\n // Official payload: {url: string, status: 'paid' | 'cancelled' | 'failed' | 'pending'}\n const unsubInvoice = subscribeToTelegramEvent(\"invoiceClosed\", (eventData: any) => {\n trackEvent(\"invoice_closed\", {\n url: eventData?.url,\n status: eventData?.status\n })\n })\n this.unsubscribers.push(unsubInvoice)\n\n // Popup events (Bot API 6.2+)\n // Official event: popupClosed\n // Payload: {button_id: string | null}\n const unsubPopup = subscribeToTelegramEvent(\"popupClosed\", (eventData: any) => {\n trackEvent(\"popup_closed\", {\n button_id: eventData?.button_id\n })\n })\n this.unsubscribers.push(unsubPopup)\n\n // QR code events (Bot API 6.4+)\n // Official event: qrTextReceived\n // Payload: {data: string}\n const unsubQrText = subscribeToTelegramEvent(\"qrTextReceived\", (eventData: any) => {\n trackEvent(\"qr_text_received\", {\n data: eventData?.data\n })\n })\n this.unsubscribers.push(unsubQrText)\n\n // Official event: scanQrPopupClosed (Bot API 6.4+)\n // No payload\n const unsubScanQr = subscribeToTelegramEvent(\"scanQrPopupClosed\", () => {\n trackEvent(\"scan_qr_popup_closed\", {})\n })\n this.unsubscribers.push(unsubScanQr)\n\n // Clipboard events (Bot API 6.4+)\n // Official event: clipboardTextReceived\n // Payload: {data: string | null} (null if clipboard is empty or permission denied)\n const unsubClipboard = subscribeToTelegramEvent(\"clipboardTextReceived\", (eventData: any) => {\n trackEvent(\"clipboard_text_received\", {\n data: eventData?.data\n })\n })\n this.unsubscribers.push(unsubClipboard)\n\n // Permission events\n // Official event: writeAccessRequested (Bot API 6.9+)\n // Payload: {status: 'allowed' | 'cancelled'}\n const unsubWriteAccess = subscribeToTelegramEvent(\"writeAccessRequested\", (eventData: any) => {\n trackEvent(\"write_access_requested\", {\n status: eventData?.status\n })\n })\n this.unsubscribers.push(unsubWriteAccess)\n\n // File download events (Bot API 8.0+)\n // Official event: fileDownloadRequested\n // Payload: {status: 'downloading' | 'cancelled'}\n const unsubFileDownload = subscribeToTelegramEvent(\"fileDownloadRequested\", (eventData: any) => {\n trackEvent(\"file_download_requested\", {\n status: eventData?.status\n })\n })\n this.unsubscribers.push(unsubFileDownload)\n\n // Custom method events (Bot API 6.9+)\n // Official event: customMethodInvoked\n // Payload: {req_id: string, result?: any, error?: string}\n const unsubCustomMethod = subscribeToTelegramEvent(\"customMethodInvoked\", (eventData: any) => {\n trackEvent(\"custom_method_invoked\", {\n req_id: eventData?.req_id,\n result: eventData?.result,\n error: eventData?.error\n })\n })\n this.unsubscribers.push(unsubCustomMethod)\n\n // Fullscreen events (Bot API 8.0+)\n // Official event: fullscreenChanged\n // Payload: {isFullscreen: boolean}\n const unsubFullscreen = subscribeToTelegramEvent(\"fullscreenChanged\", (eventData: any) => {\n trackEvent(\"fullscreen_changed\", {\n is_fullscreen: eventData?.isFullscreen\n })\n })\n this.unsubscribers.push(unsubFullscreen)\n\n // Official event: fullscreenFailed\n // Payload: {error: 'UNSUPPORTED' | 'ALREADY_FULLSCREEN'}\n const unsubFullscreenFailed = subscribeToTelegramEvent(\"fullscreenFailed\", (eventData: any) => {\n trackEvent(\"fullscreen_failed\", {\n error: eventData?.error\n })\n })\n this.unsubscribers.push(unsubFullscreenFailed)\n\n // Home screen events (Bot API 8.0+)\n // Official event: homeScreenAdded\n // No payload\n const unsubHomeScreenAdded = subscribeToTelegramEvent(\"homeScreenAdded\", () => {\n trackEvent(\"home_screen_added\", {})\n })\n this.unsubscribers.push(unsubHomeScreenAdded)\n\n // Official event: homeScreenChecked\n // Payload: {status: 'unsupported' | 'unknown' | 'added' | 'missed'}\n const unsubHomeScreenChecked = subscribeToTelegramEvent(\"homeScreenChecked\", (eventData: any) => {\n trackEvent(\"home_screen_checked\", {\n status: eventData?.status\n })\n })\n this.unsubscribers.push(unsubHomeScreenChecked)\n\n // Prepared message events (Bot API 8.0+)\n // Official event: preparedMessageSent\n // No payload (message was sent successfully)\n const unsubPreparedMessageSent = subscribeToTelegramEvent(\"preparedMessageSent\", () => {\n trackEvent(\"prepared_message_sent\", {})\n })\n this.unsubscribers.push(unsubPreparedMessageSent)\n\n // Official event: preparedMessageFailed\n // Payload: {error: 'UNSUPPORTED' | 'MESSAGE_EXPIRED' | 'MESSAGE_SEND_FAILED' | 'USER_DECLINED' | 'UNKNOWN_ERROR'}\n const unsubPreparedMessageFailed = subscribeToTelegramEvent(\"preparedMessageFailed\", (eventData: any) => {\n trackEvent(\"prepared_message_failed\", {\n error: eventData?.error\n })\n })\n this.unsubscribers.push(unsubPreparedMessageFailed)\n\n // Emoji status events (Bot API 8.0+)\n // Official event: emojiStatusSet\n // No payload (status was set successfully)\n const unsubEmojiStatusSet = subscribeToTelegramEvent(\"emojiStatusSet\", () => {\n trackEvent(\"emoji_status_set\", {})\n })\n this.unsubscribers.push(unsubEmojiStatusSet)\n\n // Official event: emojiStatusFailed\n // Payload: {error: 'UNSUPPORTED' | 'SUGGESTED_EMOJI_INVALID' | 'DURATION_INVALID' | 'USER_DECLINED' | 'SERVER_ERROR' | 'UNKNOWN_ERROR'}\n const unsubEmojiStatusFailed = subscribeToTelegramEvent(\"emojiStatusFailed\", (eventData: any) => {\n trackEvent(\"emoji_status_failed\", {\n error: eventData?.error\n })\n })\n this.unsubscribers.push(unsubEmojiStatusFailed)\n\n // Official event: emojiStatusAccessRequested\n // Payload: {status: 'allowed' | 'cancelled'}\n const unsubEmojiStatusAccess = subscribeToTelegramEvent(\"emojiStatusAccessRequested\", (eventData: any) => {\n trackEvent(\"emoji_status_access_requested\", {\n status: eventData?.status\n })\n })\n this.unsubscribers.push(unsubEmojiStatusAccess)\n\n // Settings button events (Bot API 6.1+)\n // Official event: settingsButtonClicked\n // No payload\n const unsubSettingsButton = subscribeToTelegramEvent(\"settingsButtonClicked\", () => {\n trackEvent(\"settings_button_clicked\", {})\n })\n this.unsubscribers.push(unsubSettingsButton)\n\n // Secondary button events (Bot API 7.10+)\n // Official event: secondaryButtonClicked\n // No payload\n const unsubSecondaryButton = subscribeToTelegramEvent(\"secondaryButtonClicked\", () => {\n trackEvent(\"secondary_button_clicked\", {})\n })\n this.unsubscribers.push(unsubSecondaryButton)\n\n // Share message events (Bot API 8.0+)\n // Official event: shareMessageSent\n // No payload (message was shared successfully)\n const unsubShareMessageSent = subscribeToTelegramEvent(\"shareMessageSent\", () => {\n trackEvent(\"share_message_sent\", {})\n })\n this.unsubscribers.push(unsubShareMessageSent)\n\n // Official event: shareMessageFailed\n // Payload: {error: 'UNSUPPORTED' | 'MESSAGE_EXPIRED' | 'MESSAGE_SEND_FAILED' | 'USER_DECLINED' | 'UNKNOWN_ERROR'}\n const unsubShareMessageFailed = subscribeToTelegramEvent(\"shareMessageFailed\", (eventData: any) => {\n trackEvent(\"share_message_failed\", {\n error: eventData?.error\n })\n })\n this.unsubscribers.push(unsubShareMessageFailed)\n\n // Location events (Bot API 8.0+)\n // Official event: locationManagerUpdated\n // Fires when LocationManager object is updated\n const unsubLocationManager = subscribeToTelegramEvent(\"locationManagerUpdated\", () => {\n const locationManager = webApp?.LocationManager\n trackEvent(\"location_manager_updated\", {\n is_inited: locationManager?.isInited,\n is_location_available: locationManager?.isLocationAvailable,\n is_access_requested: locationManager?.isAccessRequested,\n is_access_granted: locationManager?.isAccessGranted\n })\n })\n this.unsubscribers.push(unsubLocationManager)\n\n // Official event: locationRequested (Bot API 8.0+)\n // Payload: {locationData?: LocationData} where LocationData has latitude, longitude, etc.\n const unsubLocationRequested = subscribeToTelegramEvent(\"locationRequested\", (eventData: any) => {\n trackEvent(\"location_requested\", {\n available: eventData?.available !== false,\n latitude: eventData?.latitude,\n longitude: eventData?.longitude,\n altitude: eventData?.altitude,\n course: eventData?.course,\n speed: eventData?.speed,\n horizontal_accuracy: eventData?.horizontal_accuracy,\n vertical_accuracy: eventData?.vertical_accuracy,\n course_accuracy: eventData?.course_accuracy,\n speed_accuracy: eventData?.speed_accuracy\n })\n })\n this.unsubscribers.push(unsubLocationRequested)\n\n // Accelerometer events (Bot API 8.0+)\n // Official events: accelerometerStarted, accelerometerStopped, accelerometerChanged, accelerometerFailed\n const unsubAccelerometerStarted = subscribeToTelegramEvent(\"accelerometerStarted\", () => {\n trackEvent(\"accelerometer_started\", {})\n })\n this.unsubscribers.push(unsubAccelerometerStarted)\n\n const unsubAccelerometerStopped = subscribeToTelegramEvent(\"accelerometerStopped\", () => {\n trackEvent(\"accelerometer_stopped\", {})\n })\n this.unsubscribers.push(unsubAccelerometerStopped)\n\n // accelerometerChanged fires with no payload; read values from Accelerometer object\n const unsubAccelerometerChanged = subscribeToTelegramEvent(\"accelerometerChanged\", () => {\n const accelerometer = webApp?.Accelerometer\n trackEvent(\"accelerometer_changed\", {\n x: accelerometer?.x,\n y: accelerometer?.y,\n z: accelerometer?.z\n })\n })\n this.unsubscribers.push(unsubAccelerometerChanged)\n\n // accelerometerFailed payload: {error: 'UNSUPPORTED'}\n const unsubAccelerometerFailed = subscribeToTelegramEvent(\"accelerometerFailed\", (eventData: any) => {\n trackEvent(\"accelerometer_failed\", {\n error: eventData?.error\n })\n })\n this.unsubscribers.push(unsubAccelerometerFailed)\n\n // Device orientation events (Bot API 8.0+)\n // Official events: deviceOrientationStarted, deviceOrientationStopped, deviceOrientationChanged, deviceOrientationFailed\n const unsubDeviceOrientationStarted = subscribeToTelegramEvent(\"deviceOrientationStarted\", () => {\n trackEvent(\"device_orientation_started\", {})\n })\n this.unsubscribers.push(unsubDeviceOrientationStarted)\n\n const unsubDeviceOrientationStopped = subscribeToTelegramEvent(\"deviceOrientationStopped\", () => {\n trackEvent(\"device_orientation_stopped\", {})\n })\n this.unsubscribers.push(unsubDeviceOrientationStopped)\n\n // deviceOrientationChanged fires with no payload; read values from DeviceOrientation object\n const unsubDeviceOrientationChanged = subscribeToTelegramEvent(\"deviceOrientationChanged\", () => {\n const deviceOrientation = webApp?.DeviceOrientation\n trackEvent(\"device_orientation_changed\", {\n absolute: deviceOrientation?.absolute,\n alpha: deviceOrientation?.alpha,\n beta: deviceOrientation?.beta,\n gamma: deviceOrientation?.gamma\n })\n })\n this.unsubscribers.push(unsubDeviceOrientationChanged)\n\n // deviceOrientationFailed payload: {error: 'UNSUPPORTED'}\n const unsubDeviceOrientationFailed = subscribeToTelegramEvent(\"deviceOrientationFailed\", (eventData: any) => {\n trackEvent(\"device_orientation_failed\", {\n error: eventData?.error\n })\n })\n this.unsubscribers.push(unsubDeviceOrientationFailed)\n\n // Gyroscope events (Bot API 8.0+)\n // Official events: gyroscopeStarted, gyroscopeStopped, gyroscopeChanged, gyroscopeFailed\n const unsubGyroscopeStarted = subscribeToTelegramEvent(\"gyroscopeStarted\", () => {\n trackEvent(\"gyroscope_started\", {})\n })\n this.unsubscribers.push(unsubGyroscopeStarted)\n\n const unsubGyroscopeStopped = subscribeToTelegramEvent(\"gyroscopeStopped\", () => {\n trackEvent(\"gyroscope_stopped\", {})\n })\n this.unsubscribers.push(unsubGyroscopeStopped)\n\n // gyroscopeChanged fires with no payload; read values from Gyroscope object\n const unsubGyroscopeChanged = subscribeToTelegramEvent(\"gyroscopeChanged\", () => {\n const gyroscope = webApp?.Gyroscope\n trackEvent(\"gyroscope_changed\", {\n x: gyroscope?.x,\n y: gyroscope?.y,\n z: gyroscope?.z\n })\n })\n this.unsubscribers.push(unsubGyroscopeChanged)\n\n // gyroscopeFailed payload: {error: 'UNSUPPORTED'}\n const unsubGyroscopeFailed = subscribeToTelegramEvent(\"gyroscopeFailed\", (eventData: any) => {\n trackEvent(\"gyroscope_failed\", {\n error: eventData?.error\n })\n })\n this.unsubscribers.push(unsubGyroscopeFailed)\n\n // Contact events (Bot API 6.9+)\n // Official event: contactRequested\n // Payload: {status: 'sent' | 'cancelled'}\n const unsubContactRequested = subscribeToTelegramEvent(\"contactRequested\", (eventData: any) => {\n trackEvent(\"contact_requested\", {\n status: eventData?.status\n })\n })\n this.unsubscribers.push(unsubContactRequested)\n\n // App state events (Bot API 8.0+)\n // Official event: activated\n // Fires when Mini App becomes active (user switches to it)\n // No payload\n const unsubActivated = subscribeToTelegramEvent(\"activated\", () => {\n trackEvent(\"activated\", {})\n })\n this.unsubscribers.push(unsubActivated)\n\n // Official event: deactivated (Bot API 8.0+)\n // Fires when Mini App becomes inactive (user switches away)\n // No payload\n const unsubDeactivated = subscribeToTelegramEvent(\"deactivated\", () => {\n trackEvent(\"deactivated\", {})\n })\n this.unsubscribers.push(unsubDeactivated)\n\n // Biometric events (Bot API 7.2+)\n // Official event: biometricManagerUpdated\n // Fires when BiometricManager object is updated\n const unsubBiometricManager = subscribeToTelegramEvent(\"biometricManagerUpdated\", () => {\n const biometricManager = webApp?.BiometricManager\n trackEvent(\"biometric_manager_updated\", {\n is_inited: biometricManager?.isInited,\n is_biometric_available: biometricManager?.isBiometricAvailable,\n biometric_type: biometricManager?.biometricType,\n is_access_requested: biometricManager?.isAccessRequested,\n is_access_granted: biometricManager?.isAccessGranted,\n is_biometric_token_saved: biometricManager?.isBiometricTokenSaved,\n device_id: biometricManager?.deviceId\n })\n })\n this.unsubscribers.push(unsubBiometricManager)\n\n // Official event: biometricAuthRequested (Bot API 7.2+)\n // Payload: {isAuthenticated: boolean, biometricToken?: string}\n const unsubBiometricAuth = subscribeToTelegramEvent(\"biometricAuthRequested\", (eventData: any) => {\n trackEvent(\"biometric_auth_requested\", {\n is_authenticated: eventData?.isAuthenticated,\n biometric_token: eventData?.biometricToken\n })\n })\n this.unsubscribers.push(unsubBiometricAuth)\n\n // Official event: biometricTokenUpdated (Bot API 7.2+)\n // Payload: {isUpdated: boolean}\n const unsubBiometricToken = subscribeToTelegramEvent(\"biometricTokenUpdated\", (eventData: any) => {\n trackEvent(\"biometric_token_updated\", {\n is_updated: eventData?.isUpdated\n })\n })\n this.unsubscribers.push(unsubBiometricToken)\n\n // Note: Cloud storage operations (CloudStorage.setItem, getItem, etc.) use callbacks,\n // not WebApp.onEvent() events. Storage tracking is done via method patching if needed.\n\n // Patch webApp methods to track their calls\n this.patchWebAppMethods(webApp, trackEvent)\n }\n\n /**\n * Patch Telegram WebApp methods to track their calls\n * Prevents double-patching by checking if method is already patched\n */\n private patchWebAppMethods(webApp: any, trackEvent: (eventName: string, data?: any) => void): void {\n if (!webApp) return\n\n // Check if already patched (prevent double-patching)\n if ((webApp.openLink as any)?._dashgramPatched) {\n return\n }\n\n // Track openLink calls\n if (webApp.openLink && typeof webApp.openLink === \"function\") {\n const originalOpenLink = webApp.openLink.bind(webApp)\n const patchedOpenLink = (url: string, options?: any) => {\n trackEvent(\"open_link\", {\n url: url,\n options: options\n })\n return originalOpenLink(url, options)\n }\n patchedOpenLink._dashgramPatched = true\n webApp.openLink = patchedOpenLink\n }\n\n // Track openTelegramLink calls\n if (webApp.openTelegramLink && typeof webApp.openTelegramLink === \"function\") {\n const originalOpenTelegramLink = webApp.openTelegramLink.bind(webApp)\n const patchedOpenTelegramLink = (url: string) => {\n trackEvent(\"open_telegram_link\", {\n url: url\n })\n return originalOpenTelegramLink(url)\n }\n patchedOpenTelegramLink._dashgramPatched = true\n webApp.openTelegramLink = patchedOpenTelegramLink\n }\n\n // Track switchInlineQuery calls\n if (webApp.switchInlineQuery && typeof webApp.switchInlineQuery === \"function\") {\n const originalSwitchInlineQuery = webApp.switchInlineQuery.bind(webApp)\n const patchedSwitchInlineQuery = (query: string, chooseChatTypes?: string[]) => {\n trackEvent(\"switch_inline_query\", {\n query: query,\n choose_chat_types: chooseChatTypes\n })\n return originalSwitchInlineQuery(query, chooseChatTypes)\n }\n patchedSwitchInlineQuery._dashgramPatched = true\n webApp.switchInlineQuery = patchedSwitchInlineQuery\n }\n\n // Track shareStory calls\n if (webApp.shareToStory && typeof webApp.shareToStory === \"function\") {\n const originalShareToStory = webApp.shareToStory.bind(webApp)\n const patchedShareToStory = (mediaUrl: string, params?: any) => {\n trackEvent(\"share_story\", {\n media_url: mediaUrl,\n params: params\n })\n return originalShareToStory(mediaUrl, params)\n }\n patchedShareToStory._dashgramPatched = true\n webApp.shareToStory = patchedShareToStory\n }\n\n // Track close calls\n if (webApp.close && typeof webApp.close === \"function\") {\n const originalClose = webApp.close.bind(webApp)\n const patchedClose = (options?: any) => {\n trackEvent(\"webapp_close\", {\n return_back: options?.return_back\n })\n return originalClose(options)\n }\n patchedClose._dashgramPatched = true\n webApp.close = patchedClose\n }\n\n // Track exitFullscreen calls\n if (webApp.exitFullscreen && typeof webApp.exitFullscreen === \"function\") {\n const originalExitFullscreen = webApp.exitFullscreen.bind(webApp)\n const patchedExitFullscreen = () => {\n trackEvent(\"webapp_exit_fullscreen\", {})\n return originalExitFullscreen()\n }\n patchedExitFullscreen._dashgramPatched = true\n webApp.exitFullscreen = patchedExitFullscreen\n }\n\n // Track openInvoice calls (triggers invoice_opened event)\n if (webApp.openInvoice && typeof webApp.openInvoice === \"function\") {\n const originalOpenInvoice = webApp.openInvoice.bind(webApp)\n const patchedOpenInvoice = (slug: string, callback?: (status: string) => void) => {\n trackEvent(\"open_invoice\", {\n slug: slug\n })\n return originalOpenInvoice(slug, callback)\n }\n patchedOpenInvoice._dashgramPatched = true\n webApp.openInvoice = patchedOpenInvoice\n }\n\n // Track requestAccess calls (triggers write_access_requested event)\n if (webApp.requestAccess && typeof webApp.requestAccess === \"function\") {\n const originalRequestAccess = webApp.requestAccess.bind(webApp)\n const patchedRequestAccess = (accessType: string, callback?: (status: string) => void) => {\n trackEvent(\"request_access\", {\n access_type: accessType\n })\n return originalRequestAccess(accessType, callback)\n }\n patchedRequestAccess._dashgramPatched = true\n webApp.requestAccess = patchedRequestAccess\n }\n\n // Track requestContact calls (triggers contact_requested event)\n if (webApp.requestContact && typeof webApp.requestContact === \"function\") {\n const originalRequestContact = webApp.requestContact.bind(webApp)\n const patchedRequestContact = (callback?: (status: string) => void) => {\n trackEvent(\"request_contact\", {})\n return originalRequestContact(callback)\n }\n patchedRequestContact._dashgramPatched = true\n webApp.requestContact = patchedRequestContact\n }\n\n // Track requestPhone calls (triggers phone_requested event)\n if (webApp.requestPhone && typeof webApp.requestPhone === \"function\") {\n const originalRequestPhone = webApp.requestPhone.bind(webApp)\n const patchedRequestPhone = (callback?: (status: string) => void) => {\n trackEvent(\"request_phone\", {})\n return originalRequestPhone(callback)\n }\n patchedRequestPhone._dashgramPatched = true\n webApp.requestPhone = patchedRequestPhone\n }\n\n // Track requestLocation calls (triggers location_requested event)\n if (webApp.requestLocation && typeof webApp.requestLocation === \"function\") {\n const originalRequestLocation = webApp.requestLocation.bind(webApp)\n const patchedRequestLocation = (callback?: (status: string, location?: any) => void) => {\n trackEvent(\"request_location\", {})\n return originalRequestLocation(callback)\n }\n patchedRequestLocation._dashgramPatched = true\n webApp.requestLocation = patchedRequestLocation\n }\n\n // Track checkLocation calls (triggers location_checked event)\n if (webApp.checkLocation && typeof webApp.checkLocation === \"function\") {\n const originalCheckLocation = webApp.checkLocation.bind(webApp)\n const patchedCheckLocation = (callback?: (isAvailable: boolean, location?: any) => void) => {\n trackEvent(\"check_location\", {})\n return originalCheckLocation(callback)\n }\n patchedCheckLocation._dashgramPatched = true\n webApp.checkLocation = patchedCheckLocation\n }\n }\n}\n","import type { DashgramConfig, WebAppEvent, EventProperties, TrackLevel } from \"./types\"\nimport { Config } from \"./core/config\"\nimport { Context } from \"./core/context\"\nimport { Transport } from \"./transport/transport\"\nimport { BatchProcessor } from \"./transport/batch-processor\"\nimport { CoreTracker } from \"./trackers/core-tracker\"\nimport { InteractionTracker } from \"./trackers/interaction-tracker\"\nimport { DeepTracker } from \"./trackers/deep-tracker\"\nimport { generateUUID, isBrowser } from \"./utils/helpers\"\nimport { getTelegramInitData } from \"./utils/telegram\"\n\n/**\n * Main Dashgram SDK class\n */\nclass DashgramSDK {\n private config: Config | null = null\n private context: Context | null = null\n private transport: Transport | null = null\n private batchProcessor: BatchProcessor | null = null\n private trackers: Array<CoreTracker | InteractionTracker | DeepTracker> = []\n private isInitialized = false\n\n /**\n * Initialize Dashgram SDK\n */\n init(userConfig: DashgramConfig): void {\n if (this.isInitialized) {\n if (userConfig.debug) {\n console.warn(\"Dashgram: Already initialized\")\n }\n return\n }\n\n if (!isBrowser()) {\n if (userConfig.debug) {\n console.warn(\"Dashgram: Not running in browser environment\")\n }\n return\n }\n\n try {\n // Initialize core components\n this.config = new Config(userConfig)\n\n // Set debug flag for global access\n if (typeof window !== \"undefined\") {\n ;(window as typeof window & { __DASHGRAM_DEBUG__?: boolean }).__DASHGRAM_DEBUG__ = this.config.isDebug()\n }\n\n this.context = new Context()\n this.transport = new Transport(this.config)\n this.batchProcessor = new BatchProcessor(this.config, this.transport)\n\n // Setup trackers\n this.setupTrackers()\n\n // Start batch processor\n this.batchProcessor.start()\n\n this.isInitialized = true\n\n this.log(\"Initialized successfully\", {\n projectId: this.config.get(\"projectId\"),\n trackLevel: this.config.getTrackLevel()\n })\n } catch (error) {\n console.error(\"Dashgram: Initialization failed\", error)\n throw error\n }\n }\n\n /**\n * Setup trackers based on track level\n */\n private setupTrackers(): void {\n if (!this.config) return\n\n const trackCallback = (event: string, properties: EventProperties) => {\n this.trackAuto(event, properties)\n }\n\n // Core tracker (Level 1)\n const coreTracker = new CoreTracker(this.config, trackCallback)\n this.trackers.push(coreTracker)\n coreTracker.start()\n\n // Interaction tracker (Level 2)\n const interactionTracker = new InteractionTracker(this.config, trackCallback)\n this.trackers.push(interactionTracker)\n interactionTracker.start()\n\n // Deep tracker (Level 3)\n const deepTracker = new DeepTracker(this.config, trackCallback)\n this.trackers.push(deepTracker)\n deepTracker.start()\n }\n\n /**\n * Track custom event (manual)\n */\n track(event: string, properties: EventProperties = {}): void {\n this.ensureInitialized()\n\n const fullEvent = this.buildEvent(event, properties, \"manual\")\n this.batchProcessor!.addEvent(fullEvent)\n\n this.log(\"Tracked event\", { event, properties })\n }\n\n /**\n * Track auto event (internal use by trackers)\n */\n private trackAuto(event: string, properties: EventProperties = {}): void {\n if (!this.isInitialized) return\n\n const fullEvent = this.buildEvent(event, properties, \"auto\")\n this.batchProcessor!.addEvent(fullEvent)\n\n this.log(\"Auto-tracked event\", { event, properties })\n }\n\n /**\n * Build full event object matching backend contract\n */\n private buildEvent(type: string, properties: EventProperties, source: \"auto\" | \"manual\"): WebAppEvent {\n this.ensureInitialized()\n\n return {\n eventId: generateUUID(),\n type,\n initData: getTelegramInitData(),\n properties: Object.keys(properties).length > 0 ? properties : undefined,\n telemetry: this.context!.getTelemetry(),\n source,\n level: this.config!.getTrackLevel(),\n timestamp: Date.now()\n }\n }\n\n /**\n * Set track level\n */\n setTrackLevel(level: TrackLevel): void {\n this.ensureInitialized()\n\n const oldLevel = this.config!.getTrackLevel()\n this.config!.setTrackLevel(level)\n\n // Restart trackers with new level\n this.trackers.forEach(tracker => {\n tracker.stop()\n tracker.start()\n })\n\n this.log(\"Track level changed\", { from: oldLevel, to: level })\n }\n\n /**\n * Flush all pending events\n */\n async flush(): Promise<void> {\n this.ensureInitialized()\n\n await this.batchProcessor!.flushAsync()\n\n this.log(\"Flushed all events\")\n }\n\n /**\n * Shutdown SDK\n */\n shutdown(): void {\n if (!this.isInitialized) {\n return\n }\n\n // Stop all trackers\n this.trackers.forEach(tracker => tracker.stop())\n this.trackers = []\n\n // Flush and stop batch processor\n this.batchProcessor!.flush()\n this.batchProcessor!.stop()\n\n this.isInitialized = false\n\n this.log(\"Shutdown complete\")\n }\n\n /**\n * Ensure SDK is initialized\n */\n private ensureInitialized(): void {\n if (!this.isInitialized) {\n throw new Error(\"Dashgram: SDK not initialized. Call init() first.\")\n }\n }\n\n /**\n * Log debug message\n */\n private log(...args: unknown[]): void {\n if (this.config?.isDebug()) {\n console.log(\"[Dashgram SDK]\", ...args)\n }\n }\n}\n\n// Create singleton instance\nconst DashgramMini = new DashgramSDK()\n\n// Default export\nexport default DashgramMini\n"],"names":["DashgramError","Error","constructor","message","super","this","name","ErrorWithCapture","captureStackTrace","DashgramAPIError","statusCode","details","NetworkError","originalError","DashgramConfigurationError","DEFAULT_CONFIG","trackLevel","apiUrl","batchSize","flushInterval","debug","disabled","Config","userConfig","config","validate","projectId","includes","get","key","getOnError","onError","getTrackUrl","replace","setTrackLevel","level","getTrackLevel","isDebug","isDisabled","getTelegramWebApp","window","win","Telegram","WebApp","getTelegramInitData","webApp","initData","getTelegramPlatform","platform","getTelegramTheme","colorScheme","themeParams","bg_color","bgColor","rgb","parseInt","slice","subscribeToTelegramEvent","event","callback","onEvent","wrappedCallback","_eventType","eventData","error","__DASHGRAM_DEBUG__","console","warn","offEvent","getTelemetry","user_agent","navigator","userAgent","timezone","Intl","DateTimeFormat","resolvedOptions","timeZone","undefined","theme","Context","telemetry","updateTelemetry","throttle","func","wait","timeout","previous","args","now","Date","remaining","clearTimeout","apply","setTimeout","safeStringify","obj","JSON","stringify","getElementSelector","element","id","className","classes","trim","split","join","tagName","toLowerCase","getElementText","maxLength","text","textContent","length","substring","Transport","isOnline","pendingRequests","Set","setupOnlineListener","addEventListener","log","onLine","buildPayload","events","origin","location","updates","send","request","sendRequest","add","logError","handlerError","delete","url","payload","response","fetch","method","headers","body","keepalive","ok","statusText","errorData","json","status","String","sendBeacon","blob","Blob","type","sent","flush","Promise","all","Array","from","EventQueue","maxSize","queue","enqueue","push","shift","peek","size","isEmpty","clear","BatchProcessor","transport","flushTimer","isStarted","start","scheduleFlush","setupPageUnloadHandler","stop","addEvent","interval","flushAsync","handleUnload","document","visibilityState","BaseTracker","trackCallback","isActive","setup","teardown","track","properties","CoreTracker","unsubscribers","hasTrackedAppOpen","trackAppOpen","setupVisibilityTracking","setupUnloadTracking","forEach","unsubscribe","referrer","handleVisibilityChange","visibility_state","removeEventListener","reason","InteractionTracker","lastPath","inputValues","Map","trackScreenView","setupHistoryTracking","setupClickTracking","setupFormTracking","setupInputTracking","setupClipboardTracking","setupSelectionTracking","setupErrorTracking","path","pathname","href","title","originalPushState","history","pushState","originalReplaceState","replaceState","trackOnHistoryChange","handleClick","target","button","closest","anchor","isExternal","isExternalLink","is_external","is_download","hasAttribute","capture","URL","handleSubmit","form","form_id","form_name","form_action","action","form_method","handleFocus","input","set","value","input_type","input_name","input_id","handleBlur","previousValue","currentValue","had_value","has_value","handleCopy","_event","selection","getSelection","selectedText","toString","text_length","has_selection","handleCut","handlePaste","pastedText","clipboardData","getData","target_element","selectionTimeout","handleSelectionChange","handleError","filename","lineno","colno","stack","handleRejection","promise","DeepTracker","observers","clickTracker","maxScrollDepth","trackedMedia","WeakSet","setupScrollTracking","setupRageClickTracking","setupLongTaskTracking","setupWebVitals","setupNetworkTracking","setupOrientationTracking","setupMediaTracking","setupTelegramTracking","observer","disconnect","getScrollDepth","windowHeight","innerHeight","documentHeight","documentElement","scrollHeight","scrollTop","pageYOffset","scrollPercentage","Math","min","round","handleScroll","depth","milestone","find","m","max_depth","passive","IntersectionObserver","entries","entry","isIntersecting","selector","getAttribute","intersection_ratio","intersectionRatio","unobserve","threshold","querySelectorAll","observe","mutationObserver","MutationObserver","mutations","mutation","addedNodes","node","Element","el","childList","subtree","tracker","count","timer","click_count","PerformanceObserver","list","getEntries","duration","start_time","startTime","entryTypes","lcpObserver","lastEntry","renderTime","loadTime","fidObserver","processingStart","event_type","clsValue","clsObserver","hadRecentInput","reportCLS","handleOnline","effective_type","connection","effectiveType","downlink","rtt","handleOffline","handleConnectionChange","save_data","saveData","handleOrientationChange","orientation","screen","innerWidth","angle","width","height","trackMediaEvent","media","has","mediaType","eventType","baseProps","media_type","src","currentSrc","isFinite","current_time","currentTime","muted","volume","percent_played","completed","setupMediaElement","HTMLMediaElement","trackEvent","eventName","data","unsubTheme","color_scheme","theme_params","unsubViewport","is_state_stable","isStateStable","is_expanded","isExpanded","viewport_height","viewportHeight","viewport_stable_height","viewportStableHeight","unsubSafeArea","safe_area","safeAreaInset","unsubContentSafeArea","content_safe_area","contentSafeAreaInset","unsubBackButton","unsubMainButton","button_text","MainButton","unsubInvoice","unsubPopup","button_id","unsubQrText","unsubScanQr","unsubClipboard","unsubWriteAccess","unsubFileDownload","unsubCustomMethod","req_id","result","unsubFullscreen","is_fullscreen","isFullscreen","unsubFullscreenFailed","unsubHomeScreenAdded","unsubHomeScreenChecked","unsubPreparedMessageSent","unsubPreparedMessageFailed","unsubEmojiStatusSet","unsubEmojiStatusFailed","unsubEmojiStatusAccess","unsubSettingsButton","unsubSecondaryButton","unsubShareMessageSent","unsubShareMessageFailed","unsubLocationManager","locationManager","LocationManager","is_inited","isInited","is_location_available","isLocationAvailable","is_access_requested","isAccessRequested","is_access_granted","isAccessGranted","unsubLocationRequested","available","latitude","longitude","altitude","course","speed","horizontal_accuracy","vertical_accuracy","course_accuracy","speed_accuracy","unsubAccelerometerStarted","unsubAccelerometerStopped","unsubAccelerometerChanged","accelerometer","Accelerometer","x","y","z","unsubAccelerometerFailed","unsubDeviceOrientationStarted","unsubDeviceOrientationStopped","unsubDeviceOrientationChanged","deviceOrientation","DeviceOrientation","absolute","alpha","beta","gamma","unsubDeviceOrientationFailed","unsubGyroscopeStarted","unsubGyroscopeStopped","unsubGyroscopeChanged","gyroscope","Gyroscope","unsubGyroscopeFailed","unsubContactRequested","unsubActivated","unsubDeactivated","unsubBiometricManager","biometricManager","BiometricManager","is_biometric_available","isBiometricAvailable","biometric_type","biometricType","is_biometric_token_saved","isBiometricTokenSaved","device_id","deviceId","unsubBiometricAuth","is_authenticated","isAuthenticated","biometric_token","biometricToken","unsubBiometricToken","is_updated","isUpdated","patchWebAppMethods","openLink","_dashgramPatched","originalOpenLink","bind","patchedOpenLink","options","openTelegramLink","originalOpenTelegramLink","patchedOpenTelegramLink","switchInlineQuery","originalSwitchInlineQuery","patchedSwitchInlineQuery","query","chooseChatTypes","choose_chat_types","shareToStory","originalShareToStory","patchedShareToStory","mediaUrl","params","media_url","close","originalClose","patchedClose","return_back","exitFullscreen","originalExitFullscreen","patchedExitFullscreen","openInvoice","originalOpenInvoice","patchedOpenInvoice","slug","requestAccess","originalRequestAccess","patchedRequestAccess","accessType","access_type","requestContact","originalRequestContact","patchedRequestContact","requestPhone","originalRequestPhone","patchedRequestPhone","requestLocation","originalRequestLocation","patchedRequestLocation","checkLocation","originalCheckLocation","patchedCheckLocation","context","batchProcessor","trackers","isInitialized","init","setupTrackers","trackAuto","coreTracker","interactionTracker","deepTracker","ensureInitialized","fullEvent","buildEvent","source","eventId","crypto","randomUUID","c","r","random","Object","keys","timestamp","oldLevel","to","shutdown"],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { DashgramConfig,
|
|
1
|
+
import type { DashgramConfig, EventProperties, TrackLevel } from "./types";
|
|
2
2
|
declare class DashgramSDK {
|
|
3
3
|
private config;
|
|
4
4
|
private context;
|
|
@@ -18,8 +18,5 @@ declare class DashgramSDK {
|
|
|
18
18
|
private log;
|
|
19
19
|
}
|
|
20
20
|
declare const DashgramMini: DashgramSDK;
|
|
21
|
-
export type { DashgramConfig, WebAppEvent, EventProperties, TrackLevel };
|
|
22
|
-
export { DashgramError, DashgramAPIError, NetworkError, DashgramConfigurationError } from "./errors";
|
|
23
|
-
export { DashgramMini };
|
|
24
21
|
export default DashgramMini;
|
|
25
22
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAe,eAAe,EAAE,UAAU,EAAE,MAAM,SAAS,CAAA;AAcvF,cAAM,WAAW;IACf,OAAO,CAAC,MAAM,CAAsB;IACpC,OAAO,CAAC,OAAO,CAAuB;IACtC,OAAO,CAAC,SAAS,CAAyB;IAC1C,OAAO,CAAC,cAAc,CAA8B;IACpD,OAAO,CAAC,QAAQ,CAA4D;IAC5E,OAAO,CAAC,aAAa,CAAQ;IAK7B,IAAI,CAAC,UAAU,EAAE,cAAc,GAAG,IAAI;IAiDtC,OAAO,CAAC,aAAa;IA0BrB,KAAK,CAAC,KAAK,EAAE,MAAM,EAAE,UAAU,GAAE,eAAoB,GAAG,IAAI;IAY5D,OAAO,CAAC,SAAS;IAYjB,OAAO,CAAC,UAAU;IAkBlB,aAAa,CAAC,KAAK,EAAE,UAAU,GAAG,IAAI;IAkBhC,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAW5B,QAAQ,IAAI,IAAI;IAqBhB,OAAO,CAAC,iBAAiB;IASzB,OAAO,CAAC,GAAG;CAKZ;AAGD,QAAA,MAAM,YAAY,aAAoB,CAAA;AAGtC,eAAe,YAAY,CAAA"}
|
package/dist/index.js
CHANGED