@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.js
CHANGED
|
@@ -267,7 +267,7 @@ function getVisitorId() {
|
|
|
267
267
|
}
|
|
268
268
|
function getOrRotateSessionId(now = Date.now()) {
|
|
269
269
|
if (typeof window === "undefined")
|
|
270
|
-
return safeUuid();
|
|
270
|
+
return { id: safeUuid(), isNew: true };
|
|
271
271
|
const raw = readLocalStorage(SESSION_STORAGE_KEY);
|
|
272
272
|
if (raw) {
|
|
273
273
|
try {
|
|
@@ -276,7 +276,7 @@ function getOrRotateSessionId(now = Date.now()) {
|
|
|
276
276
|
if (now - parsed.last_event_at <= SESSION_IDLE_MS) {
|
|
277
277
|
const refreshed = { id: parsed.id, last_event_at: now };
|
|
278
278
|
writeLocalStorage(SESSION_STORAGE_KEY, JSON.stringify(refreshed));
|
|
279
|
-
return parsed.id;
|
|
279
|
+
return { id: parsed.id, isNew: false };
|
|
280
280
|
}
|
|
281
281
|
}
|
|
282
282
|
} catch {
|
|
@@ -284,7 +284,7 @@ function getOrRotateSessionId(now = Date.now()) {
|
|
|
284
284
|
}
|
|
285
285
|
const fresh = { id: safeUuid(), last_event_at: now };
|
|
286
286
|
writeLocalStorage(SESSION_STORAGE_KEY, JSON.stringify(fresh));
|
|
287
|
-
return fresh.id;
|
|
287
|
+
return { id: fresh.id, isNew: true };
|
|
288
288
|
}
|
|
289
289
|
|
|
290
290
|
// ../tracking-core/src/events/page-view.ts
|
|
@@ -424,6 +424,56 @@ function attachAutoPageView(client, options = {}) {
|
|
|
424
424
|
};
|
|
425
425
|
}
|
|
426
426
|
|
|
427
|
+
// ../tracking-core/src/heartbeat.ts
|
|
428
|
+
function serializeValue(value) {
|
|
429
|
+
if (value instanceof RegExp) return value.source;
|
|
430
|
+
if (Array.isArray(value)) return value.map(serializeValue);
|
|
431
|
+
if (value !== null && typeof value === "object") {
|
|
432
|
+
const out = {};
|
|
433
|
+
for (const [k, v] of Object.entries(value)) {
|
|
434
|
+
out[k] = serializeValue(v);
|
|
435
|
+
}
|
|
436
|
+
return out;
|
|
437
|
+
}
|
|
438
|
+
return value;
|
|
439
|
+
}
|
|
440
|
+
function buildHeartbeatMetadata(surface, sdkVersion, packageName, triggers) {
|
|
441
|
+
const automaticNames = triggers ? Object.keys(triggers.automatic) : [];
|
|
442
|
+
const manualNames = triggers?.manual ? Object.keys(triggers.manual) : [];
|
|
443
|
+
let triggerConfig = null;
|
|
444
|
+
if (triggers) {
|
|
445
|
+
const cfg = {};
|
|
446
|
+
for (const [name, config] of Object.entries(triggers.automatic)) {
|
|
447
|
+
const serialized = serializeValue(config);
|
|
448
|
+
if (Object.keys(serialized).length > 0) {
|
|
449
|
+
cfg[name] = serialized;
|
|
450
|
+
}
|
|
451
|
+
}
|
|
452
|
+
if (triggers.manual) {
|
|
453
|
+
for (const [name, config] of Object.entries(triggers.manual)) {
|
|
454
|
+
if (config === void 0) continue;
|
|
455
|
+
const serialized = serializeValue(config);
|
|
456
|
+
if (Object.keys(serialized).length > 0) {
|
|
457
|
+
cfg[name] = serialized;
|
|
458
|
+
}
|
|
459
|
+
}
|
|
460
|
+
}
|
|
461
|
+
if (Object.keys(cfg).length > 0) {
|
|
462
|
+
triggerConfig = cfg;
|
|
463
|
+
}
|
|
464
|
+
}
|
|
465
|
+
return {
|
|
466
|
+
sdk_version: sdkVersion ?? "unknown",
|
|
467
|
+
package_name: packageName,
|
|
468
|
+
surface,
|
|
469
|
+
triggers: {
|
|
470
|
+
automatic: automaticNames,
|
|
471
|
+
manual: manualNames
|
|
472
|
+
},
|
|
473
|
+
trigger_config: triggerConfig
|
|
474
|
+
};
|
|
475
|
+
}
|
|
476
|
+
|
|
427
477
|
// ../tracking-core/src/ingest.ts
|
|
428
478
|
var DEFAULT_FLUSH_INTERVAL_MS = 2e3;
|
|
429
479
|
var DEFAULT_MAX_QUEUE_SIZE = 10;
|
|
@@ -503,11 +553,33 @@ function createTrackingClient(config) {
|
|
|
503
553
|
let firstPage = null;
|
|
504
554
|
let destroyed = false;
|
|
505
555
|
const visitorId = getVisitorId();
|
|
506
|
-
|
|
556
|
+
const initialSession = getOrRotateSessionId();
|
|
557
|
+
let sessionId = initialSession.id;
|
|
507
558
|
if (typeof window !== "undefined")
|
|
508
559
|
firstPage = window.location.href;
|
|
560
|
+
function enqueueHeartbeat() {
|
|
561
|
+
const metadata = buildHeartbeatMetadata(
|
|
562
|
+
config.surface,
|
|
563
|
+
sdkVersion,
|
|
564
|
+
packageName,
|
|
565
|
+
config.triggers ?? null
|
|
566
|
+
);
|
|
567
|
+
queue.push({
|
|
568
|
+
event_type: "sdk_heartbeat",
|
|
569
|
+
page_url: typeof window === "undefined" ? null : window.location.href,
|
|
570
|
+
metadata,
|
|
571
|
+
occurred_at: (/* @__PURE__ */ new Date()).toISOString()
|
|
572
|
+
});
|
|
573
|
+
}
|
|
574
|
+
if (initialSession.isNew) {
|
|
575
|
+
enqueueHeartbeat();
|
|
576
|
+
}
|
|
509
577
|
function buildSessionPayload() {
|
|
510
|
-
|
|
578
|
+
const rotated = getOrRotateSessionId();
|
|
579
|
+
if (rotated.isNew && rotated.id !== sessionId) {
|
|
580
|
+
enqueueHeartbeat();
|
|
581
|
+
}
|
|
582
|
+
sessionId = rotated.id;
|
|
511
583
|
const params = readTrackingParams();
|
|
512
584
|
const context = buildContext(config.surface, sdkVersion, packageName);
|
|
513
585
|
return {
|
|
@@ -608,60 +680,144 @@ function createTrackingClient(config) {
|
|
|
608
680
|
};
|
|
609
681
|
}
|
|
610
682
|
|
|
611
|
-
// ../tracking-core/src/events/
|
|
683
|
+
// ../tracking-core/src/events/cta-click.ts
|
|
612
684
|
var import_zod2 = require("zod");
|
|
613
|
-
var
|
|
685
|
+
var ctaClickMetadataSchema = import_zod2.z.object({
|
|
686
|
+
cta_name: import_zod2.z.string(),
|
|
614
687
|
page: import_zod2.z.object({
|
|
615
688
|
path: import_zod2.z.string()
|
|
616
|
-
})
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
// RegExp is runtime-only so we wrap it via z.custom. Consumers pass a
|
|
620
|
-
// real regex at createTracking() time; the factory validates with this
|
|
621
|
-
// schema and then keeps the live RegExp reference for runtime matching.
|
|
622
|
-
pathPattern: import_zod2.z.custom(
|
|
623
|
-
(value) => value instanceof RegExp,
|
|
624
|
-
{ message: "pathPattern must be a RegExp" }
|
|
625
|
-
)
|
|
689
|
+
}),
|
|
690
|
+
section: import_zod2.z.string().nullable().optional(),
|
|
691
|
+
destination_url: import_zod2.z.string().nullable().optional()
|
|
626
692
|
}).strict();
|
|
693
|
+
var ctaClickConfigSchema = import_zod2.z.object({}).strict();
|
|
627
694
|
|
|
628
|
-
// ../tracking-core/src/events/
|
|
695
|
+
// ../tracking-core/src/events/sdk-heartbeat.ts
|
|
629
696
|
var import_zod3 = require("zod");
|
|
630
|
-
var
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
697
|
+
var sdkHeartbeatTriggersSchema = import_zod3.z.object({
|
|
698
|
+
automatic: import_zod3.z.array(import_zod3.z.string()),
|
|
699
|
+
manual: import_zod3.z.array(import_zod3.z.string())
|
|
700
|
+
}).strict();
|
|
701
|
+
var sdkHeartbeatMetadataSchema = import_zod3.z.object({
|
|
702
|
+
sdk_version: import_zod3.z.string(),
|
|
703
|
+
package_name: import_zod3.z.string().nullable(),
|
|
704
|
+
surface: import_zod3.z.enum(["next", "react", "script"]),
|
|
705
|
+
triggers: sdkHeartbeatTriggersSchema,
|
|
706
|
+
trigger_config: import_zod3.z.record(import_zod3.z.string(), import_zod3.z.record(import_zod3.z.string(), import_zod3.z.unknown())).nullable().optional()
|
|
638
707
|
}).strict();
|
|
639
|
-
var
|
|
708
|
+
var sdkHeartbeatConfigSchema = import_zod3.z.object({}).strict();
|
|
640
709
|
|
|
641
|
-
// ../tracking-core/src/events/
|
|
710
|
+
// ../tracking-core/src/events/form-start.ts
|
|
642
711
|
var import_zod4 = require("zod");
|
|
643
|
-
var
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
href: import_zod4.z.string()
|
|
712
|
+
var formStartMetadataSchema = import_zod4.z.object({
|
|
713
|
+
form: import_zod4.z.object({
|
|
714
|
+
id: import_zod4.z.string(),
|
|
715
|
+
action: import_zod4.z.string().nullable()
|
|
648
716
|
}),
|
|
649
717
|
page: import_zod4.z.object({
|
|
650
718
|
path: import_zod4.z.string()
|
|
651
719
|
})
|
|
652
720
|
}).strict();
|
|
653
|
-
var
|
|
721
|
+
var formStartConfigSchema = import_zod4.z.object({
|
|
722
|
+
selector: import_zod4.z.string().optional()
|
|
723
|
+
}).strict();
|
|
654
724
|
|
|
655
|
-
// ../tracking-core/src/events/
|
|
725
|
+
// ../tracking-core/src/events/form-submit.ts
|
|
656
726
|
var import_zod5 = require("zod");
|
|
657
|
-
var
|
|
658
|
-
|
|
727
|
+
var formSubmitMetadataSchema = import_zod5.z.object({
|
|
728
|
+
form: import_zod5.z.object({
|
|
729
|
+
id: import_zod5.z.string(),
|
|
730
|
+
action: import_zod5.z.string().nullable(),
|
|
731
|
+
fields: import_zod5.z.array(
|
|
732
|
+
import_zod5.z.object({
|
|
733
|
+
name: import_zod5.z.string(),
|
|
734
|
+
type: import_zod5.z.string(),
|
|
735
|
+
label: import_zod5.z.string().nullable(),
|
|
736
|
+
has_value: import_zod5.z.boolean()
|
|
737
|
+
})
|
|
738
|
+
).optional()
|
|
739
|
+
}),
|
|
659
740
|
page: import_zod5.z.object({
|
|
660
741
|
path: import_zod5.z.string()
|
|
661
742
|
})
|
|
662
743
|
}).strict();
|
|
663
|
-
var
|
|
664
|
-
|
|
744
|
+
var formSubmitConfigSchema = import_zod5.z.object({}).strict();
|
|
745
|
+
|
|
746
|
+
// ../tracking-core/src/events/multi-page-session.ts
|
|
747
|
+
var import_zod6 = require("zod");
|
|
748
|
+
var multiPageSessionMetadataSchema = import_zod6.z.object({
|
|
749
|
+
page_count: import_zod6.z.number().int().min(2),
|
|
750
|
+
page: import_zod6.z.object({
|
|
751
|
+
path: import_zod6.z.string()
|
|
752
|
+
})
|
|
753
|
+
}).strict();
|
|
754
|
+
var multiPageSessionConfigSchema = import_zod6.z.object({
|
|
755
|
+
pageThreshold: import_zod6.z.number().int().min(2)
|
|
756
|
+
}).strict();
|
|
757
|
+
|
|
758
|
+
// ../tracking-core/src/events/phone-click.ts
|
|
759
|
+
var import_zod7 = require("zod");
|
|
760
|
+
var phoneClickMetadataSchema = import_zod7.z.object({
|
|
761
|
+
phone_number: import_zod7.z.string(),
|
|
762
|
+
page: import_zod7.z.object({
|
|
763
|
+
path: import_zod7.z.string()
|
|
764
|
+
}),
|
|
765
|
+
section: import_zod7.z.string().nullable().optional()
|
|
766
|
+
}).strict();
|
|
767
|
+
var phoneClickConfigSchema = import_zod7.z.object({}).strict();
|
|
768
|
+
|
|
769
|
+
// ../tracking-core/src/events/scroll-depth.ts
|
|
770
|
+
var import_zod8 = require("zod");
|
|
771
|
+
var scrollDepthMetadataSchema = import_zod8.z.object({
|
|
772
|
+
depth_percent: import_zod8.z.number().int().min(1).max(100),
|
|
773
|
+
page: import_zod8.z.object({
|
|
774
|
+
path: import_zod8.z.string()
|
|
775
|
+
})
|
|
776
|
+
}).strict();
|
|
777
|
+
var scrollDepthConfigSchema = import_zod8.z.object({
|
|
778
|
+
thresholds: import_zod8.z.array(import_zod8.z.number().int().min(1).max(100)).min(1)
|
|
779
|
+
}).strict();
|
|
780
|
+
|
|
781
|
+
// ../tracking-core/src/events/specific-page-visit.ts
|
|
782
|
+
var import_zod9 = require("zod");
|
|
783
|
+
var SPECIFIC_PAGE_NAMES = [
|
|
784
|
+
"contact_page",
|
|
785
|
+
"about_page",
|
|
786
|
+
"services_page",
|
|
787
|
+
"booking_page",
|
|
788
|
+
"location_page",
|
|
789
|
+
"pricing_page",
|
|
790
|
+
"faq_page",
|
|
791
|
+
"testimonials_page"
|
|
792
|
+
];
|
|
793
|
+
var specificPageNameSchema = import_zod9.z.enum(SPECIFIC_PAGE_NAMES);
|
|
794
|
+
var specificPageVisitMetadataSchema = import_zod9.z.object({
|
|
795
|
+
page_name: specificPageNameSchema,
|
|
796
|
+
page: import_zod9.z.object({
|
|
797
|
+
path: import_zod9.z.string()
|
|
798
|
+
})
|
|
799
|
+
}).strict();
|
|
800
|
+
var specificPageVisitConfigSchema = import_zod9.z.object({
|
|
801
|
+
pages: import_zod9.z.array(
|
|
802
|
+
import_zod9.z.object({
|
|
803
|
+
name: specificPageNameSchema,
|
|
804
|
+
pathPattern: import_zod9.z.custom((value) => value instanceof RegExp, {
|
|
805
|
+
message: "pathPattern must be a RegExp"
|
|
806
|
+
})
|
|
807
|
+
})
|
|
808
|
+
).min(1)
|
|
809
|
+
}).strict();
|
|
810
|
+
|
|
811
|
+
// ../tracking-core/src/events/time-on-site.ts
|
|
812
|
+
var import_zod10 = require("zod");
|
|
813
|
+
var timeOnSiteMetadataSchema = import_zod10.z.object({
|
|
814
|
+
duration_ms: import_zod10.z.number().int().nonnegative(),
|
|
815
|
+
page: import_zod10.z.object({
|
|
816
|
+
path: import_zod10.z.string()
|
|
817
|
+
})
|
|
818
|
+
}).strict();
|
|
819
|
+
var timeOnSiteConfigSchema = import_zod10.z.object({
|
|
820
|
+
thresholdSeconds: import_zod10.z.number().int().positive()
|
|
665
821
|
}).strict();
|
|
666
822
|
|
|
667
823
|
// ../tracking-core/src/events/registry.ts
|
|
@@ -677,10 +833,31 @@ var EVENT_REGISTRY = {
|
|
|
677
833
|
metadataSchema: timeOnSiteMetadataSchema,
|
|
678
834
|
configSchema: timeOnSiteConfigSchema
|
|
679
835
|
},
|
|
680
|
-
|
|
836
|
+
specific_page_visit: {
|
|
837
|
+
kind: "automatic",
|
|
838
|
+
metadataSchema: specificPageVisitMetadataSchema,
|
|
839
|
+
configSchema: specificPageVisitConfigSchema
|
|
840
|
+
},
|
|
841
|
+
scroll_depth: {
|
|
681
842
|
kind: "automatic",
|
|
682
|
-
metadataSchema:
|
|
683
|
-
configSchema:
|
|
843
|
+
metadataSchema: scrollDepthMetadataSchema,
|
|
844
|
+
configSchema: scrollDepthConfigSchema
|
|
845
|
+
},
|
|
846
|
+
multi_page_session: {
|
|
847
|
+
kind: "automatic",
|
|
848
|
+
metadataSchema: multiPageSessionMetadataSchema,
|
|
849
|
+
configSchema: multiPageSessionConfigSchema
|
|
850
|
+
},
|
|
851
|
+
form_start: {
|
|
852
|
+
kind: "automatic",
|
|
853
|
+
metadataSchema: formStartMetadataSchema,
|
|
854
|
+
configSchema: formStartConfigSchema
|
|
855
|
+
},
|
|
856
|
+
// --- SDK-internal automatic (not consumer-configurable) ---
|
|
857
|
+
sdk_heartbeat: {
|
|
858
|
+
kind: "automatic",
|
|
859
|
+
metadataSchema: sdkHeartbeatMetadataSchema,
|
|
860
|
+
configSchema: sdkHeartbeatConfigSchema
|
|
684
861
|
},
|
|
685
862
|
// --- manual triggers ---
|
|
686
863
|
form_submit: {
|
|
@@ -692,6 +869,11 @@ var EVENT_REGISTRY = {
|
|
|
692
869
|
kind: "manual",
|
|
693
870
|
metadataSchema: phoneClickMetadataSchema,
|
|
694
871
|
configSchema: phoneClickConfigSchema
|
|
872
|
+
},
|
|
873
|
+
cta_click: {
|
|
874
|
+
kind: "manual",
|
|
875
|
+
metadataSchema: ctaClickMetadataSchema,
|
|
876
|
+
configSchema: ctaClickConfigSchema
|
|
695
877
|
}
|
|
696
878
|
};
|
|
697
879
|
var ALL_AUTOMATIC_EVENT_NAMES = Object.entries(EVENT_REGISTRY).filter(([, def]) => def.kind === "automatic").map(([name]) => name);
|
|
@@ -782,26 +964,193 @@ function attachTimeOnSite(client, config) {
|
|
|
782
964
|
};
|
|
783
965
|
}
|
|
784
966
|
|
|
785
|
-
// ../tracking-core/src/triggers/
|
|
786
|
-
function
|
|
967
|
+
// ../tracking-core/src/triggers/specific-page-visit.ts
|
|
968
|
+
function attachSpecificPageVisit(client, config) {
|
|
787
969
|
if (typeof window === "undefined" || typeof history === "undefined") {
|
|
788
970
|
return () => {
|
|
789
971
|
};
|
|
790
972
|
}
|
|
791
|
-
const {
|
|
792
|
-
|
|
973
|
+
const { pages } = config;
|
|
974
|
+
const firedSet = /* @__PURE__ */ new Set();
|
|
793
975
|
function check() {
|
|
794
976
|
const path = window.location.pathname;
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
977
|
+
for (const { name, pathPattern } of pages) {
|
|
978
|
+
pathPattern.lastIndex = 0;
|
|
979
|
+
if (!pathPattern.test(path)) continue;
|
|
980
|
+
const key = `${name}:${path}`;
|
|
981
|
+
if (firedSet.has(key)) continue;
|
|
982
|
+
firedSet.add(key);
|
|
983
|
+
client.trackEvent({
|
|
984
|
+
eventType: "specific_page_visit",
|
|
985
|
+
metadata: { page_name: name, page: { path } },
|
|
986
|
+
pageUrl: window.location.href,
|
|
987
|
+
occurredAt: null
|
|
988
|
+
});
|
|
989
|
+
}
|
|
990
|
+
}
|
|
991
|
+
const originalPushState = history.pushState.bind(history);
|
|
992
|
+
const originalReplaceState = history.replaceState.bind(history);
|
|
993
|
+
function patchedPushState(...args) {
|
|
994
|
+
originalPushState(...args);
|
|
995
|
+
setTimeout(check, 0);
|
|
996
|
+
}
|
|
997
|
+
function patchedReplaceState(...args) {
|
|
998
|
+
originalReplaceState(...args);
|
|
999
|
+
setTimeout(check, 0);
|
|
1000
|
+
}
|
|
1001
|
+
history.pushState = patchedPushState;
|
|
1002
|
+
history.replaceState = patchedReplaceState;
|
|
1003
|
+
window.addEventListener("popstate", check);
|
|
1004
|
+
check();
|
|
1005
|
+
return () => {
|
|
1006
|
+
history.pushState = originalPushState;
|
|
1007
|
+
history.replaceState = originalReplaceState;
|
|
1008
|
+
window.removeEventListener("popstate", check);
|
|
1009
|
+
};
|
|
1010
|
+
}
|
|
1011
|
+
|
|
1012
|
+
// ../tracking-core/src/triggers/scroll-depth.ts
|
|
1013
|
+
function attachScrollDepth(client, config) {
|
|
1014
|
+
if (typeof window === "undefined" || typeof document === "undefined") {
|
|
1015
|
+
return () => {
|
|
1016
|
+
};
|
|
1017
|
+
}
|
|
1018
|
+
const thresholds = new Set(config.thresholds);
|
|
1019
|
+
let firedForPath = /* @__PURE__ */ new Set();
|
|
1020
|
+
let currentPath = window.location.pathname;
|
|
1021
|
+
let rafId = null;
|
|
1022
|
+
function getScrollPercent() {
|
|
1023
|
+
const doc = document.documentElement;
|
|
1024
|
+
const scrollTop = window.scrollY || doc.scrollTop;
|
|
1025
|
+
const scrollHeight = doc.scrollHeight;
|
|
1026
|
+
const clientHeight = doc.clientHeight;
|
|
1027
|
+
if (scrollHeight <= clientHeight) return 100;
|
|
1028
|
+
return Math.round((scrollTop + clientHeight) / scrollHeight * 100);
|
|
1029
|
+
}
|
|
1030
|
+
function checkThresholds() {
|
|
1031
|
+
const percent = getScrollPercent();
|
|
1032
|
+
for (const threshold of thresholds) {
|
|
1033
|
+
if (percent >= threshold && !firedForPath.has(threshold)) {
|
|
1034
|
+
firedForPath.add(threshold);
|
|
1035
|
+
client.trackEvent({
|
|
1036
|
+
eventType: "scroll_depth",
|
|
1037
|
+
metadata: {
|
|
1038
|
+
depth_percent: threshold,
|
|
1039
|
+
page: { path: currentPath }
|
|
1040
|
+
},
|
|
1041
|
+
pageUrl: window.location.href,
|
|
1042
|
+
occurredAt: null
|
|
1043
|
+
});
|
|
1044
|
+
}
|
|
1045
|
+
}
|
|
1046
|
+
}
|
|
1047
|
+
function onScroll() {
|
|
1048
|
+
if (rafId !== null) return;
|
|
1049
|
+
rafId = requestAnimationFrame(() => {
|
|
1050
|
+
rafId = null;
|
|
1051
|
+
checkThresholds();
|
|
803
1052
|
});
|
|
804
1053
|
}
|
|
1054
|
+
function resetIfPathChanged() {
|
|
1055
|
+
const newPath = window.location.pathname;
|
|
1056
|
+
if (newPath === currentPath) return;
|
|
1057
|
+
currentPath = newPath;
|
|
1058
|
+
firedForPath = /* @__PURE__ */ new Set();
|
|
1059
|
+
setTimeout(checkThresholds, 0);
|
|
1060
|
+
}
|
|
1061
|
+
const originalPushState = history.pushState.bind(history);
|
|
1062
|
+
const originalReplaceState = history.replaceState.bind(history);
|
|
1063
|
+
function patchedPushState(...args) {
|
|
1064
|
+
originalPushState(...args);
|
|
1065
|
+
setTimeout(resetIfPathChanged, 0);
|
|
1066
|
+
}
|
|
1067
|
+
function patchedReplaceState(...args) {
|
|
1068
|
+
originalReplaceState(...args);
|
|
1069
|
+
setTimeout(resetIfPathChanged, 0);
|
|
1070
|
+
}
|
|
1071
|
+
history.pushState = patchedPushState;
|
|
1072
|
+
history.replaceState = patchedReplaceState;
|
|
1073
|
+
window.addEventListener("popstate", resetIfPathChanged);
|
|
1074
|
+
window.addEventListener("scroll", onScroll, { passive: true });
|
|
1075
|
+
setTimeout(checkThresholds, 0);
|
|
1076
|
+
return () => {
|
|
1077
|
+
if (rafId !== null) cancelAnimationFrame(rafId);
|
|
1078
|
+
history.pushState = originalPushState;
|
|
1079
|
+
history.replaceState = originalReplaceState;
|
|
1080
|
+
window.removeEventListener("popstate", resetIfPathChanged);
|
|
1081
|
+
window.removeEventListener("scroll", onScroll);
|
|
1082
|
+
};
|
|
1083
|
+
}
|
|
1084
|
+
|
|
1085
|
+
// ../tracking-core/src/triggers/multi-page-session.ts
|
|
1086
|
+
var STORAGE_KEY = "aranova_tracking_mps_paths";
|
|
1087
|
+
var SESSION_KEY = "aranova_tracking_mps_session";
|
|
1088
|
+
var FIRED_KEY = "aranova_tracking_mps_fired";
|
|
1089
|
+
function getSessionStorage() {
|
|
1090
|
+
try {
|
|
1091
|
+
return typeof window !== "undefined" ? window.sessionStorage : null;
|
|
1092
|
+
} catch {
|
|
1093
|
+
return null;
|
|
1094
|
+
}
|
|
1095
|
+
}
|
|
1096
|
+
function attachMultiPageSession(client, config) {
|
|
1097
|
+
if (typeof window === "undefined" || typeof history === "undefined") {
|
|
1098
|
+
return () => {
|
|
1099
|
+
};
|
|
1100
|
+
}
|
|
1101
|
+
const storage = getSessionStorage();
|
|
1102
|
+
if (!storage) return () => {
|
|
1103
|
+
};
|
|
1104
|
+
const { pageThreshold } = config;
|
|
1105
|
+
let lastCheckedPath = "";
|
|
1106
|
+
function getDistinctPaths() {
|
|
1107
|
+
try {
|
|
1108
|
+
const raw = storage.getItem(STORAGE_KEY);
|
|
1109
|
+
return raw ? new Set(JSON.parse(raw)) : /* @__PURE__ */ new Set();
|
|
1110
|
+
} catch {
|
|
1111
|
+
return /* @__PURE__ */ new Set();
|
|
1112
|
+
}
|
|
1113
|
+
}
|
|
1114
|
+
function saveDistinctPaths(paths) {
|
|
1115
|
+
try {
|
|
1116
|
+
storage.setItem(STORAGE_KEY, JSON.stringify([...paths]));
|
|
1117
|
+
} catch {
|
|
1118
|
+
}
|
|
1119
|
+
}
|
|
1120
|
+
function resetIfSessionChanged() {
|
|
1121
|
+
const currentSession = getOrRotateSessionId().id;
|
|
1122
|
+
const storedSession = storage.getItem(SESSION_KEY);
|
|
1123
|
+
if (storedSession !== currentSession) {
|
|
1124
|
+
storage.setItem(SESSION_KEY, currentSession);
|
|
1125
|
+
storage.removeItem(STORAGE_KEY);
|
|
1126
|
+
storage.removeItem(FIRED_KEY);
|
|
1127
|
+
}
|
|
1128
|
+
}
|
|
1129
|
+
function hasFired() {
|
|
1130
|
+
return storage.getItem(FIRED_KEY) === "1";
|
|
1131
|
+
}
|
|
1132
|
+
function check() {
|
|
1133
|
+
const currentPath = window.location.pathname;
|
|
1134
|
+
if (currentPath === lastCheckedPath) return;
|
|
1135
|
+
lastCheckedPath = currentPath;
|
|
1136
|
+
resetIfSessionChanged();
|
|
1137
|
+
if (hasFired()) return;
|
|
1138
|
+
const paths = getDistinctPaths();
|
|
1139
|
+
paths.add(currentPath);
|
|
1140
|
+
saveDistinctPaths(paths);
|
|
1141
|
+
if (paths.size >= pageThreshold) {
|
|
1142
|
+
storage.setItem(FIRED_KEY, "1");
|
|
1143
|
+
client.trackEvent({
|
|
1144
|
+
eventType: "multi_page_session",
|
|
1145
|
+
metadata: {
|
|
1146
|
+
page_count: paths.size,
|
|
1147
|
+
page: { path: window.location.pathname }
|
|
1148
|
+
},
|
|
1149
|
+
pageUrl: window.location.href,
|
|
1150
|
+
occurredAt: null
|
|
1151
|
+
});
|
|
1152
|
+
}
|
|
1153
|
+
}
|
|
805
1154
|
const originalPushState = history.pushState.bind(history);
|
|
806
1155
|
const originalReplaceState = history.replaceState.bind(history);
|
|
807
1156
|
function patchedPushState(...args) {
|
|
@@ -823,6 +1172,71 @@ function attachContactPageVisit(client, config) {
|
|
|
823
1172
|
};
|
|
824
1173
|
}
|
|
825
1174
|
|
|
1175
|
+
// ../tracking-core/src/triggers/form-start.ts
|
|
1176
|
+
function attachFormStart(client, config) {
|
|
1177
|
+
if (typeof window === "undefined" || typeof document === "undefined") {
|
|
1178
|
+
return () => {
|
|
1179
|
+
};
|
|
1180
|
+
}
|
|
1181
|
+
const selector = config.selector ?? "form";
|
|
1182
|
+
let firedForms = /* @__PURE__ */ new Set();
|
|
1183
|
+
let currentPath = window.location.pathname;
|
|
1184
|
+
function getFormKey(form) {
|
|
1185
|
+
if (form.id) return `id:${form.id}`;
|
|
1186
|
+
const explicitAction = form.getAttribute("action");
|
|
1187
|
+
if (explicitAction) return `action:${explicitAction}`;
|
|
1188
|
+
const forms = Array.from(document.querySelectorAll(selector));
|
|
1189
|
+
return `index:${forms.indexOf(form)}`;
|
|
1190
|
+
}
|
|
1191
|
+
function onFocusIn(event) {
|
|
1192
|
+
const target = event.target;
|
|
1193
|
+
if (!(target instanceof HTMLElement)) return;
|
|
1194
|
+
const form = target.closest(selector);
|
|
1195
|
+
if (!form || form.tagName !== "FORM") return;
|
|
1196
|
+
const key = getFormKey(form);
|
|
1197
|
+
if (firedForms.has(key)) return;
|
|
1198
|
+
firedForms.add(key);
|
|
1199
|
+
client.trackEvent({
|
|
1200
|
+
eventType: "form_start",
|
|
1201
|
+
metadata: {
|
|
1202
|
+
form: {
|
|
1203
|
+
id: form.id || "",
|
|
1204
|
+
action: form.getAttribute("action") ?? null
|
|
1205
|
+
},
|
|
1206
|
+
page: { path: window.location.pathname }
|
|
1207
|
+
},
|
|
1208
|
+
pageUrl: window.location.href,
|
|
1209
|
+
occurredAt: null
|
|
1210
|
+
});
|
|
1211
|
+
}
|
|
1212
|
+
function resetIfPathChanged() {
|
|
1213
|
+
const newPath = window.location.pathname;
|
|
1214
|
+
if (newPath === currentPath) return;
|
|
1215
|
+
currentPath = newPath;
|
|
1216
|
+
firedForms = /* @__PURE__ */ new Set();
|
|
1217
|
+
}
|
|
1218
|
+
const originalPushState = history.pushState.bind(history);
|
|
1219
|
+
const originalReplaceState = history.replaceState.bind(history);
|
|
1220
|
+
function patchedPushState(...args) {
|
|
1221
|
+
originalPushState(...args);
|
|
1222
|
+
setTimeout(resetIfPathChanged, 0);
|
|
1223
|
+
}
|
|
1224
|
+
function patchedReplaceState(...args) {
|
|
1225
|
+
originalReplaceState(...args);
|
|
1226
|
+
setTimeout(resetIfPathChanged, 0);
|
|
1227
|
+
}
|
|
1228
|
+
history.pushState = patchedPushState;
|
|
1229
|
+
history.replaceState = patchedReplaceState;
|
|
1230
|
+
window.addEventListener("popstate", resetIfPathChanged);
|
|
1231
|
+
document.addEventListener("focusin", onFocusIn);
|
|
1232
|
+
return () => {
|
|
1233
|
+
history.pushState = originalPushState;
|
|
1234
|
+
history.replaceState = originalReplaceState;
|
|
1235
|
+
window.removeEventListener("popstate", resetIfPathChanged);
|
|
1236
|
+
document.removeEventListener("focusin", onFocusIn);
|
|
1237
|
+
};
|
|
1238
|
+
}
|
|
1239
|
+
|
|
826
1240
|
// src/ConsentBanner.tsx
|
|
827
1241
|
var import_jsx_runtime = require("react/jsx-runtime");
|
|
828
1242
|
function ConsentBanner() {
|
|
@@ -912,7 +1326,7 @@ function useConsentState() {
|
|
|
912
1326
|
var import_react4 = require("react");
|
|
913
1327
|
|
|
914
1328
|
// package.json
|
|
915
|
-
var version = "0.
|
|
1329
|
+
var version = "0.5.1";
|
|
916
1330
|
|
|
917
1331
|
// src/factory.tsx
|
|
918
1332
|
var import_jsx_runtime2 = require("react/jsx-runtime");
|
|
@@ -948,6 +1362,7 @@ function createTracking(options) {
|
|
|
948
1362
|
surface: "react",
|
|
949
1363
|
packageName: "@aranova/tracking-react",
|
|
950
1364
|
sdkVersion: version,
|
|
1365
|
+
triggers,
|
|
951
1366
|
debug
|
|
952
1367
|
}),
|
|
953
1368
|
triggers,
|
|
@@ -966,6 +1381,7 @@ function createTracking(options) {
|
|
|
966
1381
|
endpoint,
|
|
967
1382
|
surface: "react",
|
|
968
1383
|
packageName: "@aranova/tracking-react",
|
|
1384
|
+
triggers,
|
|
969
1385
|
debug
|
|
970
1386
|
});
|
|
971
1387
|
detachers.push(attachAutoPageView(rawClient));
|
|
@@ -974,9 +1390,21 @@ function createTracking(options) {
|
|
|
974
1390
|
if (timeOnSite) {
|
|
975
1391
|
detachers.push(attachTimeOnSite(rawClient, timeOnSite));
|
|
976
1392
|
}
|
|
977
|
-
const
|
|
978
|
-
if (
|
|
979
|
-
detachers.push(
|
|
1393
|
+
const specificPageVisit = triggers.automatic.specific_page_visit;
|
|
1394
|
+
if (specificPageVisit) {
|
|
1395
|
+
detachers.push(attachSpecificPageVisit(rawClient, specificPageVisit));
|
|
1396
|
+
}
|
|
1397
|
+
const scrollDepth = triggers.automatic.scroll_depth;
|
|
1398
|
+
if (scrollDepth) {
|
|
1399
|
+
detachers.push(attachScrollDepth(rawClient, scrollDepth));
|
|
1400
|
+
}
|
|
1401
|
+
const multiPageSession = triggers.automatic.multi_page_session;
|
|
1402
|
+
if (multiPageSession) {
|
|
1403
|
+
detachers.push(attachMultiPageSession(rawClient, multiPageSession));
|
|
1404
|
+
}
|
|
1405
|
+
const formStart = triggers.automatic.form_start;
|
|
1406
|
+
if (formStart) {
|
|
1407
|
+
detachers.push(attachFormStart(rawClient, formStart));
|
|
980
1408
|
}
|
|
981
1409
|
return () => {
|
|
982
1410
|
for (let i = detachers.length - 1; i >= 0; i--) {
|