@aranova/tracking-react 0.4.2 → 0.5.1
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.d.mts +544 -100
- package/dist/index.d.ts +544 -100
- package/dist/index.js +486 -58
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +486 -58
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -229,7 +229,7 @@ function getVisitorId() {
|
|
|
229
229
|
}
|
|
230
230
|
function getOrRotateSessionId(now = Date.now()) {
|
|
231
231
|
if (typeof window === "undefined")
|
|
232
|
-
return safeUuid();
|
|
232
|
+
return { id: safeUuid(), isNew: true };
|
|
233
233
|
const raw = readLocalStorage(SESSION_STORAGE_KEY);
|
|
234
234
|
if (raw) {
|
|
235
235
|
try {
|
|
@@ -238,7 +238,7 @@ function getOrRotateSessionId(now = Date.now()) {
|
|
|
238
238
|
if (now - parsed.last_event_at <= SESSION_IDLE_MS) {
|
|
239
239
|
const refreshed = { id: parsed.id, last_event_at: now };
|
|
240
240
|
writeLocalStorage(SESSION_STORAGE_KEY, JSON.stringify(refreshed));
|
|
241
|
-
return parsed.id;
|
|
241
|
+
return { id: parsed.id, isNew: false };
|
|
242
242
|
}
|
|
243
243
|
}
|
|
244
244
|
} catch {
|
|
@@ -246,7 +246,7 @@ function getOrRotateSessionId(now = Date.now()) {
|
|
|
246
246
|
}
|
|
247
247
|
const fresh = { id: safeUuid(), last_event_at: now };
|
|
248
248
|
writeLocalStorage(SESSION_STORAGE_KEY, JSON.stringify(fresh));
|
|
249
|
-
return fresh.id;
|
|
249
|
+
return { id: fresh.id, isNew: true };
|
|
250
250
|
}
|
|
251
251
|
|
|
252
252
|
// ../tracking-core/src/events/page-view.ts
|
|
@@ -386,6 +386,56 @@ function attachAutoPageView(client, options = {}) {
|
|
|
386
386
|
};
|
|
387
387
|
}
|
|
388
388
|
|
|
389
|
+
// ../tracking-core/src/heartbeat.ts
|
|
390
|
+
function serializeValue(value) {
|
|
391
|
+
if (value instanceof RegExp) return value.source;
|
|
392
|
+
if (Array.isArray(value)) return value.map(serializeValue);
|
|
393
|
+
if (value !== null && typeof value === "object") {
|
|
394
|
+
const out = {};
|
|
395
|
+
for (const [k, v] of Object.entries(value)) {
|
|
396
|
+
out[k] = serializeValue(v);
|
|
397
|
+
}
|
|
398
|
+
return out;
|
|
399
|
+
}
|
|
400
|
+
return value;
|
|
401
|
+
}
|
|
402
|
+
function buildHeartbeatMetadata(surface, sdkVersion, packageName, triggers) {
|
|
403
|
+
const automaticNames = triggers ? Object.keys(triggers.automatic) : [];
|
|
404
|
+
const manualNames = triggers?.manual ? Object.keys(triggers.manual) : [];
|
|
405
|
+
let triggerConfig = null;
|
|
406
|
+
if (triggers) {
|
|
407
|
+
const cfg = {};
|
|
408
|
+
for (const [name, config] of Object.entries(triggers.automatic)) {
|
|
409
|
+
const serialized = serializeValue(config);
|
|
410
|
+
if (Object.keys(serialized).length > 0) {
|
|
411
|
+
cfg[name] = serialized;
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
if (triggers.manual) {
|
|
415
|
+
for (const [name, config] of Object.entries(triggers.manual)) {
|
|
416
|
+
if (config === void 0) continue;
|
|
417
|
+
const serialized = serializeValue(config);
|
|
418
|
+
if (Object.keys(serialized).length > 0) {
|
|
419
|
+
cfg[name] = serialized;
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
if (Object.keys(cfg).length > 0) {
|
|
424
|
+
triggerConfig = cfg;
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
return {
|
|
428
|
+
sdk_version: sdkVersion ?? "unknown",
|
|
429
|
+
package_name: packageName,
|
|
430
|
+
surface,
|
|
431
|
+
triggers: {
|
|
432
|
+
automatic: automaticNames,
|
|
433
|
+
manual: manualNames
|
|
434
|
+
},
|
|
435
|
+
trigger_config: triggerConfig
|
|
436
|
+
};
|
|
437
|
+
}
|
|
438
|
+
|
|
389
439
|
// ../tracking-core/src/ingest.ts
|
|
390
440
|
var DEFAULT_FLUSH_INTERVAL_MS = 2e3;
|
|
391
441
|
var DEFAULT_MAX_QUEUE_SIZE = 10;
|
|
@@ -465,11 +515,33 @@ function createTrackingClient(config) {
|
|
|
465
515
|
let firstPage = null;
|
|
466
516
|
let destroyed = false;
|
|
467
517
|
const visitorId = getVisitorId();
|
|
468
|
-
|
|
518
|
+
const initialSession = getOrRotateSessionId();
|
|
519
|
+
let sessionId = initialSession.id;
|
|
469
520
|
if (typeof window !== "undefined")
|
|
470
521
|
firstPage = window.location.href;
|
|
522
|
+
function enqueueHeartbeat() {
|
|
523
|
+
const metadata = buildHeartbeatMetadata(
|
|
524
|
+
config.surface,
|
|
525
|
+
sdkVersion,
|
|
526
|
+
packageName,
|
|
527
|
+
config.triggers ?? null
|
|
528
|
+
);
|
|
529
|
+
queue.push({
|
|
530
|
+
event_type: "sdk_heartbeat",
|
|
531
|
+
page_url: typeof window === "undefined" ? null : window.location.href,
|
|
532
|
+
metadata,
|
|
533
|
+
occurred_at: (/* @__PURE__ */ new Date()).toISOString()
|
|
534
|
+
});
|
|
535
|
+
}
|
|
536
|
+
if (initialSession.isNew) {
|
|
537
|
+
enqueueHeartbeat();
|
|
538
|
+
}
|
|
471
539
|
function buildSessionPayload() {
|
|
472
|
-
|
|
540
|
+
const rotated = getOrRotateSessionId();
|
|
541
|
+
if (rotated.isNew && rotated.id !== sessionId) {
|
|
542
|
+
enqueueHeartbeat();
|
|
543
|
+
}
|
|
544
|
+
sessionId = rotated.id;
|
|
473
545
|
const params = readTrackingParams();
|
|
474
546
|
const context = buildContext(config.surface, sdkVersion, packageName);
|
|
475
547
|
return {
|
|
@@ -570,60 +642,144 @@ function createTrackingClient(config) {
|
|
|
570
642
|
};
|
|
571
643
|
}
|
|
572
644
|
|
|
573
|
-
// ../tracking-core/src/events/
|
|
645
|
+
// ../tracking-core/src/events/cta-click.ts
|
|
574
646
|
import { z as z2 } from "zod";
|
|
575
|
-
var
|
|
647
|
+
var ctaClickMetadataSchema = z2.object({
|
|
648
|
+
cta_name: z2.string(),
|
|
576
649
|
page: z2.object({
|
|
577
650
|
path: z2.string()
|
|
578
|
-
})
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
// RegExp is runtime-only so we wrap it via z.custom. Consumers pass a
|
|
582
|
-
// real regex at createTracking() time; the factory validates with this
|
|
583
|
-
// schema and then keeps the live RegExp reference for runtime matching.
|
|
584
|
-
pathPattern: z2.custom(
|
|
585
|
-
(value) => value instanceof RegExp,
|
|
586
|
-
{ message: "pathPattern must be a RegExp" }
|
|
587
|
-
)
|
|
651
|
+
}),
|
|
652
|
+
section: z2.string().nullable().optional(),
|
|
653
|
+
destination_url: z2.string().nullable().optional()
|
|
588
654
|
}).strict();
|
|
655
|
+
var ctaClickConfigSchema = z2.object({}).strict();
|
|
589
656
|
|
|
590
|
-
// ../tracking-core/src/events/
|
|
657
|
+
// ../tracking-core/src/events/sdk-heartbeat.ts
|
|
591
658
|
import { z as z3 } from "zod";
|
|
592
|
-
var
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
659
|
+
var sdkHeartbeatTriggersSchema = z3.object({
|
|
660
|
+
automatic: z3.array(z3.string()),
|
|
661
|
+
manual: z3.array(z3.string())
|
|
662
|
+
}).strict();
|
|
663
|
+
var sdkHeartbeatMetadataSchema = z3.object({
|
|
664
|
+
sdk_version: z3.string(),
|
|
665
|
+
package_name: z3.string().nullable(),
|
|
666
|
+
surface: z3.enum(["next", "react", "script"]),
|
|
667
|
+
triggers: sdkHeartbeatTriggersSchema,
|
|
668
|
+
trigger_config: z3.record(z3.string(), z3.record(z3.string(), z3.unknown())).nullable().optional()
|
|
600
669
|
}).strict();
|
|
601
|
-
var
|
|
670
|
+
var sdkHeartbeatConfigSchema = z3.object({}).strict();
|
|
602
671
|
|
|
603
|
-
// ../tracking-core/src/events/
|
|
672
|
+
// ../tracking-core/src/events/form-start.ts
|
|
604
673
|
import { z as z4 } from "zod";
|
|
605
|
-
var
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
href: z4.string()
|
|
674
|
+
var formStartMetadataSchema = z4.object({
|
|
675
|
+
form: z4.object({
|
|
676
|
+
id: z4.string(),
|
|
677
|
+
action: z4.string().nullable()
|
|
610
678
|
}),
|
|
611
679
|
page: z4.object({
|
|
612
680
|
path: z4.string()
|
|
613
681
|
})
|
|
614
682
|
}).strict();
|
|
615
|
-
var
|
|
683
|
+
var formStartConfigSchema = z4.object({
|
|
684
|
+
selector: z4.string().optional()
|
|
685
|
+
}).strict();
|
|
616
686
|
|
|
617
|
-
// ../tracking-core/src/events/
|
|
687
|
+
// ../tracking-core/src/events/form-submit.ts
|
|
618
688
|
import { z as z5 } from "zod";
|
|
619
|
-
var
|
|
620
|
-
|
|
689
|
+
var formSubmitMetadataSchema = z5.object({
|
|
690
|
+
form: z5.object({
|
|
691
|
+
id: z5.string(),
|
|
692
|
+
action: z5.string().nullable(),
|
|
693
|
+
fields: z5.array(
|
|
694
|
+
z5.object({
|
|
695
|
+
name: z5.string(),
|
|
696
|
+
type: z5.string(),
|
|
697
|
+
label: z5.string().nullable(),
|
|
698
|
+
has_value: z5.boolean()
|
|
699
|
+
})
|
|
700
|
+
).optional()
|
|
701
|
+
}),
|
|
621
702
|
page: z5.object({
|
|
622
703
|
path: z5.string()
|
|
623
704
|
})
|
|
624
705
|
}).strict();
|
|
625
|
-
var
|
|
626
|
-
|
|
706
|
+
var formSubmitConfigSchema = z5.object({}).strict();
|
|
707
|
+
|
|
708
|
+
// ../tracking-core/src/events/multi-page-session.ts
|
|
709
|
+
import { z as z6 } from "zod";
|
|
710
|
+
var multiPageSessionMetadataSchema = z6.object({
|
|
711
|
+
page_count: z6.number().int().min(2),
|
|
712
|
+
page: z6.object({
|
|
713
|
+
path: z6.string()
|
|
714
|
+
})
|
|
715
|
+
}).strict();
|
|
716
|
+
var multiPageSessionConfigSchema = z6.object({
|
|
717
|
+
pageThreshold: z6.number().int().min(2)
|
|
718
|
+
}).strict();
|
|
719
|
+
|
|
720
|
+
// ../tracking-core/src/events/phone-click.ts
|
|
721
|
+
import { z as z7 } from "zod";
|
|
722
|
+
var phoneClickMetadataSchema = z7.object({
|
|
723
|
+
phone_number: z7.string(),
|
|
724
|
+
page: z7.object({
|
|
725
|
+
path: z7.string()
|
|
726
|
+
}),
|
|
727
|
+
section: z7.string().nullable().optional()
|
|
728
|
+
}).strict();
|
|
729
|
+
var phoneClickConfigSchema = z7.object({}).strict();
|
|
730
|
+
|
|
731
|
+
// ../tracking-core/src/events/scroll-depth.ts
|
|
732
|
+
import { z as z8 } from "zod";
|
|
733
|
+
var scrollDepthMetadataSchema = z8.object({
|
|
734
|
+
depth_percent: z8.number().int().min(1).max(100),
|
|
735
|
+
page: z8.object({
|
|
736
|
+
path: z8.string()
|
|
737
|
+
})
|
|
738
|
+
}).strict();
|
|
739
|
+
var scrollDepthConfigSchema = z8.object({
|
|
740
|
+
thresholds: z8.array(z8.number().int().min(1).max(100)).min(1)
|
|
741
|
+
}).strict();
|
|
742
|
+
|
|
743
|
+
// ../tracking-core/src/events/specific-page-visit.ts
|
|
744
|
+
import { z as z9 } from "zod";
|
|
745
|
+
var SPECIFIC_PAGE_NAMES = [
|
|
746
|
+
"contact_page",
|
|
747
|
+
"about_page",
|
|
748
|
+
"services_page",
|
|
749
|
+
"booking_page",
|
|
750
|
+
"location_page",
|
|
751
|
+
"pricing_page",
|
|
752
|
+
"faq_page",
|
|
753
|
+
"testimonials_page"
|
|
754
|
+
];
|
|
755
|
+
var specificPageNameSchema = z9.enum(SPECIFIC_PAGE_NAMES);
|
|
756
|
+
var specificPageVisitMetadataSchema = z9.object({
|
|
757
|
+
page_name: specificPageNameSchema,
|
|
758
|
+
page: z9.object({
|
|
759
|
+
path: z9.string()
|
|
760
|
+
})
|
|
761
|
+
}).strict();
|
|
762
|
+
var specificPageVisitConfigSchema = z9.object({
|
|
763
|
+
pages: z9.array(
|
|
764
|
+
z9.object({
|
|
765
|
+
name: specificPageNameSchema,
|
|
766
|
+
pathPattern: z9.custom((value) => value instanceof RegExp, {
|
|
767
|
+
message: "pathPattern must be a RegExp"
|
|
768
|
+
})
|
|
769
|
+
})
|
|
770
|
+
).min(1)
|
|
771
|
+
}).strict();
|
|
772
|
+
|
|
773
|
+
// ../tracking-core/src/events/time-on-site.ts
|
|
774
|
+
import { z as z10 } from "zod";
|
|
775
|
+
var timeOnSiteMetadataSchema = z10.object({
|
|
776
|
+
duration_ms: z10.number().int().nonnegative(),
|
|
777
|
+
page: z10.object({
|
|
778
|
+
path: z10.string()
|
|
779
|
+
})
|
|
780
|
+
}).strict();
|
|
781
|
+
var timeOnSiteConfigSchema = z10.object({
|
|
782
|
+
thresholdSeconds: z10.number().int().positive()
|
|
627
783
|
}).strict();
|
|
628
784
|
|
|
629
785
|
// ../tracking-core/src/events/registry.ts
|
|
@@ -639,10 +795,31 @@ var EVENT_REGISTRY = {
|
|
|
639
795
|
metadataSchema: timeOnSiteMetadataSchema,
|
|
640
796
|
configSchema: timeOnSiteConfigSchema
|
|
641
797
|
},
|
|
642
|
-
|
|
798
|
+
specific_page_visit: {
|
|
799
|
+
kind: "automatic",
|
|
800
|
+
metadataSchema: specificPageVisitMetadataSchema,
|
|
801
|
+
configSchema: specificPageVisitConfigSchema
|
|
802
|
+
},
|
|
803
|
+
scroll_depth: {
|
|
643
804
|
kind: "automatic",
|
|
644
|
-
metadataSchema:
|
|
645
|
-
configSchema:
|
|
805
|
+
metadataSchema: scrollDepthMetadataSchema,
|
|
806
|
+
configSchema: scrollDepthConfigSchema
|
|
807
|
+
},
|
|
808
|
+
multi_page_session: {
|
|
809
|
+
kind: "automatic",
|
|
810
|
+
metadataSchema: multiPageSessionMetadataSchema,
|
|
811
|
+
configSchema: multiPageSessionConfigSchema
|
|
812
|
+
},
|
|
813
|
+
form_start: {
|
|
814
|
+
kind: "automatic",
|
|
815
|
+
metadataSchema: formStartMetadataSchema,
|
|
816
|
+
configSchema: formStartConfigSchema
|
|
817
|
+
},
|
|
818
|
+
// --- SDK-internal automatic (not consumer-configurable) ---
|
|
819
|
+
sdk_heartbeat: {
|
|
820
|
+
kind: "automatic",
|
|
821
|
+
metadataSchema: sdkHeartbeatMetadataSchema,
|
|
822
|
+
configSchema: sdkHeartbeatConfigSchema
|
|
646
823
|
},
|
|
647
824
|
// --- manual triggers ---
|
|
648
825
|
form_submit: {
|
|
@@ -654,6 +831,11 @@ var EVENT_REGISTRY = {
|
|
|
654
831
|
kind: "manual",
|
|
655
832
|
metadataSchema: phoneClickMetadataSchema,
|
|
656
833
|
configSchema: phoneClickConfigSchema
|
|
834
|
+
},
|
|
835
|
+
cta_click: {
|
|
836
|
+
kind: "manual",
|
|
837
|
+
metadataSchema: ctaClickMetadataSchema,
|
|
838
|
+
configSchema: ctaClickConfigSchema
|
|
657
839
|
}
|
|
658
840
|
};
|
|
659
841
|
var ALL_AUTOMATIC_EVENT_NAMES = Object.entries(EVENT_REGISTRY).filter(([, def]) => def.kind === "automatic").map(([name]) => name);
|
|
@@ -744,26 +926,193 @@ function attachTimeOnSite(client, config) {
|
|
|
744
926
|
};
|
|
745
927
|
}
|
|
746
928
|
|
|
747
|
-
// ../tracking-core/src/triggers/
|
|
748
|
-
function
|
|
929
|
+
// ../tracking-core/src/triggers/specific-page-visit.ts
|
|
930
|
+
function attachSpecificPageVisit(client, config) {
|
|
749
931
|
if (typeof window === "undefined" || typeof history === "undefined") {
|
|
750
932
|
return () => {
|
|
751
933
|
};
|
|
752
934
|
}
|
|
753
|
-
const {
|
|
754
|
-
|
|
935
|
+
const { pages } = config;
|
|
936
|
+
const firedSet = /* @__PURE__ */ new Set();
|
|
755
937
|
function check() {
|
|
756
938
|
const path = window.location.pathname;
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
939
|
+
for (const { name, pathPattern } of pages) {
|
|
940
|
+
pathPattern.lastIndex = 0;
|
|
941
|
+
if (!pathPattern.test(path)) continue;
|
|
942
|
+
const key = `${name}:${path}`;
|
|
943
|
+
if (firedSet.has(key)) continue;
|
|
944
|
+
firedSet.add(key);
|
|
945
|
+
client.trackEvent({
|
|
946
|
+
eventType: "specific_page_visit",
|
|
947
|
+
metadata: { page_name: name, page: { path } },
|
|
948
|
+
pageUrl: window.location.href,
|
|
949
|
+
occurredAt: null
|
|
950
|
+
});
|
|
951
|
+
}
|
|
952
|
+
}
|
|
953
|
+
const originalPushState = history.pushState.bind(history);
|
|
954
|
+
const originalReplaceState = history.replaceState.bind(history);
|
|
955
|
+
function patchedPushState(...args) {
|
|
956
|
+
originalPushState(...args);
|
|
957
|
+
setTimeout(check, 0);
|
|
958
|
+
}
|
|
959
|
+
function patchedReplaceState(...args) {
|
|
960
|
+
originalReplaceState(...args);
|
|
961
|
+
setTimeout(check, 0);
|
|
962
|
+
}
|
|
963
|
+
history.pushState = patchedPushState;
|
|
964
|
+
history.replaceState = patchedReplaceState;
|
|
965
|
+
window.addEventListener("popstate", check);
|
|
966
|
+
check();
|
|
967
|
+
return () => {
|
|
968
|
+
history.pushState = originalPushState;
|
|
969
|
+
history.replaceState = originalReplaceState;
|
|
970
|
+
window.removeEventListener("popstate", check);
|
|
971
|
+
};
|
|
972
|
+
}
|
|
973
|
+
|
|
974
|
+
// ../tracking-core/src/triggers/scroll-depth.ts
|
|
975
|
+
function attachScrollDepth(client, config) {
|
|
976
|
+
if (typeof window === "undefined" || typeof document === "undefined") {
|
|
977
|
+
return () => {
|
|
978
|
+
};
|
|
979
|
+
}
|
|
980
|
+
const thresholds = new Set(config.thresholds);
|
|
981
|
+
let firedForPath = /* @__PURE__ */ new Set();
|
|
982
|
+
let currentPath = window.location.pathname;
|
|
983
|
+
let rafId = null;
|
|
984
|
+
function getScrollPercent() {
|
|
985
|
+
const doc = document.documentElement;
|
|
986
|
+
const scrollTop = window.scrollY || doc.scrollTop;
|
|
987
|
+
const scrollHeight = doc.scrollHeight;
|
|
988
|
+
const clientHeight = doc.clientHeight;
|
|
989
|
+
if (scrollHeight <= clientHeight) return 100;
|
|
990
|
+
return Math.round((scrollTop + clientHeight) / scrollHeight * 100);
|
|
991
|
+
}
|
|
992
|
+
function checkThresholds() {
|
|
993
|
+
const percent = getScrollPercent();
|
|
994
|
+
for (const threshold of thresholds) {
|
|
995
|
+
if (percent >= threshold && !firedForPath.has(threshold)) {
|
|
996
|
+
firedForPath.add(threshold);
|
|
997
|
+
client.trackEvent({
|
|
998
|
+
eventType: "scroll_depth",
|
|
999
|
+
metadata: {
|
|
1000
|
+
depth_percent: threshold,
|
|
1001
|
+
page: { path: currentPath }
|
|
1002
|
+
},
|
|
1003
|
+
pageUrl: window.location.href,
|
|
1004
|
+
occurredAt: null
|
|
1005
|
+
});
|
|
1006
|
+
}
|
|
1007
|
+
}
|
|
1008
|
+
}
|
|
1009
|
+
function onScroll() {
|
|
1010
|
+
if (rafId !== null) return;
|
|
1011
|
+
rafId = requestAnimationFrame(() => {
|
|
1012
|
+
rafId = null;
|
|
1013
|
+
checkThresholds();
|
|
765
1014
|
});
|
|
766
1015
|
}
|
|
1016
|
+
function resetIfPathChanged() {
|
|
1017
|
+
const newPath = window.location.pathname;
|
|
1018
|
+
if (newPath === currentPath) return;
|
|
1019
|
+
currentPath = newPath;
|
|
1020
|
+
firedForPath = /* @__PURE__ */ new Set();
|
|
1021
|
+
setTimeout(checkThresholds, 0);
|
|
1022
|
+
}
|
|
1023
|
+
const originalPushState = history.pushState.bind(history);
|
|
1024
|
+
const originalReplaceState = history.replaceState.bind(history);
|
|
1025
|
+
function patchedPushState(...args) {
|
|
1026
|
+
originalPushState(...args);
|
|
1027
|
+
setTimeout(resetIfPathChanged, 0);
|
|
1028
|
+
}
|
|
1029
|
+
function patchedReplaceState(...args) {
|
|
1030
|
+
originalReplaceState(...args);
|
|
1031
|
+
setTimeout(resetIfPathChanged, 0);
|
|
1032
|
+
}
|
|
1033
|
+
history.pushState = patchedPushState;
|
|
1034
|
+
history.replaceState = patchedReplaceState;
|
|
1035
|
+
window.addEventListener("popstate", resetIfPathChanged);
|
|
1036
|
+
window.addEventListener("scroll", onScroll, { passive: true });
|
|
1037
|
+
setTimeout(checkThresholds, 0);
|
|
1038
|
+
return () => {
|
|
1039
|
+
if (rafId !== null) cancelAnimationFrame(rafId);
|
|
1040
|
+
history.pushState = originalPushState;
|
|
1041
|
+
history.replaceState = originalReplaceState;
|
|
1042
|
+
window.removeEventListener("popstate", resetIfPathChanged);
|
|
1043
|
+
window.removeEventListener("scroll", onScroll);
|
|
1044
|
+
};
|
|
1045
|
+
}
|
|
1046
|
+
|
|
1047
|
+
// ../tracking-core/src/triggers/multi-page-session.ts
|
|
1048
|
+
var STORAGE_KEY = "aranova_tracking_mps_paths";
|
|
1049
|
+
var SESSION_KEY = "aranova_tracking_mps_session";
|
|
1050
|
+
var FIRED_KEY = "aranova_tracking_mps_fired";
|
|
1051
|
+
function getSessionStorage() {
|
|
1052
|
+
try {
|
|
1053
|
+
return typeof window !== "undefined" ? window.sessionStorage : null;
|
|
1054
|
+
} catch {
|
|
1055
|
+
return null;
|
|
1056
|
+
}
|
|
1057
|
+
}
|
|
1058
|
+
function attachMultiPageSession(client, config) {
|
|
1059
|
+
if (typeof window === "undefined" || typeof history === "undefined") {
|
|
1060
|
+
return () => {
|
|
1061
|
+
};
|
|
1062
|
+
}
|
|
1063
|
+
const storage = getSessionStorage();
|
|
1064
|
+
if (!storage) return () => {
|
|
1065
|
+
};
|
|
1066
|
+
const { pageThreshold } = config;
|
|
1067
|
+
let lastCheckedPath = "";
|
|
1068
|
+
function getDistinctPaths() {
|
|
1069
|
+
try {
|
|
1070
|
+
const raw = storage.getItem(STORAGE_KEY);
|
|
1071
|
+
return raw ? new Set(JSON.parse(raw)) : /* @__PURE__ */ new Set();
|
|
1072
|
+
} catch {
|
|
1073
|
+
return /* @__PURE__ */ new Set();
|
|
1074
|
+
}
|
|
1075
|
+
}
|
|
1076
|
+
function saveDistinctPaths(paths) {
|
|
1077
|
+
try {
|
|
1078
|
+
storage.setItem(STORAGE_KEY, JSON.stringify([...paths]));
|
|
1079
|
+
} catch {
|
|
1080
|
+
}
|
|
1081
|
+
}
|
|
1082
|
+
function resetIfSessionChanged() {
|
|
1083
|
+
const currentSession = getOrRotateSessionId().id;
|
|
1084
|
+
const storedSession = storage.getItem(SESSION_KEY);
|
|
1085
|
+
if (storedSession !== currentSession) {
|
|
1086
|
+
storage.setItem(SESSION_KEY, currentSession);
|
|
1087
|
+
storage.removeItem(STORAGE_KEY);
|
|
1088
|
+
storage.removeItem(FIRED_KEY);
|
|
1089
|
+
}
|
|
1090
|
+
}
|
|
1091
|
+
function hasFired() {
|
|
1092
|
+
return storage.getItem(FIRED_KEY) === "1";
|
|
1093
|
+
}
|
|
1094
|
+
function check() {
|
|
1095
|
+
const currentPath = window.location.pathname;
|
|
1096
|
+
if (currentPath === lastCheckedPath) return;
|
|
1097
|
+
lastCheckedPath = currentPath;
|
|
1098
|
+
resetIfSessionChanged();
|
|
1099
|
+
if (hasFired()) return;
|
|
1100
|
+
const paths = getDistinctPaths();
|
|
1101
|
+
paths.add(currentPath);
|
|
1102
|
+
saveDistinctPaths(paths);
|
|
1103
|
+
if (paths.size >= pageThreshold) {
|
|
1104
|
+
storage.setItem(FIRED_KEY, "1");
|
|
1105
|
+
client.trackEvent({
|
|
1106
|
+
eventType: "multi_page_session",
|
|
1107
|
+
metadata: {
|
|
1108
|
+
page_count: paths.size,
|
|
1109
|
+
page: { path: window.location.pathname }
|
|
1110
|
+
},
|
|
1111
|
+
pageUrl: window.location.href,
|
|
1112
|
+
occurredAt: null
|
|
1113
|
+
});
|
|
1114
|
+
}
|
|
1115
|
+
}
|
|
767
1116
|
const originalPushState = history.pushState.bind(history);
|
|
768
1117
|
const originalReplaceState = history.replaceState.bind(history);
|
|
769
1118
|
function patchedPushState(...args) {
|
|
@@ -785,6 +1134,71 @@ function attachContactPageVisit(client, config) {
|
|
|
785
1134
|
};
|
|
786
1135
|
}
|
|
787
1136
|
|
|
1137
|
+
// ../tracking-core/src/triggers/form-start.ts
|
|
1138
|
+
function attachFormStart(client, config) {
|
|
1139
|
+
if (typeof window === "undefined" || typeof document === "undefined") {
|
|
1140
|
+
return () => {
|
|
1141
|
+
};
|
|
1142
|
+
}
|
|
1143
|
+
const selector = config.selector ?? "form";
|
|
1144
|
+
let firedForms = /* @__PURE__ */ new Set();
|
|
1145
|
+
let currentPath = window.location.pathname;
|
|
1146
|
+
function getFormKey(form) {
|
|
1147
|
+
if (form.id) return `id:${form.id}`;
|
|
1148
|
+
const explicitAction = form.getAttribute("action");
|
|
1149
|
+
if (explicitAction) return `action:${explicitAction}`;
|
|
1150
|
+
const forms = Array.from(document.querySelectorAll(selector));
|
|
1151
|
+
return `index:${forms.indexOf(form)}`;
|
|
1152
|
+
}
|
|
1153
|
+
function onFocusIn(event) {
|
|
1154
|
+
const target = event.target;
|
|
1155
|
+
if (!(target instanceof HTMLElement)) return;
|
|
1156
|
+
const form = target.closest(selector);
|
|
1157
|
+
if (!form || form.tagName !== "FORM") return;
|
|
1158
|
+
const key = getFormKey(form);
|
|
1159
|
+
if (firedForms.has(key)) return;
|
|
1160
|
+
firedForms.add(key);
|
|
1161
|
+
client.trackEvent({
|
|
1162
|
+
eventType: "form_start",
|
|
1163
|
+
metadata: {
|
|
1164
|
+
form: {
|
|
1165
|
+
id: form.id || "",
|
|
1166
|
+
action: form.getAttribute("action") ?? null
|
|
1167
|
+
},
|
|
1168
|
+
page: { path: window.location.pathname }
|
|
1169
|
+
},
|
|
1170
|
+
pageUrl: window.location.href,
|
|
1171
|
+
occurredAt: null
|
|
1172
|
+
});
|
|
1173
|
+
}
|
|
1174
|
+
function resetIfPathChanged() {
|
|
1175
|
+
const newPath = window.location.pathname;
|
|
1176
|
+
if (newPath === currentPath) return;
|
|
1177
|
+
currentPath = newPath;
|
|
1178
|
+
firedForms = /* @__PURE__ */ new Set();
|
|
1179
|
+
}
|
|
1180
|
+
const originalPushState = history.pushState.bind(history);
|
|
1181
|
+
const originalReplaceState = history.replaceState.bind(history);
|
|
1182
|
+
function patchedPushState(...args) {
|
|
1183
|
+
originalPushState(...args);
|
|
1184
|
+
setTimeout(resetIfPathChanged, 0);
|
|
1185
|
+
}
|
|
1186
|
+
function patchedReplaceState(...args) {
|
|
1187
|
+
originalReplaceState(...args);
|
|
1188
|
+
setTimeout(resetIfPathChanged, 0);
|
|
1189
|
+
}
|
|
1190
|
+
history.pushState = patchedPushState;
|
|
1191
|
+
history.replaceState = patchedReplaceState;
|
|
1192
|
+
window.addEventListener("popstate", resetIfPathChanged);
|
|
1193
|
+
document.addEventListener("focusin", onFocusIn);
|
|
1194
|
+
return () => {
|
|
1195
|
+
history.pushState = originalPushState;
|
|
1196
|
+
history.replaceState = originalReplaceState;
|
|
1197
|
+
window.removeEventListener("popstate", resetIfPathChanged);
|
|
1198
|
+
document.removeEventListener("focusin", onFocusIn);
|
|
1199
|
+
};
|
|
1200
|
+
}
|
|
1201
|
+
|
|
788
1202
|
// src/ConsentBanner.tsx
|
|
789
1203
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
790
1204
|
function ConsentBanner() {
|
|
@@ -879,7 +1293,7 @@ import {
|
|
|
879
1293
|
} from "react";
|
|
880
1294
|
|
|
881
1295
|
// package.json
|
|
882
|
-
var version = "0.
|
|
1296
|
+
var version = "0.5.1";
|
|
883
1297
|
|
|
884
1298
|
// src/factory.tsx
|
|
885
1299
|
import { jsx as jsx2 } from "react/jsx-runtime";
|
|
@@ -915,6 +1329,7 @@ function createTracking(options) {
|
|
|
915
1329
|
surface: "react",
|
|
916
1330
|
packageName: "@aranova/tracking-react",
|
|
917
1331
|
sdkVersion: version,
|
|
1332
|
+
triggers,
|
|
918
1333
|
debug
|
|
919
1334
|
}),
|
|
920
1335
|
triggers,
|
|
@@ -933,6 +1348,7 @@ function createTracking(options) {
|
|
|
933
1348
|
endpoint,
|
|
934
1349
|
surface: "react",
|
|
935
1350
|
packageName: "@aranova/tracking-react",
|
|
1351
|
+
triggers,
|
|
936
1352
|
debug
|
|
937
1353
|
});
|
|
938
1354
|
detachers.push(attachAutoPageView(rawClient));
|
|
@@ -941,9 +1357,21 @@ function createTracking(options) {
|
|
|
941
1357
|
if (timeOnSite) {
|
|
942
1358
|
detachers.push(attachTimeOnSite(rawClient, timeOnSite));
|
|
943
1359
|
}
|
|
944
|
-
const
|
|
945
|
-
if (
|
|
946
|
-
detachers.push(
|
|
1360
|
+
const specificPageVisit = triggers.automatic.specific_page_visit;
|
|
1361
|
+
if (specificPageVisit) {
|
|
1362
|
+
detachers.push(attachSpecificPageVisit(rawClient, specificPageVisit));
|
|
1363
|
+
}
|
|
1364
|
+
const scrollDepth = triggers.automatic.scroll_depth;
|
|
1365
|
+
if (scrollDepth) {
|
|
1366
|
+
detachers.push(attachScrollDepth(rawClient, scrollDepth));
|
|
1367
|
+
}
|
|
1368
|
+
const multiPageSession = triggers.automatic.multi_page_session;
|
|
1369
|
+
if (multiPageSession) {
|
|
1370
|
+
detachers.push(attachMultiPageSession(rawClient, multiPageSession));
|
|
1371
|
+
}
|
|
1372
|
+
const formStart = triggers.automatic.form_start;
|
|
1373
|
+
if (formStart) {
|
|
1374
|
+
detachers.push(attachFormStart(rawClient, formStart));
|
|
947
1375
|
}
|
|
948
1376
|
return () => {
|
|
949
1377
|
for (let i = detachers.length - 1; i >= 0; i--) {
|