@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.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
- let sessionId = getOrRotateSessionId();
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
- sessionId = getOrRotateSessionId();
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/contact-page-visit.ts
683
+ // ../tracking-core/src/events/cta-click.ts
612
684
  var import_zod2 = require("zod");
613
- var contactPageVisitMetadataSchema = import_zod2.z.object({
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
- }).strict();
618
- var contactPageVisitConfigSchema = import_zod2.z.object({
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/form-submit.ts
695
+ // ../tracking-core/src/events/sdk-heartbeat.ts
629
696
  var import_zod3 = require("zod");
630
- var formSubmitMetadataSchema = import_zod3.z.object({
631
- form: import_zod3.z.object({
632
- id: import_zod3.z.string(),
633
- action: import_zod3.z.string().nullable()
634
- }),
635
- page: import_zod3.z.object({
636
- path: import_zod3.z.string()
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 formSubmitConfigSchema = import_zod3.z.object({}).strict();
708
+ var sdkHeartbeatConfigSchema = import_zod3.z.object({}).strict();
640
709
 
641
- // ../tracking-core/src/events/phone-click.ts
710
+ // ../tracking-core/src/events/form-start.ts
642
711
  var import_zod4 = require("zod");
643
- var phoneClickMetadataSchema = import_zod4.z.object({
644
- element: import_zod4.z.object({
645
- tag: import_zod4.z.string(),
646
- text: import_zod4.z.string().nullable(),
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 phoneClickConfigSchema = import_zod4.z.object({}).strict();
721
+ var formStartConfigSchema = import_zod4.z.object({
722
+ selector: import_zod4.z.string().optional()
723
+ }).strict();
654
724
 
655
- // ../tracking-core/src/events/time-on-site.ts
725
+ // ../tracking-core/src/events/form-submit.ts
656
726
  var import_zod5 = require("zod");
657
- var timeOnSiteMetadataSchema = import_zod5.z.object({
658
- duration_ms: import_zod5.z.number().int().nonnegative(),
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 timeOnSiteConfigSchema = import_zod5.z.object({
664
- thresholdSeconds: import_zod5.z.number().int().positive()
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
- contact_page_visit: {
836
+ specific_page_visit: {
837
+ kind: "automatic",
838
+ metadataSchema: specificPageVisitMetadataSchema,
839
+ configSchema: specificPageVisitConfigSchema
840
+ },
841
+ scroll_depth: {
681
842
  kind: "automatic",
682
- metadataSchema: contactPageVisitMetadataSchema,
683
- configSchema: contactPageVisitConfigSchema
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/contact-page-visit.ts
786
- function attachContactPageVisit(client, config) {
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 { pathPattern } = config;
792
- let lastFiredPath = null;
973
+ const { pages } = config;
974
+ const firedSet = /* @__PURE__ */ new Set();
793
975
  function check() {
794
976
  const path = window.location.pathname;
795
- if (!pathPattern.test(path)) return;
796
- if (lastFiredPath === path) return;
797
- lastFiredPath = path;
798
- client.trackEvent({
799
- eventType: "contact_page_visit",
800
- metadata: { page: { path } },
801
- pageUrl: window.location.href,
802
- occurredAt: null
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.4.2";
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 contactPageVisit = triggers.automatic.contact_page_visit;
978
- if (contactPageVisit) {
979
- detachers.push(attachContactPageVisit(rawClient, contactPageVisit));
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--) {