@faststats/web 0.5.0 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1 +1,462 @@
1
- import{a as e,i as t,n,r,t as i}from"./chunks/api-urls-Bh77rElT.js";import{c as a,o,r as s,s as c,t as l}from"./chunks/send-data-CIbuTxPh.js";import{n as u,t as d}from"./chunks/identifiers-DcGHdsnG.js";var f=class{lastActivation=null;getHref(e){if(!(e instanceof MouseEvent)||!p(e))return null;let t=m(e);return!t||this.isDuplicate(e,t.href)?null:t.href}isDuplicate(e,t){let n={button:e.button,href:t,clientX:e.clientX,clientY:e.clientY,at:Date.now()},r=this.lastActivation;return this.lastActivation=n,!!(r&&r.href===n.href&&r.button===n.button&&r.clientX===n.clientX&&r.clientY===n.clientY&&n.at-r.at<=500)}};function p(e){return e.defaultPrevented?!1:e.type===`click`?e.button===0:e.type===`auxclick`?e.button===1:!1}function m(e){for(let t of e.composedPath())if(h(t))return t;let t=e.target;for(;t;){if(h(t))return t;t=t.parentNode}return null}function h(e){return e instanceof HTMLAnchorElement&&!!e.href&&e.host!==location.host}let g=null,_;function v(){return g}function y(e,t){typeof window>`u`||E()||g?.track(e,t??{})}function b(e,t,n){return typeof window>`u`||E()?Promise.resolve(!1):g?.identify(e,t,n??{})??Promise.resolve(!1)}function x(e=!0){typeof window>`u`||E()||g?.logout(e)}function S(e){g?g.setConsentMode(e):_=e}function C(){S(`granted`)}function w(){S(`denied`)}function T(e){typeof window>`u`||E()||g?.reportError(e)}function E(){try{let e=globalThis.localStorage?.getItem(`disable-faststats`);return e===`true`||e===`1`}catch{return!1}}var D=class{options;baseUrl;debug;started=!1;destroyed=!1;epoch=0;heartbeatTimer=null;pageKey=``;entry={path:``,url:``,hash:``};left=!1;initialPageviewPending=!1;initialPageviewTrigger=`load`;consentMode;pendingBehavior;cleanup=[];childTrackers=[];outboundLinks=new f;constructor(t){if(this.options=t,this.baseUrl=e(t.baseUrl,i),this.debug=t.debug??!1,this.consentMode=_??t.consent?.mode??`granted`,_=void 0,this.pendingBehavior=t.consent?.pendingBehavior??`anonymous`,t.autoTrack??!0){if(typeof window>`u`)return;if(E()){this.log(`disabled`);return}setTimeout(()=>void this.start(),0)}}log(e){this.debug&&console.log(`[Analytics] ${e}`)}isTrackingBlocked(){return typeof window>`u`||this.destroyed||E()}ensureActive(){return this.isTrackingBlocked()?!1:(this.started||this.start(),this.started&&!this.destroyed&&g===this)}canTrack(){return!(this.consentMode===`pending`&&this.pendingBehavior===`disabled`)}canSendEvents(){return!this.isTrackingBlocked()&&this.canTrack()}cookieless(){return!!this.options.cookieless||this.consentMode===`denied`||this.consentMode===`pending`&&this.pendingBehavior===`anonymous`}touch(){this.canTrack()&&a(this.options.siteKey,this.cookieless())}bind(e,t,n,r){e.addEventListener(t,n,r),this.cleanup.push(()=>e.removeEventListener(t,n,r))}loadChild(e,t){let n=this.epoch;t().then(async t=>{if(this.epoch!==n||!this.started||(await t.start(),this.epoch!==n||!this.started))return t.stop?.();this.childTrackers.push(t),this.log(`${e} loaded`)}).catch(t=>this.log(`failed to initialize ${e} tracker: ${String(t)}`))}loadOptionalTrackers(){let e=this.options,t={siteKey:e.siteKey,baseUrl:this.baseUrl,debug:this.debug};if(e.sessionReplays?.enabled){let n=e.replayOptions??{};this.loadChild(`replay`,async()=>{let{default:e}=await import(`./replay.js`);return new e({...t,...n})})}e.errorTracking?.enabled&&this.loadChild(`error`,async()=>{let{default:n}=await import(`./error.js`);return new n({...t,sdkName:e.sdkName,sdkVersion:e.sdkVersion})}),e.webVitals?.enabled&&this.loadChild(`web-vitals`,async()=>{let{default:n}=await import(`./web-vitals.js`);return new n({...t,attribution:e.webVitals?.attribution??!1})})}beginTracking(e){if(this.touch(),this.loadOptionalTrackers(),this.entry={path:location.pathname,url:location.href,hash:location.hash},this.left=!1,this.pageKey=``,document.visibilityState===`visible`){this.pageview({trigger:e});return}this.initialPageviewTrigger=e,this.initialPageviewPending=!0}onLinkClick=e=>{let t=this.outboundLinks.getHref(e);t&&this.track(`outbound_link`,{outbound_link:t})};onVisibilityChange=()=>{if(this.touch(),document.visibilityState===`hidden`){for(let e of this.childTrackers)e.onPageHidden?.();this.heartbeatTimer&&clearInterval(this.heartbeatTimer),this.heartbeatTimer=null;return}this.startHeartbeat(),this.initialPageviewPending&&(this.initialPageviewPending=!1,this.pageview({trigger:this.initialPageviewTrigger}))};onPageHide=e=>{let t=e.persisted;for(let e of this.childTrackers)e.onPageHidden?.(t);t||this.leavePage()};onPageShow=e=>{for(let t of this.childTrackers)t.onPageShow?.(e.persisted)};async start(){if(this.started)return;if(this.isTrackingBlocked()){E()&&this.log(`disabled`);return}if(g&&g!==this){this.log(`already started by another instance`);return}this.started=!0,g=this,c(this.cookieless());let e=()=>this.navigate(),t=[[document,`click`,this.onLinkClick,!0],[document,`auxclick`,this.onLinkClick,!0],[document,`visibilitychange`,this.onVisibilityChange,void 0],[window,`pagehide`,this.onPageHide,void 0],[window,`pageshow`,this.onPageShow,void 0],[window,`popstate`,e,void 0]];(this.options.trackHash??!1)&&t.push([window,`hashchange`,e,void 0]);for(let[e,n,r,i]of t)this.bind(e,n,r,i);for(let e of[`pushState`,`replaceState`]){let t=history[e].bind(history);history[e]=(e,n,r)=>{t(e,n,r),this.navigate()},this.cleanup.push(()=>{history[e]=t})}this.startHeartbeat(),this.canTrack()&&this.beginTracking(`load`)}destroy(){if(!this.destroyed){this.epoch++,this.started&&typeof window<`u`&&this.leavePage(),this.initialPageviewPending=!1,this.heartbeatTimer&&clearInterval(this.heartbeatTimer),this.heartbeatTimer=null;for(let e of this.cleanup.splice(0))e();for(let e of this.childTrackers.splice(0))e.stop?.();g===this&&(g=null),this.started=!1,this.destroyed=!0}}pageview(e={}){if(!this.ensureActive())return;let t=this.options.trackHash??!1,n=`${location.pathname}|${t?location.hash:``}`;n!==this.pageKey&&(this.pageKey=n,this.send(`pageview`,e))}track(e,t={}){if(!this.ensureActive())return;let n=e.trim();n&&this.send(n,t)}identify(e,t,n={}){if(!this.ensureActive()||!this.canTrack()||this.cookieless())return Promise.resolve(!1);let i=e.trim(),a=t.trim();return!i||!a?Promise.resolve(!1):l({url:`${this.baseUrl}${r.identify}`,data:JSON.stringify({token:this.options.siteKey,identifier:this.getAnonymousId(),externalId:i,email:a,name:n.name?.trim()||void 0,phone:n.phone?.trim()||void 0,avatarUrl:n.avatarUrl?.trim()||void 0,traits:n.traits??{}}),contentType:`text/plain`,debug:this.debug,debugPrefix:`[Analytics] identify`,useBeacon:!1})}logout(e=!0){this.ensureActive()&&(e&&u(this.cookieless()),o(this.options.siteKey))}setConsentMode(e){let t=!this.canTrack();this.consentMode=e;let n=this.cookieless();c(n);for(let e of this.childTrackers)e.setCookielessMode?.(n);t&&this.canTrack()&&this.started&&this.beginTracking(`consent`)}getConsentMode(){return this.consentMode}getAnonymousId(){return this.canTrack()?d(this.cookieless()):``}getSessionId(){return s(this.options.siteKey,this.cookieless()).sessionId}getWindowId(){return s(this.options.siteKey,this.cookieless()).windowId}async checkFeatureFlag(t,r,i){if(typeof window>`u`||E()||!this.canTrack())return{value:`false`};let a=i?.externalId?.trim(),o=this.getAnonymousId();if(!a&&!o)return{value:`false`};let{fetchFeatureFlagEvaluation:s}=await import(`./feature-flags.js`);return s(t,{baseUrl:e(this.options.featureFlagsBaseUrl,n),projectToken:this.options.siteKey,...o?{identifier:o}:{},...a?{externalId:a}:{},sessionId:this.getSessionId(),attributes:r,signal:i?.signal})}reportError(e){!this.ensureActive()||!this.options.errorTracking?.enabled||!this.canTrack()||this.childTrackers.find(e=>e.captureError)?.captureError?.(e)}send(e,n={},i={}){if(!this.canSendEvents())return;let a=this.cookieless(),o=d(a),c=s(this.options.siteKey,a);this.log(e),l({url:`${this.baseUrl}${r.events}`,data:JSON.stringify({token:this.options.siteKey,...o?{userId:o}:{},sessionId:c.sessionId,windowId:c.windowId,event:e,...t(),...i,properties:n}),contentType:`text/plain`,debug:this.debug,debugPrefix:`[Analytics] ${e}`})}leavePage(){if(this.destroyed||this.left)return;this.left=!0;let e=s(this.options.siteKey,this.cookieless());this.send(`page_leave`,{session_duration:Date.now()-e.sessionStart},{page:this.entry.path,url:this.entry.url})}startHeartbeat(){this.heartbeatTimer&&clearInterval(this.heartbeatTimer),this.heartbeatTimer=setInterval(()=>{if(document.visibilityState===`hidden`){this.heartbeatTimer&&clearInterval(this.heartbeatTimer),this.heartbeatTimer=null;return}this.touch()},300*1e3)}navigate(){if(!this.started||this.destroyed)return;let e=this.options.trackHash??!1;if(!(location.pathname===this.entry.path&&(!e||location.hash===this.entry.hash))){for(let e of this.childTrackers)e.trackPageChange?.(location.href);this.leavePage(),this.entry={path:location.pathname,url:location.href,hash:location.hash},this.left=!1,this.pageview({trigger:`navigation`})}}};export{D as WebAnalytics,v as getInstance,b as identify,E as isTrackingDisabled,x as logout,C as optIn,w as optOut,T as reportError,S as setConsentMode,y as trackEvent};
1
+ import { a as resolveBaseUrl, i as getPageContext, n as FEATURE_FLAGS_BASE, o as sanitizeUrl, r as URLS, t as ANALYTICS_BASE } from "./chunks/api-urls-Dp2XNjRF.js";
2
+ import { c as touchActivity, l as getStorageItem, o as resetSession, r as getSessionContext, s as setCookielessMode, t as sendData } from "./chunks/send-data-DR1JUXka.js";
3
+ import { n as resetAnonymousId, t as getAnonymousId } from "./chunks/identifiers-BvRNbiwA.js";
4
+ //#region src/outbound-links.ts
5
+ const DEDUPE_MS = 500;
6
+ var OutboundLinkTracker = class {
7
+ lastActivation = null;
8
+ getHref(event) {
9
+ if (!(event instanceof MouseEvent) || !isEligibleActivation(event)) return null;
10
+ const anchor = findOutboundAnchor(event);
11
+ if (!anchor || this.isDuplicate(event, anchor.href)) return null;
12
+ return anchor.href;
13
+ }
14
+ isDuplicate(event, href) {
15
+ const activation = {
16
+ button: event.button,
17
+ href,
18
+ clientX: event.clientX,
19
+ clientY: event.clientY,
20
+ at: Date.now()
21
+ };
22
+ const previous = this.lastActivation;
23
+ this.lastActivation = activation;
24
+ return !!(previous && previous.href === activation.href && previous.button === activation.button && previous.clientX === activation.clientX && previous.clientY === activation.clientY && activation.at - previous.at <= DEDUPE_MS);
25
+ }
26
+ };
27
+ function isEligibleActivation(event) {
28
+ if (event.defaultPrevented) return false;
29
+ if (event.type === "click") return event.button === 0;
30
+ if (event.type === "auxclick") return event.button === 1;
31
+ return false;
32
+ }
33
+ function findOutboundAnchor(event) {
34
+ for (const node of event.composedPath()) if (isOutboundAnchor(node)) return node;
35
+ let node = event.target;
36
+ while (node) {
37
+ if (isOutboundAnchor(node)) return node;
38
+ node = node.parentNode;
39
+ }
40
+ return null;
41
+ }
42
+ function isOutboundAnchor(node) {
43
+ return node instanceof HTMLAnchorElement && (node.protocol === "http:" || node.protocol === "https:") && node.host !== location.host;
44
+ }
45
+ //#endregion
46
+ //#region src/analytics.ts
47
+ let instance = null;
48
+ let pendingConsentMode;
49
+ function getInstance() {
50
+ return instance;
51
+ }
52
+ function activeInstance() {
53
+ if (typeof window === "undefined" || isTrackingDisabled()) return null;
54
+ return instance;
55
+ }
56
+ function trackEvent(eventName, properties) {
57
+ activeInstance()?.track(eventName, properties);
58
+ }
59
+ async function identify(externalId, email, options) {
60
+ return activeInstance()?.identify(externalId, email, options) ?? false;
61
+ }
62
+ function logout(resetAnonymousIdentity = true) {
63
+ activeInstance()?.logout(resetAnonymousIdentity);
64
+ }
65
+ function setConsentMode(mode) {
66
+ if (instance) instance.setConsentMode(mode);
67
+ else pendingConsentMode = mode;
68
+ }
69
+ function optIn() {
70
+ setConsentMode("granted");
71
+ }
72
+ function optOut() {
73
+ setConsentMode("denied");
74
+ }
75
+ function reportError(error) {
76
+ activeInstance()?.reportError(error);
77
+ }
78
+ function isTrackingDisabled() {
79
+ const value = getStorageItem("localStorage", "disable-faststats");
80
+ return value === "true" || value === "1";
81
+ }
82
+ var WebAnalytics = class {
83
+ options;
84
+ baseUrl;
85
+ debug;
86
+ started = false;
87
+ destroyed = false;
88
+ epoch = 0;
89
+ heartbeatTimer = null;
90
+ pageKey = "";
91
+ entry = {
92
+ path: "",
93
+ url: "",
94
+ search: ""
95
+ };
96
+ left = false;
97
+ visitDuration = 0;
98
+ visitStartedAt = null;
99
+ pendingPageviewTrigger = null;
100
+ consentMode;
101
+ pendingBehavior;
102
+ cleanup = [];
103
+ childTrackers = [];
104
+ outboundLinks = new OutboundLinkTracker();
105
+ constructor(options) {
106
+ this.options = options;
107
+ this.baseUrl = resolveBaseUrl(options.baseUrl, ANALYTICS_BASE);
108
+ this.debug = options.debug ?? false;
109
+ this.consentMode = pendingConsentMode ?? options.consent?.mode ?? "granted";
110
+ pendingConsentMode = void 0;
111
+ this.pendingBehavior = options.consent?.pendingBehavior ?? "anonymous";
112
+ if (options.autoTrack ?? true) {
113
+ if (typeof window === "undefined") return;
114
+ if (isTrackingDisabled()) {
115
+ this.log("disabled");
116
+ return;
117
+ }
118
+ setTimeout(() => void this.start(), 0);
119
+ }
120
+ }
121
+ log(msg) {
122
+ if (this.debug) console.log(`[Analytics] ${msg}`);
123
+ }
124
+ isTrackingBlocked() {
125
+ return typeof window === "undefined" || this.destroyed || isTrackingDisabled();
126
+ }
127
+ ensureActive() {
128
+ if (this.isTrackingBlocked()) return false;
129
+ if (!this.started) this.start();
130
+ return this.started && !this.destroyed && instance === this;
131
+ }
132
+ canTrack() {
133
+ return this.consentMode === "granted" || this.consentMode === "pending" && this.pendingBehavior === "anonymous";
134
+ }
135
+ canSendEvents() {
136
+ return !this.isTrackingBlocked() && this.canTrack();
137
+ }
138
+ cookieless() {
139
+ return !!this.options.cookieless || this.consentMode === "pending" && this.pendingBehavior === "anonymous";
140
+ }
141
+ touch() {
142
+ if (this.canTrack()) touchActivity(this.options.siteKey, this.cookieless());
143
+ }
144
+ bind(target, type, listener, options) {
145
+ target.addEventListener(type, listener, options);
146
+ this.cleanup.push(() => target.removeEventListener(type, listener, options));
147
+ }
148
+ stopHeartbeat() {
149
+ if (!this.heartbeatTimer) return;
150
+ clearInterval(this.heartbeatTimer);
151
+ this.heartbeatTimer = null;
152
+ }
153
+ loadChild(name, create) {
154
+ const epoch = this.epoch;
155
+ create().then(async (tracker) => {
156
+ if (this.epoch !== epoch || !this.started) return tracker.stop?.(true);
157
+ await tracker.start();
158
+ if (this.epoch !== epoch || !this.started) return tracker.stop?.(true);
159
+ this.childTrackers.push(tracker);
160
+ this.log(`${name} loaded`);
161
+ }).catch((error) => this.log(`failed to initialize ${name} tracker: ${String(error)}`));
162
+ }
163
+ loadOptionalTrackers() {
164
+ const o = this.options;
165
+ const base = {
166
+ siteKey: o.siteKey,
167
+ baseUrl: this.baseUrl,
168
+ debug: this.debug,
169
+ trackHash: o.trackHash ?? false
170
+ };
171
+ if (o.sessionReplays?.enabled) this.loadChild("replay", async () => {
172
+ const { default: ReplayTracker } = await import("./replay.js");
173
+ return new ReplayTracker({
174
+ ...base,
175
+ ...o.replayOptions
176
+ });
177
+ });
178
+ if (o.errorTracking?.enabled) this.loadChild("error", async () => {
179
+ const { default: ErrorTracker } = await import("./error.js");
180
+ return new ErrorTracker({
181
+ ...base,
182
+ sdkName: o.sdkName,
183
+ sdkVersion: o.sdkVersion
184
+ });
185
+ });
186
+ if (o.webVitals?.enabled) this.loadChild("web-vitals", async () => {
187
+ const { default: WebVitalsTracker } = await import("./web-vitals.js");
188
+ return new WebVitalsTracker({
189
+ ...base,
190
+ attribution: o.webVitals?.attribution ?? false
191
+ });
192
+ });
193
+ }
194
+ enterPage() {
195
+ const includeHash = this.options.trackHash ?? false;
196
+ const hash = includeHash ? location.hash : "";
197
+ this.entry = {
198
+ path: `${location.pathname}${hash}`,
199
+ url: sanitizeUrl(location.href, includeHash),
200
+ search: location.search
201
+ };
202
+ this.left = false;
203
+ this.startVisit();
204
+ }
205
+ beginTracking(trigger) {
206
+ this.touch();
207
+ this.loadOptionalTrackers();
208
+ this.enterPage();
209
+ this.pageKey = "";
210
+ if (document.visibilityState === "visible") {
211
+ this.pageview({ trigger });
212
+ return;
213
+ }
214
+ this.pendingPageviewTrigger = trigger;
215
+ }
216
+ onLinkClick = (event) => {
217
+ const href = this.outboundLinks.getHref(event);
218
+ if (href) this.send("outbound_link", { outbound_link: sanitizeUrl(href) });
219
+ };
220
+ onVisibilityChange = () => {
221
+ this.touch();
222
+ if (document.visibilityState === "hidden") {
223
+ this.pauseVisit();
224
+ for (const tracker of this.childTrackers) tracker.onPageHidden?.(false, false);
225
+ this.stopHeartbeat();
226
+ return;
227
+ }
228
+ this.startHeartbeat();
229
+ this.resumeVisit();
230
+ const trigger = this.pendingPageviewTrigger;
231
+ this.pendingPageviewTrigger = null;
232
+ if (trigger) this.pageview({ trigger });
233
+ };
234
+ onPageHide = (event) => {
235
+ const persisted = event.persisted;
236
+ this.pauseVisit();
237
+ for (const tracker of this.childTrackers) tracker.onPageHidden?.(persisted, !persisted);
238
+ if (!persisted) this.leavePage();
239
+ };
240
+ onPageShow = (event) => {
241
+ if (document.visibilityState === "visible") this.resumeVisit();
242
+ for (const tracker of this.childTrackers) tracker.onPageShow?.(event.persisted);
243
+ };
244
+ async start() {
245
+ if (this.started) return;
246
+ if (this.isTrackingBlocked()) {
247
+ if (isTrackingDisabled()) this.log("disabled");
248
+ return;
249
+ }
250
+ if (instance && instance !== this) {
251
+ this.log("already started by another instance");
252
+ return;
253
+ }
254
+ this.started = true;
255
+ instance = this;
256
+ setCookielessMode(this.cookieless());
257
+ this.bind(document, "click", this.onLinkClick, true);
258
+ this.bind(document, "auxclick", this.onLinkClick, true);
259
+ this.bind(document, "visibilitychange", this.onVisibilityChange);
260
+ this.bind(window, "pagehide", this.onPageHide);
261
+ this.bind(window, "pageshow", this.onPageShow);
262
+ this.bind(window, "popstate", () => this.navigate());
263
+ if (this.options.trackHash ?? false) this.bind(window, "hashchange", () => this.navigate());
264
+ for (const method of ["pushState", "replaceState"]) {
265
+ const original = history[method];
266
+ const wrapped = (data, unused, url) => {
267
+ Reflect.apply(original, history, [
268
+ data,
269
+ unused,
270
+ url
271
+ ]);
272
+ this.navigate();
273
+ };
274
+ history[method] = wrapped;
275
+ this.cleanup.push(() => {
276
+ if (history[method] === wrapped) history[method] = original;
277
+ });
278
+ }
279
+ this.startHeartbeat();
280
+ if (this.canTrack()) this.beginTracking("load");
281
+ }
282
+ destroy() {
283
+ if (this.destroyed) return;
284
+ this.epoch++;
285
+ if (this.started && typeof window !== "undefined") this.leavePage();
286
+ this.pendingPageviewTrigger = null;
287
+ this.stopHeartbeat();
288
+ for (const fn of this.cleanup.splice(0)) fn();
289
+ for (const tracker of this.childTrackers.splice(0)) tracker.stop?.();
290
+ if (instance === this) instance = null;
291
+ this.started = false;
292
+ this.destroyed = true;
293
+ }
294
+ pageview(extra = {}) {
295
+ if (!this.ensureActive()) return;
296
+ const trackHash = this.options.trackHash ?? false;
297
+ const key = `${location.pathname}|${location.search}|${trackHash ? location.hash : ""}`;
298
+ if (key === this.pageKey) return;
299
+ this.pageKey = key;
300
+ this.send("pageview", extra);
301
+ }
302
+ track(name, extra = {}) {
303
+ if (!this.ensureActive()) return;
304
+ const eventName = name.trim();
305
+ if (!eventName || eventName === "pageview" || eventName === "page_leave" || eventName === "error" || eventName === "outbound_link") return;
306
+ this.send(eventName, extra);
307
+ }
308
+ async identify(externalId, email, options = {}) {
309
+ if (!this.ensureActive() || !this.canTrack() || this.cookieless()) return false;
310
+ const trimmedExternalId = externalId.trim();
311
+ const trimmedEmail = email.trim();
312
+ if (!trimmedExternalId || !trimmedEmail) return false;
313
+ return sendData({
314
+ url: `${this.baseUrl}${URLS.identify}`,
315
+ data: JSON.stringify({
316
+ token: this.options.siteKey,
317
+ identifier: this.getAnonymousId(),
318
+ externalId: trimmedExternalId,
319
+ email: trimmedEmail,
320
+ name: options.name?.trim() || void 0,
321
+ phone: options.phone?.trim() || void 0,
322
+ avatarUrl: options.avatarUrl?.trim() || void 0,
323
+ traits: options.traits ?? {}
324
+ }),
325
+ contentType: "text/plain",
326
+ debug: this.debug,
327
+ debugPrefix: "[Analytics] identify",
328
+ useBeacon: false
329
+ });
330
+ }
331
+ logout(resetAnonymousIdentity = true) {
332
+ if (!this.ensureActive()) return;
333
+ if (resetAnonymousIdentity) resetAnonymousId(this.options.siteKey, this.cookieless());
334
+ resetSession(this.options.siteKey);
335
+ }
336
+ setConsentMode(mode) {
337
+ if (mode === this.consentMode) return;
338
+ const wasTracking = this.canTrack();
339
+ this.consentMode = mode;
340
+ const tracking = this.canTrack();
341
+ const cookieless = this.cookieless();
342
+ setCookielessMode(cookieless);
343
+ if (!tracking) {
344
+ this.epoch++;
345
+ this.pauseVisit();
346
+ this.stopHeartbeat();
347
+ this.pendingPageviewTrigger = null;
348
+ for (const tracker of this.childTrackers.splice(0)) tracker.stop?.(true);
349
+ return;
350
+ }
351
+ for (const tracker of this.childTrackers) tracker.setCookielessMode?.(cookieless);
352
+ if (!wasTracking && this.started) {
353
+ this.startHeartbeat();
354
+ this.beginTracking("consent");
355
+ }
356
+ }
357
+ getConsentMode() {
358
+ return this.consentMode;
359
+ }
360
+ getAnonymousId() {
361
+ if (!this.canTrack()) return "";
362
+ return getAnonymousId(this.options.siteKey, this.cookieless());
363
+ }
364
+ getSessionId() {
365
+ if (!this.canTrack()) return "";
366
+ return getSessionContext(this.options.siteKey, this.cookieless()).sessionId;
367
+ }
368
+ getWindowId() {
369
+ if (!this.canTrack()) return "";
370
+ return getSessionContext(this.options.siteKey, this.cookieless()).windowId;
371
+ }
372
+ async checkFeatureFlag(key, attributes, opts) {
373
+ if (typeof window === "undefined" || isTrackingDisabled() || !this.canTrack()) return { value: "false" };
374
+ const externalId = opts?.externalId?.trim();
375
+ const identifier = this.getAnonymousId();
376
+ if (!externalId && !identifier) return { value: "false" };
377
+ const { fetchFeatureFlagEvaluation } = await import("./feature-flags.js");
378
+ return fetchFeatureFlagEvaluation(key, {
379
+ baseUrl: resolveBaseUrl(this.options.featureFlagsBaseUrl, FEATURE_FLAGS_BASE),
380
+ projectToken: this.options.siteKey,
381
+ ...identifier ? { identifier } : {},
382
+ ...externalId ? { externalId } : {},
383
+ sessionId: this.getSessionId(),
384
+ attributes,
385
+ signal: opts?.signal
386
+ });
387
+ }
388
+ reportError(error) {
389
+ if (!this.ensureActive() || !this.options.errorTracking?.enabled || !this.canTrack()) return;
390
+ this.childTrackers.find((tracker) => tracker.captureError)?.captureError?.(error);
391
+ }
392
+ send(event, properties = {}, dims = {}) {
393
+ if (!this.canSendEvents()) return;
394
+ const cookieless = this.cookieless();
395
+ const id = getAnonymousId(this.options.siteKey, cookieless);
396
+ const ctx = getSessionContext(this.options.siteKey, cookieless);
397
+ this.log(event);
398
+ sendData({
399
+ url: `${this.baseUrl}${URLS.events}`,
400
+ data: JSON.stringify({
401
+ token: this.options.siteKey,
402
+ ...id ? { userId: id } : {},
403
+ sessionId: ctx.sessionId,
404
+ windowId: ctx.windowId,
405
+ event,
406
+ ...getPageContext(this.options.trackHash ?? false),
407
+ ...dims,
408
+ properties
409
+ }),
410
+ contentType: "text/plain",
411
+ debug: this.debug,
412
+ debugPrefix: `[Analytics] ${event}`
413
+ });
414
+ }
415
+ leavePage() {
416
+ if (this.destroyed || this.left) return;
417
+ this.pauseVisit();
418
+ this.left = true;
419
+ const ctx = getSessionContext(this.options.siteKey, this.cookieless());
420
+ this.send("page_leave", {
421
+ time_on_page: this.visitDuration,
422
+ session_duration: Date.now() - ctx.sessionStart
423
+ }, {
424
+ page: this.entry.path,
425
+ url: this.entry.url
426
+ });
427
+ }
428
+ startVisit() {
429
+ this.visitDuration = 0;
430
+ this.visitStartedAt = document.visibilityState === "visible" ? Date.now() : null;
431
+ }
432
+ pauseVisit() {
433
+ if (this.visitStartedAt === null) return;
434
+ this.visitDuration += Math.max(0, Date.now() - this.visitStartedAt);
435
+ this.visitStartedAt = null;
436
+ }
437
+ resumeVisit() {
438
+ if (this.left || this.visitStartedAt !== null) return;
439
+ this.visitStartedAt = Date.now();
440
+ }
441
+ startHeartbeat() {
442
+ this.stopHeartbeat();
443
+ this.heartbeatTimer = setInterval(() => {
444
+ if (document.visibilityState === "hidden") {
445
+ this.stopHeartbeat();
446
+ return;
447
+ }
448
+ this.touch();
449
+ }, 300 * 1e3);
450
+ }
451
+ navigate() {
452
+ if (!this.started || this.destroyed) return;
453
+ const trackHash = this.options.trackHash ?? false;
454
+ if (`${location.pathname}${trackHash ? location.hash : ""}` === this.entry.path && location.search === this.entry.search) return;
455
+ for (const tracker of this.childTrackers) tracker.trackPageChange?.(sanitizeUrl(location.href, trackHash));
456
+ this.leavePage();
457
+ this.enterPage();
458
+ this.pageview({ trigger: "navigation" });
459
+ }
460
+ };
461
+ //#endregion
462
+ export { WebAnalytics, getInstance, identify, isTrackingDisabled, logout, optIn, optOut, reportError, setConsentMode, trackEvent };
package/dist/replay.d.ts CHANGED
@@ -1,2 +1,2 @@
1
- import { n as ReplayTrackerOptions, t as ReplayTracker } from "./chunks/replay-CLfrGjqj.js";
1
+ import { n as ReplayTrackerOptions, t as ReplayTracker } from "./chunks/replay-BeC2XA4N.js";
2
2
  export { ReplayTrackerOptions, ReplayTracker as default };